Обновление пользовательского интерфейса Android с использованием потоков

Я пишу приложение для Android чата. Я прослушиваю соединения, получаю данные и вижу их в Log.d, но всякий раз, когда я пытаюсь обновить свой интерфейс, приложение вылетает.

Фрагмент кода:

private class chatReceiver implements Runnable {
    @Override
    public void run() {
        try {
            skt = new DatagramSocket(Integer.parseInt(Main.prefs.getString("port_number", "5432")));
            DatagramPacket rcvPkt = new DatagramPacket(rcvBuf,rcvBuf.length);
            String ack = "Hello from our SimpleUDPServer";
            byte[] sndBuf = ack.getBytes();
            while (true) {
                Log.d("Server received: " ,"entered loop");
                skt.receive(rcvPkt);
                String rcvMsg = new String(rcvBuf, 0, rcvPkt.getLength(), "UTF-8");
                Log.d("Server received: " ,"receiving" + rcvMsg);
                if (rcvMsg != null) {
                    Log.d("Server received: " ,"not equal null");
                    // I want to update my UI here
                }
                DatagramPacket k = new DatagramPacket(sndBuf, sndBuf.length,
                        rcvPkt.getAddress(), rcvPkt.getPort());
                skt.send(k);
                Log.d("Server sent" ,ack);

            }
        } catch (IOException ex) {
            Log.d("ThreadStart", "Error Starting thread" + ex.getStackTrace());
        }

    }
} 

и чтобы обновить пользовательский интерфейс, который я использую:

public static void updateUI(Bubble b, View itemView) {

    TextView txt_display_name = (TextView) itemView
            .findViewById(R.id.display_name);
    txt_display_name.setText(b.getDisplay_name());
    TextView txt_chat_body = (TextView) itemView
            .findViewById(R.id.chat_body);
    txt_chat_body.setText(b.getChat_body());
    TextView txt_creation_date = (TextView) itemView
            .findViewById(R.id.creation_date);
    txt_creation_date.setText(b.getCreation_time());
}

Приложение продолжает падать.

5 ответов

Решение

Вы не можете ничего коснуться в потоке пользовательского интерфейса из фонового потока, чтобы сделать это использовать Handlers, инициализировать свой фон thread передавая это Handler объект. Когда данные поступают для использования handler отправить сообщение в интерфейс. В пользовательском интерфейсе, когда сообщение из фона thread приходит, просто обновите Views,

Пример кода:

в фоновом потоке:

if(dataArrives){
    Message msg = handler.obtainMessage();
    msg.what = UPDATE_IMAGE;
    msg.obj = bitmap;
    msg.arg1 = index;
    handler.sendMessage(msg);
}

в потоке пользовательского интерфейса:

final Handler handler = new Handler(){
  @Override
  public void handleMessage(Message msg) {
    if(msg.what==UPDATE_IMAGE){
      images.get(msg.arg1).setImageBitmap((Bitmap) msg.obj);
    }
    super.handleMessage(msg);
  }
};

и передать handler на задний план thread,

Вы не можете изменять элементы пользовательского интерфейса из не-пользовательского потока. Попробуйте использовать runOnUiThread.

runOnUiThread(new Runnable(){
    @Override
    public void run(){
        // change UI elements here
    }
});

Или просто используйте AsyncTask, это более полезно IMHO.

Используйте этот метод для обновления вашего пользовательского интерфейса из рабочего потока, здесь это хорошо объяснено.

Примечание: - Если вы используете progressbar.setProgress(progress) вы можете обновить прямо с рабочего thread поскольку ProgressBar внутренний звонок setProgress() метод с использованием Handler,

private void yourMethodName(){

new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                //do some heavy task here on main separate thread like: Saving files in directory, any server operation or any heavy task

                 ///Once this task done and if you want to update UI the you can update UI operation on runOnUiThread method like this:

                         homeActivity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                txtview.setText("some value");
                                edittext.setText("some new value");
                            }
                        });
                }
                catch (Exception e) {
                  //print the error here
                }
            }
        }).start();
}
Другие вопросы по тегам