Ich schreibe eine Android Chat App. Ich höre auf Verbindungen und erhalte Daten und kann sie im Log.d
sehen. Wenn ich jedoch versuche, meine Benutzeroberfläche zu aktualisieren, stürzt die Anwendung ab.
Code-Auszug:
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());
}
}
}
und zum Aktualisieren der von mir verwendeten Benutzeroberfläche:
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());
}
Die Anwendung stürzt ständig ab.
Sie können nichts im UI-Thread von einem Hintergrundthread aus anfassen . Dazu verwenden Sie Handlers
. Initialisieren Sie Ihren Hintergrund thread
, indem Sie ein Handler
-Objekt übergeben. Wenn Daten eingehen, verwenden Sie handler
, um eine Nachricht an die Benutzeroberfläche zu senden. Wenn die Nachricht aus dem Hintergrund thread
kommt, aktualisieren Sie einfach die Views
in der Benutzeroberfläche.
Beispiel-Code-Snippet:
im Hintergrundthread:
if(dataArrives){
Message msg = handler.obtainMessage();
msg.what = UPDATE_IMAGE;
msg.obj = bitmap;
msg.arg1 = index;
handler.sendMessage(msg);
}
im UI-Thread:
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);
}
};
und übergeben Sie die handler
an den Hintergrund thread
.
Sie können keine Benutzeroberflächenelemente in einem Thread ohne Benutzeroberfläche ändern. Versuchen Sie es mit runOnUiThread .
runOnUiThread(new Runnable(){
@Override
public void run(){
// change UI elements here
}
});
Oder benutzen Sie einfach AsyncTask , es ist IMHO nützlicher.
Verwenden Sie die Methode " this ", um Ihre Benutzeroberfläche vom Worker-Thread zu aktualisieren. Hier wird es gut erklärt.
Hinweis: - Wenn Sie progressbar.setProgress(progress)
verwenden, können Sie direkt vom Worker thread
aus aktualisieren, da die ProgressBar
intern die setProgress()
-Methode mit Handler
aufruft.
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();
}