Android子线程其实也可以刷新UI。。。。
来源:互联网 发布:win7下怎么安装ubuntu 编辑:程序博客网 时间:2024/04/29 11:32
如果你在网上搜索CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views. 那么你肯定能看到很多文章说android里子线程不能刷新UI。这句话不能说错,只是有些不太严谨。其实线程能否刷新UI的关键在于ViewRoot是否属于该线程。
首先,CalledFromWrongThreadException这个异常是有下面的代码抛出的:
void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } }
该段代码出自 framework/base/core/java/android/view/ViewRoot.java
其次,看看RootView的构造函数:
public ViewRoot(Context context) { super(); if (MEASURE_LATENCY && lt == null) { lt = new LatencyTimer(100, 1000); } // For debug only //++sInstanceCount; // Initialize the statics when this class is first instantiated. This is // done here instead of in the static block because Zygote does not // allow the spawning of threads. getWindowSession(context.getMainLooper()); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); mLocation.fillInStackTrace(); mWidth = -1; mHeight = -1; mDirty = new Rect(); mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); mWindow = new W(this, context); mInputMethodCallback = new InputMethodCallback(this); mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; // true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; }
最后,我们看看ViewRoot.checkThread的调用顺序:
com.david.test.helloworld.MainActivity$TestThread2.run
-> android.widget.TextView.setText
-> android.widget.TextView.checkForRelayout
-> android.view.View.invalidate
-> android.view.ViewGroup.invalidateChild
-> android.view.ViewRoot.invalidateChildInParent
-> android.view.ViewRoot.invalidateChild
-> android.view.ViewRoot.checkThread
到这里相信网友已经明白CalledFromWrongThreadException为什么出现了。那到底非主线程以外的线程能否刷新UI呢?呵呵,答案当然是能,前提条件是它要拥有自己的ViewRoot。如果你要直接创建ViewRoot的实例的话,你会失望的发现不能找到这个类。那么我们要如何做呢?让我们用实例来说说吧,代码如下:
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),奥妙就在这里,具体看看代码吧!
private void addView(View view, ViewGroup.LayoutParams params, boolean nest) { if (Config.LOGV) Log.v("WindowManager", "addView view=" + view); if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException( "Params must be WindowManager.LayoutParams"); } final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params; ViewRoot root; View panelParentView = null; synchronized (this) { // Here's an odd/questionable case: if someone tries to add a // view multiple times, then we simply bump up a nesting count // and they need to remove the view the corresponding number of // times to have it actually removed from the window manager. // This is useful specifically for the notification manager, // which can continually add/remove the same view as a // notification gets updated. int index = findViewLocked(view, false); if (index >= 0) { if (!nest) { throw new IllegalStateException("View " + view + " has already been added to the window manager."); } root = mRoots[index]; root.mAddNesting++; // Update layout parameters. view.setLayoutParams(wparams); root.setLayoutParams(wparams, true); return; } // If this is a panel window, then find the window it is being // attached to for future reference. if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews != null ? mViews.length : 0; for (int i=0; i<count; i++) { if (mRoots[i].mWindow.asBinder() == wparams.token) { panelParentView = mViews[i]; } } } root = new ViewRoot(view.getContext()); root.mAddNesting = 1; view.setLayoutParams(wparams); if (mViews == null) { index = 1; mViews = new View[1]; mRoots = new ViewRoot[1]; mParams = new WindowManager.LayoutParams[1]; } else { index = mViews.length + 1; Object[] old = mViews; mViews = new View[index]; System.arraycopy(old, 0, mViews, 0, index-1); old = mRoots; mRoots = new ViewRoot[index]; System.arraycopy(old, 0, mRoots, 0, index-1); old = mParams; mParams = new WindowManager.LayoutParams[index]; System.arraycopy(old, 0, mParams, 0, index-1); } index--; mViews[index] = view; mRoots[index] = root; mParams[index] = wparams; } // do this last because it fires off messages to start doing things root.setView(view, wparams, panelParentView); }
出自:frameworks/base/core/java/android/view/WindowManagerImpl.java
Ok,相信到了这里,大家都已经明白了:子线程是能够刷新UI的!!!
原文出处:http://blog.csdn.net/imyfriend/article/details/6877959
- Android子线程其实也可以刷新UI。。。。
- 子线程是否可以刷新UI视图?
- android之在子线程刷新UI
- 子线程 刷新UI
- Android子线程居然可以更新UI?
- 关于子线程刷新ui
- Android进阶-子线程中刷新UI的讨论
- android 为什么可以在子线程更新UI
- Android系统上可以在子线程修改UI吗
- 在Android子线程中初始化handler后,为什么该子线程也能更新UI?
- 子线程中无法刷新更新 UI
- 19 子线程刷新UI runOnUiThread
- ProgressBar可以在子线程更新UI
- 子线程oncreate可以修改UI
- Android常用的3种定时刷新UI的方法和子线程能否刷新UI那些事
- Android常用的3种定时刷新UI的方法和子线程能否刷新UI那些事
- android 子线程刷新view
- Android 子线程更新UI
- NSObject +load and +initialize
- java 事务
- [LeetCode]Partition List
- Mac 源码安装 mongo-php-driver
- LeetCode OJ Construct Binary Tree from Preorder and Inorder Traversal
- Android子线程其实也可以刷新UI。。。。
- 【环境配置】配置AndroidStudio
- LeetCode OJ Symmetric Tree
- 相机标定
- 尝试使用绕线法制作数字电路
- 第一周项目2长方柱类
- search 页面
- printf中%p的输出应用
- LeetCode OJ Maximal Rectangle