Android - код после лупера
У меня есть дочерний поток, выполняющий задачу бесконечно. Я хочу (1) постоянно отправлять данные обратно в поток пользовательского интерфейса и (2) иногда отправлять данные (соответствующие кнопкам) в дочерний поток, чтобы приостановить / продолжить выполнение бесконечной задачи. Моя проблема в том, что дочерний поток застревает в цикле, то есть задача не выполняется.
У меня такой вопрос: как заставить дочерний поток получать сообщения из потока пользовательского интерфейса, не блокируя бесконечную задачу?
Это то, что у меня есть: для задачи (1) у меня есть обработчик в потоке пользовательского интерфейса, который работает, и бесконечный цикл в дочернем потоке, который отправляет обратно сообщение, которое работает само по себе.
В пользовательском интерфейсе:
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
В дочернем потоке (в настоящее время использую фиктивную задачу, пока я не разрабатываю фреймворк):
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
}
Для задачи (2) у меня есть метод в потоке пользовательского интерфейса, соответствующий нажатию кнопки, который отправляет сообщение в дочерний поток, который работает, и обработчик в дочернем потоке, который работает сам по себе.
В пользовательском интерфейсе:
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
В дочерней ветке:
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Looper.loop();
Каждый из этих сценариев отлично работает в одиночку, но проблема в том, чтобы сделать оба одновременно. Если я ставлю бесконечное задание после Looper.loop(), оно никогда не будет достигнуто. Если я поставлю его перед Looper.prepare(), он запускается один раз. Если я положу это без петлителя, он все равно будет запущен только один раз.
Благодарим за любую идею:)
Вот мой полный код (без пакета / импорта) для справки:
public class MainActivity extends Activity {
Thread thread;
private Handler mMainHandler, mChildHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
thread = new ChildThread();
thread.start();
// Get a reference to the button
Button buttonStart = (Button)findViewById(R.id.btnStart);
Button buttonStop = (Button)findViewById(R.id.btnStop);
// Set the click listener to run my code
buttonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Starting...", Toast.LENGTH_SHORT).show();
sendRunning(true);
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Stopping...", Toast.LENGTH_SHORT).show();
sendRunning(false);
}
});
}
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
@Override
protected void onDestroy() {
Log.i("tag", "stop looping the child thread's message queue");
mChildHandler.getLooper().quit();
super.onDestroy();
}
class ChildThread extends Thread {
private static final String INNER_TAG = "ChildThread";
private boolean running = true;
final int maxCount = 10;
final int minCount = 0;
public int curCount = minCount;
private int up = 1;
public void run() {
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
this.setName("child");
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Log.i(INNER_TAG, "Child handler is bound to - " +
mChildHandler.getLooper().getThread().getName());
Looper.loop();
}
}
}
}
2 ответа
Просто используйте сервис Intent, а не этот поток, чтобы вы могли управлять всем пользовательским интерфейсом своего обновления и тем, что вы хотите сделать с пользовательским интерфейсом в сервисе намерений, который использует один широковещательный приемник, и его очень легко обрабатывать потоки и заражать ваш пользовательский интерфейс. блокировка во время выполнения фонового процесса.
Я просто использовал переменное время для потока, чтобы избежать ситуации. Спасибо за совет.