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

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值