中国移动补卡系统坏了 什么时候可以好

为什么不能再子线程修改UI? - 简书
为什么不能再子线程修改UI?
如果在子线程中修改UI报错如下:
如果问题搞清楚了这三大原则基本上就ok了;
为什么会报错,报错的方法是checkThread,requestLayout 方法都在ViewRootimpl 类里面,
也就是说一旦ViewRootImpl 这个类被实例化,则就会调用requestLaoyout 方法来检查,requestLayout
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested =
scheduleTraversals();
void checkThread() {
//报错如下
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
报错的原因是因为咱们没有在主线程里面去修改UI,chechThread 方法会检查当前线程是不是主线程
正确修改方法如下:
Handler handler = new Handler(){
public void handleMessage(Message msg) {
super.handleMessage(msg);
//当子线程获取到数据之后使用Handler 来修改UI
// 当然如果这样写会存在内存泄露
这里不做讨论
if(msg.waht == 0x123){
textView.setText("主线程修改UI");
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.supportRequestWindowFeature(Window.FEATURE_ACTION_BAR);
setContentView(R.layout.aty_xxx);
new Thread(new Runnable() {
public void run() {
//获取数据
//成功之后使用handler 发送what
Message msg = Message.obtain();
msg.what = 0x123;
hanlder.sendMessage(msg)
}).start();
以上就是在主线程修改UI的标准写法。
请观察以下代码
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.supportRequestWindowFeature(Window.FEATURE_ACTION_BAR);
setContentView(R.layout.aty_xxx);
new Thread(new Runnable() {
public void run() {
textView.setText("我在onCreate方法 一开始的时候就修改UI你拿我怎的?");
}).start();
以上代码会不会执行成功呢?如果你是从文章的开始看到这里来的话也许您会说肯定不能运行啊,不能再子线程里面修改UI啊;很遗憾,程序会正常运行,(截图我就不上了,有兴趣探究的同学可以试试)而模拟器上也会显示textView 几个大字;那到底这是为什么呢?
这里我们回到之前的为什么会报错,咱们进入源码看一看:、
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested =
scheduleTraversals();
void checkThread() {
//报错如下
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
前面说到了如果实例化了ViewRootImpl 这个类则会检查当前线程是不是主线程,那么直接杀到在哪里实例化ViewRootImpl 这个类的地方不就水落石出了嘛,别急,咱们一步一步来:可以看到requestLayout 调用了checkThread ,和scheduleTraversals() 方法,前者呢 是抛出错误的地方那后者呢?
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled =
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
这里postCallback 方法 第一个为一个常数,第三个是null,第二个则是一跟线程,代码如下;
final class TraversalRunnable implements Runnable {
public void run() {
doTraversal();
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled =
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
mProfile =
performTraversals() 这个方法则是View进行绘制的开始; 每一次访问UI,即UI则会重绘;
回过头来我们再来找找在哪里进行实例化 ViewRootimpl
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged =
// TODO Push resumeArgs into the activity for consideration
// 执行resume activity
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.
if (localLOGV) Slog.v(
TAG, "Resume " + r + " started activity: " +
a.mStartedActivity + ", hideForNow: " + r.hideForNow
+ ", finished: " + a.mFinished);
可以看到上面执行了resumeActivity 方法 ; 方法如下:
public final ActivityClientRecord performResumeActivity(IBinder token,
boolean clearHide) {
ActivityClientRecord r = mActivities.get(token);
if (localLOGV) Slog.v(TAG, "Performing resume of " + r
+ " finished=" + r.activity.mFinished);
if (r != null && !r.activity.mFinished) {
if (clearHide) {
r.hideForNow =
r.activity.mStartedActivity =
r.activity.performResume();
这里可以看到回调了activity.performResume() 方法 方法如下:
Activity ===&performResume()
final void performResume() {
performRestart();
mFragments.execPendingActions();
mLastNonConfigurationInstances =
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
" did not call through to super.onResume()");
mInstrumentation 是用来辅助Activity完成启动Activity的过程
Instrumentation===&callActivityOnResume()
public void callActivityOnResume(Activity activity) {
activity.mResumed =
activity.onResume();
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i&N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
am.match(activity, activity, activity.getIntent());
可是看到真正执行onResume在这里 也就是说执行到这里 activity 的生命周期经历如下onCreate
----- onStart
而performResumeActivity 里面执行完回调activity.onResume() 方法 有如下代码:
r.activity.mVisibleFromServer =
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
进入makeVisible 如下:
Activity===&callActivityOnResume()
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded =
mDecor.setVisibility(View.VISIBLE);
ViewManager 是一个抽象类,而mDecor 是一个View ,我们找到ViewManager 实现类如下:
WindowManagerGlobal===&addView()
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
if (display == null) {
throw new IllegalArgumentException("display must not be null");
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
View panelParentView =
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
进入到addView 方法内部终于找到了实例化ViewRootImpl 的地方;
这也就是解释了为什么在oncreate 生命周期刚开始的时候在子线程修改UI会报错呢,因此此时的ViewRootImpl 还没有被实例化;
ActivityClientRecord r = performResumeActivity(token, clearHide);
要知道ViewRootImpl 实例化是在执行完handleResumeActivity 方法里面以上代码之后哦,而performResumeActivity 是回调activity.onResume的,他们的流程是这样的
QQ图片41.png
可是ViewRootImpl 实例化最后的过程是在activity -& makeVisible 方法里面在里面调用了在WindowManagerGlobal (ViewManager 的实现类)---&addView 真正实行了ViewRootImpl 的实例化
有时候看源码真的很枯燥,但是某一个把自己看过的源码给串起来的感觉真的特别好(比如笔者之后有了解了activity的启动过程);
Contact Me:
Github:/LikeQuite
学习烹饪的快活~他用整个青春岁月换来了我们的成长-UI设计lol界面ui一键美化软件|LOL一键替换UI工具1.0 免费版-东坡下载
东坡下载:内容最丰富最安全的下载站!
→ LOL一键替换UI工具 1.0 免费版
LOL一键替换UI工具是一款可以一件更换lol的ui界面的工具,喜欢玩lol的玩家肯定都想自己的游戏界面变的美美哒,喜欢什么界面就一件更换吧,赶紧来试试。LOLUI界面功能介绍:蓝色科技风冰雪世界海盗界面黑色透明使用方法打开后运行即可。
安卓官方手机版
IOS官方手机版
LOL一键替换UI工具截图
LOL一键替换UI工具 1.0 免费版
本类最新软件
本类软件推荐
13.8M / 05-20 / 2.0. 最新免费版
10.0M / 03-17 / 4.7.4.0官方防封防警告版
2.8M / 03-07 / 3.75免费破解版 【专用版】
22.1M / 02-17 / 1.2.2绿色免费版
907KB / 02-10 / 9.4最新破解版 【2017变态攻击】
本类软件排行
本类软件必备
刷枪透视盒子全图
请简要描述您遇到的错误,我们将尽快予以修正。
轮坛转帖HTML方式
轮坛转帖UBB方式}

我要回帖

更多关于 小坏卡盟 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信