非UI线程可不可以更新UI
Posted coderzdz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非UI线程可不可以更新UI相关的知识,希望对你有一定的参考价值。
上篇文章提到因为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权限进行了限制,所以使用小米手机测试时,必须开启浮窗权限。
以上是关于非UI线程可不可以更新UI的主要内容,如果未能解决你的问题,请参考以下文章
Android Handler 机制:Hander 机制深入探究问题梳理