#android #multithreading
#Android #многопоточность
Вопрос:
Я читал о потоках в своей книге по Java, и я хотел попробовать создавать обновления с помощью двух последовательных потоков одновременно.
Конечно, потоки не могут обновлять пользовательский интерфейс. Я немного использовал обработчики, но только путем передачи мессенджеров из одного класса в другой для отслеживания местоположения от службы к действию.
Но это должно быть проще, чем это.
Я предполагаю, что мне следует использовать AsyncTask, но я хочу считать 1-10 в каждом поле, и я не хочу постоянно входить в класс asynctask и выходить из него.
Любые указатели приветствуются
Стивен
Обновить
Итак, я еще немного поэкспериментировал. Я написал метод обработчика для обработки любых отправленных ему сообщений. Он проверяет, какое поле оно должно обновлять, а затем выполняет setText в указанном поле. Вот код
Handler myHandler = new Handler(){
public void handleMessage(Message msg){
msg = Message.obtain();
Bundle bundle = msg.getData();
String fieldName = bundle.getString("fieldName");
int count = bundle.getInt("count");
if(fieldName=="text1"){
text1.setText(count);
}else{
text2.setText(count);
}
}
};
Затем у меня есть некоторый код в onCreate моей активности, который запускает два потока, и каждый поток передает обработчику сообщения с моим количеством значений int. Он также передает имя TextView, поэтому мой обработчик знает, какой textview он должен обновлять. Вот код…
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
text1 = (TextView)findViewById(R.id.text1);
text2 = (TextView)findViewById(R.id.text2);
new Thread(){
public void run(){
for(int i=1;i<10;i ){
message = Message.obtain(myHandler);
Bundle bundle = new Bundle();
bundle.putCharSequence("fieldName", "text1");
message.setData(bundle);
myHandler.sendMessageDelayed(message, 1000);
}
}
}.start();
new Thread(){
public void run(){
for(int i=1;i<10;i ){
message = Message.obtain(myHandler);
Bundle bundle = new Bundle();
bundle.putCharSequence("fieldName", "text2");
message.setData(bundle);
myHandler.sendMessageDelayed(message, 1000);
}
}
}.start();
}
Но я получаю сообщение об ошибке в setText
05-17 17:13:00.013: ОШИБКА / AndroidRuntime(966): android.content.res.Resources$NotFoundException: идентификатор строкового ресурса #0x0
Есть идеи?
Комментарии:
1. «Я предполагаю, что мне следует использовать AsyncTask, но я хочу посчитать 1-10 в каждом поле, и я не хочу постоянно входить и выходить из класса asynctask». — что это значит?
Ответ №1:
Вот что вы можете сделать. Вы на правильном пути в использовании AsyncTask, поэтому расширьте класс и внесите свой подсчет в функцию обновления хода выполнения. У вас должно быть что-то вроде этого:
private class BackgroundTask extends AsyncTask<Void, Void, Void> {
int i;
protected void onPreExecute() {
i = 0;
}
@Override
protected Void doInBackground(Void... arg0) {
i ;
publishProgress(i);
}
protected void onProgressUpdate(Integer... progress) {
TextView tv1 = (TextView) Main.this.findViewById(R.id.textView1)
TextView tv2 = (TextView) Main.this.findViewById(R.id.textView2)
tv1.setText(i);
tv2.setText(i);
}
protected void onPostExecute(Void result) {
i = null;
}
}
где Main
ваша активность и textView1
и textView2
ваши текстовые представления, которые вы собираетесь обновить.
Комментарии:
1. Спасибо, ребята, я попробую оба этих метода и дам вам знать, как у меня получается
2. Я ответил на свой собственный вопрос случайно. Пожалуйста, ознакомьтесь с дополнительным ответом на этот пост.
Ответ №2:
Если вы действительно хотите запустить два дополнительных потока, это можно сделать с помощью обработчиков. Просто создайте ОДИН обработчик для своей активности и включите what. Затем запустите два потока и, когда каждый поток завершится, отправьте сообщение обработчику, используя соответствующее значение what. Затем обновите соответствующее текстовое представление в обработчике, когда вы вернетесь в поток пользовательского интерфейса в обработчике:
private Handler myHandler= new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case 0:
this.removeMessages(0);
Toast.makeText(Main.this,"Message0", Toast.LENGTH_SHORT).show();
break;
case 1:
this.removeMessages(1);
Toast.makeText(Main.this,"Message1", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
break;
}
}
};
Просто замените toast кодом обновления пользовательского интерфейса. Вы можете запустить поток, как в:
// DISPLAY ON CLICK HANDLER
threadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Thread thread= new Thread( new Runnable() {
public void run() {
try { // DO NOT TOUCH THE UI HERE
Thread.sleep(1000); // mimic time consuming task
}
catch(Exception e){
}
myHandler.sendEmptyMessage(0);
}
});
thread.setDaemon(true);
thread.start();
}
});
Если вы просто хотите отсчитывать от i = 1-10 секунд, вам даже не нужно использовать потоки, просто используйте postMessageDelayed путем зацикливания и вызова:
myHandler.sendEmptyMessageDelayed(0, 1000); // what 0, 1 second
Вы можете передавать (предпочтительно неизменяемые) данные в сообщениях, как в:
Message msg= Message.obtainMessage(0);
Bundle b= new Bundle();
b.putString("stringData",outString);
msg.setData(b);
handler.sendMessage(msg);
и извлеките его, как в:
Bundle b= msg.getData();
String data="";
if (b != null){
data= b.getString("stringData");
}
Если вам нужен только один дополнительный поток, я бы использовал AsyncTask.