#android #multithreading #while-loop
#Android #многопоточность #цикл while
Вопрос:
У меня очень простой пользовательский интерфейс, и мне нужно постоянно запускать процесс проверки, поэтому я пытаюсь использовать поток с циклом while. Когда я запускаю цикл только с помощью команды Thread.sleep(1000), он работает нормально, но как только я ввожу display.setText() , программа запускается на секунду в эмуляторе, а затем завершается. Я даже не вижу сообщения об ошибке, поскольку оно так быстро завершается.
Затем я взял команду display.setText() вне потока и просто поместил ее непосредственно в onCreate, и она работает нормально (так что с фактической командой проблем нет).
вот мой код, и я буду признателен за помощь. Спасибо!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
Комментарии:
1. код, относящийся к потоку, был бы полезен.
2. Добро пожаловать в stackoverflow! Если вы найдете ответ полезным, вы можете проголосовать за него! Если вы чувствуете, что кто-то адекватно ответил на ваш вопрос, установите флажок рядом с ответом, чтобы принять его.
3. @AlanMoore, код добавлен с оригинальным сообщением
Ответ №1:
Вы не можете обновить пользовательский интерфейс из потока, отличного от пользовательского интерфейса. Используйте обработчик. Что-то вроде этого может сработать:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
Вы также можете избежать обработчика для этого простого случая и просто использовать
while (boo) {
runOnUiThread(updater);
// ...
В качестве альтернативы вы можете использовать AsyncTask вместо своего собственного класса Thread и переопределить onProgressUpdate
метод.
Комментарии:
1. @user947659 Я добавил ссылку на документы обработчика, а также некоторые примеры кода.
2. Прежде чем я попробовал ваше решение, я установил команду display.setText внутри потока, как и в моем коде, но я просто удалил цикл while. Не могли бы вы сказать мне, почему это работает без цикла while? Он по-прежнему изменяет пользовательский интерфейс из потока, отличного от пользовательского интерфейса.
3. Вы не должны изменять пользовательский интерфейс из чего-либо, кроме потока пользовательского интерфейса; иногда это может сработать, но это зависит от удачи, и на него никогда не следует полагаться.
Ответ №2:
Не уверен на 100%, но я думаю, что это случай невозможности изменять элементы управления пользовательского интерфейса из потока, который их не создавал?
Ответ №3:
Когда вы не находитесь в своем потоке пользовательского интерфейса, вместо display3.setText("test")
использования:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
Комментарии:
1. Вам не нужно объявлять display3 как final, если это переменная экземпляра.
2. Но он объявил ‘display3’ в методе.
3. Он инициализировал его в методе. Я не вижу объявления
TextView display3
в его коде.
Ответ №4:
Вместо этого вы должны инкапсулировать этот код в AsyncTask. Вот так:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Затем просто запустите задачу из вашего метода onCreate.
Ответ №5:
В потоке, отличном от пользовательского интерфейса, вы не можете обновить пользовательский интерфейс.В новом потоке вы можете использовать некоторые методы для уведомления об обновлении пользовательского интерфейса.
- используйте обработчик
- используйте AsyncTask
- используйте LocalBroadcast
- если процесс является шаблоном наблюдателя, можно использовать RxJava