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

来源:互联网 发布:mac 查找java安装路径 编辑:程序博客网 时间:2024/04/30 17:31

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.");    }}  

ViewRootImple.setView() -> requestLayout() 中有调用checkThread()

那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

0 0
原创粉丝点击