1.不能在主线程以外操作UI,android中把耗时的操作都放到子线程里面,主线程又叫UI线程
注意:
不要阻塞主线程(UI线程)
不要从主线程以外的线程更新UI(UI线程)
我们看看这个代码
public class FourActivity extends Activity {
private Button btn;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
tv = (TextView) findViewById(R.id.tv_four);
btn = (Button) findViewById(R.id.btn_four);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Toast.makeText(getApplicationContext(), "click button", Toast.LENGTH_SHORT).show();
}
}).start();
}
});
}
}
运行结果是:点击按钮,五秒之后,程序会错误闪退,错误日志为:
05-17 17:41:52.200 28847-28890/com.example.admin.ztest E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: com.example.admin.ztest, PID: 28847
java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:397)
at android.widget.Toast.<init>(Toast.java:117)
at android.widget.Toast.makeText(Toast.java:280)
at android.widget.Toast.makeText(Toast.java:270)
at com.example.admin.ztest.run.FourActivity$1$1.run(FourActivity.java:37)
at java.lang.Thread.run(Thread.java:764)
2.使用runOnUiThread方法,我们修改一下程序:
package com.example.admin.ztest.run;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.admin.ztest.R;
public class FourActivity2 extends Activity {
private Button btn;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
tv = (TextView) findViewById(R.id.tv_four);
btn = (Button) findViewById(R.id.btn_four);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "FourActivity2 click button", Toast.LENGTH_SHORT).show();
}
});
}
}).start();
}
});
}
}
这次程序运行正常,点击按钮,五秒以后,正确提示我们的内容。
在这种情况下,可以使用Activity的runOnUiThread方法将toast的显示发布到主线程。 从主线程调用时,runOnUiThread方法立即执行传递的操作,但是当从主线程以外调用时,它会将传递的操作发布到主线程的事件队列。
3.此外,还可以使用控件.post的方式,把消息传递到主线程中
package com.example.admin.ztest.run;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.admin.ztest.R;
public class FourActivity3 extends Activity {
private Button btn;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
tv = (TextView) findViewById(R.id.tv_four);
btn = (Button) findViewById(R.id.btn_four);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tv.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "FourActivity3 click button", Toast.LENGTH_SHORT).show();
tv.setText("FourActivity3 click button");
}
});
}
}).start();
}
});
}
}
4.还有一种,最经典的方式,扩展性最好,使用最广泛的,就是Thread+Handler实现异步消息处理
package com.example.admin.ztest.run;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.example.admin.ztest.R;
public class FourActivity4 extends Activity {
private Button btn;
private TextView tv;
//这个地方的handler最好封装 防止内存泄漏
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 100) {
String res = (String) msg.obj;
tv.setText(res);
Toast.makeText(getApplicationContext(), res, Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_four);
tv = (TextView) findViewById(R.id.tv_four);
btn = (Button) findViewById(R.id.btn_four);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000); //模拟耗时操作,比如下载
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
msg.what = 100; //消息发送的标志
msg.obj = "FourActivity4 click button"; //消息发送的内容如: Object String 类 int
handler.sendMessage(msg);
}
}).start();
}
});
}
}