web-dev-qa-db-fra.com

Mise à jour de l'interface utilisateur Android à l'aide de threads

J'écris une application de chat Android. J'écoute les connexions et je reçois des données que je peux voir dans le Log.d, mais chaque fois que je tente de mettre à jour mon interface utilisateur, l'application se bloque. 

Extrait de code:  

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());
        }

    }
} 

et pour mettre à jour l'interface utilisateur que j'utilise: 

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());
}

L'application continue à planter.

27
AhmadAssaf

Vous ne pouvez rien toucher dans le fil de l'interface utilisateur à partir d'un fil de fond , pour ce faire, utilisez Handlers, initialisez votre fond thread en lui passant un objet Handler. Lorsque les données arrivent, utilisez la variable handler pour envoyer un message à l'interface utilisateur. Dans l'interface utilisateur lorsque le message de la thread d'arrière-plan arrive, il suffit de mettre à jour la Views.

Exemple d'extrait de code:

dans le fil de fond: 

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

dans le fil de l'interface utilisateur:

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);
  }
};

et passez la handler à l'arrière-plan thread.

55
Franco

Vous ne pouvez pas modifier les éléments d'interface utilisateur à partir d'un thread non-UI. Essayez d’utiliser runOnUiThread .

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

Ou utilisez simplement AsyncTask , il est plus utile à mon humble avis.

8
Olsavage

Utilisez this pour mettre à jour votre interface utilisateur à partir du thread de travail, voici comment cela est expliqué. 

Remarque: - Si vous utilisez progressbar.setProgress(progress), vous pouvez effectuer une mise à jour directement à partir de l'agent thread car la méthode ProgressBar appelle en interne la méthode setProgress() à l'aide de Handler.

0
Bijay
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();
}
0