您的位置:首页 > 产品设计 > UI/UE

Android 里子线程真的不能刷新UI吗?

2016-04-16 14:54 483 查看

Android 里子线程真的不能刷新UI吗?

在开发应用中,如果子线程中更新UI会抛出异常,但并不是因为只有UI线程才能更新UI,

而是因为ViewRootImpl会进行检查,如果 mThread!=当前线程 时会抛出异常CalledFromWrongThreadException异常

ViewRootImple.java

void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}


那mThread是什么呢?

通过ViewRootImpl的构造函数我们可以发现mThread会被赋值为创建ViewRootImp的那个线程

public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();

//此处进行mThread的赋值
mThread = Thread.currentThread();
//代码省略...
}


而ViewRootImpl是在主线程中创建的,所以,才需要在主线程中更新UI

不过,设定为在主线程更新UI也是为了安全和简化起见吧

那么,能否在子线程中更新UI呢

如果ViewRootImpl是由子线程创造的,那么自然可以在该子线程中更新UI

但是如果我们直接创建ViewRootImpl实例的话,会发现找不到该类。

可以通过WindowManager.addView来间接创建一个ViewRootImpl

比如

class TestThread1 extends Thread{
@Override
public void run() {
Looper.prepare();

TextView tx = new TextView(MainActivity.this);
tx.setText("test11111111111111111");

WindowManager wm = MainActivity.this.getWindowManager();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
250, 250, 200, 200, WindowManager.LayoutParams.FIRST_SUB_WINDOW,
WindowManager.LayoutParams.TYPE_TOAST,PixelFormat.OPAQUE);
wm.addView(tx, params);

Looper.loop();
}
}


MainActivity是建立android工程时生成的入口类,TestThread1是MainActivity的内部类。感兴趣的话,试试吧!看看是不是在屏幕上看到了”test11111111111111111”?

具体创建ViewRoot的地方在wm.addView(tx, params)

具体流程:

WindowManagerImpl.addView(View view, ViewGroup.LayoutParams params)

->

WindowManagerImpl.addView(View view, ViewGroup.LayoutParams params, boolean nest)

代码(精简):

public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

ViewRootImpl root;
View panelParentView = null;

synchronized (mLock) {

//新建ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}

root.setView(view, wparams, panelParentView);
}


其他

参考

http://www.oschina.net/question/54100_29585
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: