子线程为什么不能更新UI

安卓不允许子线程更新UI是因为UI访问是没有加锁的,多个线程访问UI不是线程安全的

 

检测机制:ViewRootImpl的checkThread()检测当前线程是否是UI线程,否则抛异常 

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

ViewRootImpl 在Activity的onResume()时的创建过程: 

源码中可以看到 

ActivityThread的handleResumeActivity 

final void handleResumeActivity(IBinder token,
		boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
	...
	if (r != null) {
		...
		// The window is now visible if it has been added, we are not
		// simply finishing, and we are not starting another activity.
		if (!r.activity.mFinished && willBeVisible
				&& r.activity.mDecor != null && !r.hideForNow) {
			...
			if (r.activity.mVisibleFromClient) {
				r.activity.makeVisible();
			}
		}
		...
	} else {
		...
	}
}

- > Activity的makeVisible 

void makeVisible() {
	if (!mWindowAdded) {
		ViewManager wm = getWindowManager();
		wm.addView(mDecor, getWindow().getAttributes());
		mWindowAdded = true;
	}
	mDecor.setVisibility(View.VISIBLE);
}


注释: 

WindowManager是外界访问窗口的入口;
WindowManager是一个接口,它的真正实现是WindowManagerImpl
WindowManagerImpl这种工作模式是典型的桥接模式,将所有的操作全部委托给WindowManagerGlobal来实现


- > WindowManagerGlobal的addView 

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

	ViewRootImpl root;
	View panelParentView = null;

	synchronized (mLock) {
		...

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

		view.setLayoutParams(wparams);

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

		...
	}
}

- > ViewRootImpl


由源码可知,检测UI更新是否在主线程的操作是在Activity的onResume()方法中执行的

如果在子线程立刻访问UI,此时还没走到的的的onResume()方法,系统则不会抛出异常


猜你喜欢

转载自blog.csdn.net/mr_freeler/article/details/51348678