上篇文章提到因为ViewRootImpl会在线程更新UI时检查当前线程是不是创建它的线程,子线程可以在ViewRootImpl未创建的时候尽行更新UI。下面我们来看另外一种可以在子线程更新UI的办法。
既然ViewRootImpl的checkThread方法只会检查当前更新UI的线程是不是创建它的线程。那么可不可以在子线程中构建自己的ViewRootImpl,这样在子线程中更新UI就应该不会报下面的错误:
Only the original thread that created a view hierarchy can touch its views.
由于ViewRootImpl对象的创建在WindowManager调用addView方法时创建的。所以下面我们用windowManager在子线程中创建自己的视图。
UnUIThread.java
public class UnUIThread extends Thread {
private String TAG = "looper";
private Looper mLooper = null;
TextView tv_thread;//要添加的textView
WindowManager wManager;
private Context mContext;
private Handler threadHandler;
public UnUIThread(Context context){
mContext = context;
}
public void run() {
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
createUI();
if(threadHandler==null){
threadHandler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
tv_thread.setText(msg.obj.toString());
if(msg.arg1==2){
getmLooper().quit();
}
if(msg.arg1==3){
wManager.removeView(tv_thread);
}
}
};
}
Looper.loop();
}
public void createUI() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
tv_thread = new TextView(mContext);
tv_thread.setTextColor(0xFF000000);
tv_thread.setText("UNUIThread");
wManager = (WindowManager) mContext.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mParams.format = PixelFormat.TRANSLUCENT;
mParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mParams.width = 400;
mParams.height = 100;
mParams.alpha = 1.0f;
mParams.gravity=Gravity.BOTTOM;
wManager.addView(tv_thread, mParams);
}
public void updateUI(){
Message msg = new Message();
msg.arg1 =1;
msg.obj = String.valueOf(System.currentTimeMillis());
threadHandler.sendMessage(msg);
}
public void stopLoop(){
if(mLooper==null){
Toast.makeText(mContext, "mLooper", Toast.LENGTH_LONG).show();
}
Message msg = new Message();
msg.arg1 =2;
msg.obj = String.valueOf(System.currentTimeMillis());
threadHandler.sendMessage(msg);
}
public void removeUI(){
if(mLooper==null){
Toast.makeText(mContext, "mLooper", Toast.LENGTH_LONG).show();
}
Message msg = new Message();
msg.arg1 =3;
msg.obj = String.valueOf(System.currentTimeMillis());
threadHandler.sendMessage(msg);
}
public Looper getmLooper()
{
if(mLooper!=null){
return mLooper;
}else
{
synchronized (this){
try {
while (isAlive()&& mLooper==null){
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return mLooper;
}
}
}
Activity.java
public class SecondActivity extends ActionBarActivity {
private Button btn_create;//创建UI
private Button btn_change;//改变UI显示
private Button btn_remove;//移除UI
private Button btn_stop;//停止子线程消息循环
public void autoLoad_activity_second() {
btn_create = (Button) findViewById(R.id.btn_create);
btn_change = (Button) findViewById(R.id.btn_change);
btn_remove = (Button) findViewById(R.id.btn_remove);
btn_stop = (Button) findViewById(R.id.btn_stop);
}
private UnUIThread unUIThread = new UnUIThread(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
autoLoad_activity_second();
btn_create.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(unUIThread.getState()==Thread.State.NEW){
unUIThread.start();
}else{
unUIThread = new UnUIThread(SecondActivity.this);
unUIThread.start();
}
if(unUIThread!=null&&!unUIThread.isAlive()){
}
}
});
btn_remove.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(unUIThread==null){
return;
}
unUIThread.removeUI();
}
});
btn_stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(unUIThread==null){
return;
}
unUIThread.stopLoop();
}
});
btn_change.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(unUIThread==null){
return;
}
unUIThread.updateUI();
}
});
}
}
效果:
Android UI相关的操作不管是在主线程还是子线程都必须依赖Looper,Handler,Message。所以必须在子线程中构建自己的消息循环机制。通过Handler机制对UI进行更新。相关原理请看http://blog.csdn.net/innost/article/details/6055793
另外由于小米系列手机对Android权限进行了限制,所以使用小米手机测试时,必须开启浮窗权限。