Обновление двух последовательных текстовых представлений с использованием потоков

#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.