android 子线程真的不能操作ui么

 我来答
greystar_cn
2016-11-24 · 知道合伙人软件行家
greystar_cn
知道合伙人软件行家
采纳数:16407 获赞数:17260
本人主要从事.NET C#方向的技术开发工作,具有10多年的各类架构开发工作经验。

向TA提问 私信TA
展开全部
在开发应用中,如果子线程中更新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);
}
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
安徽电信网上营业厅
2016-11-24 · 查话费、办靓号、装宽带,尽在中国电信!
安徽电信网上营业厅
中国电信网上营业厅一直坚持以满足客户需求和全方位提升客户服务为根本,不断追求产品的完善与创新,向您提供费用查询、充值交费、买手机、办靓号、装宽带、积分兑换等差异化服务。
向TA提问
展开全部
当一个程序第一次启动的时候,Android会同时启动一个对应的主线程,这个主线程就是UI线程,也就是ActivityThread。UI线程主要负责处理与UI相关的事件,如用户的按键点击、用户触摸屏幕以及屏幕绘图等。系统不会为每个组件单独创建一个线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都从UI线程分发出去。所以,响应系统回调的方法永远都是在UI线程里运行,如响应用户动作的onKeyDown()的回调。
详情
  • 在线客服
  • 官方服务
    • 官方网站
    • 费用查询
    • 充值交费
    • 业务办理
    • 宽带提速
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式