在非UI线程上实例化视图

我知道UI元素(视图层次结构)可能只能从UI线程中操作。 对于后台操作,可以使用AsyncTask,它提供事件处理程序以访问UI线程。

简而言之,是否允许在非UI线程中实例化View(与getApplicationContext() )? 此自定义View后代 – 一旦实例化 – 将从UI线程添加到视图层次结构中。 所以只有构造函数调用是在Asynctask.doInBackground() ; 它附加( addView(...) )到Activity的根布局层次结构仍然在UI线程中完成。

详情如下:

 public MyView extends View { public MyView(Context context) { ... } ... } 
  1. 我制作了一个自定义视图,重写了onDraw(...)等。

  2. 当用户单击我的主Activity中的某个MenuItem时,会创建另一个Activity(MyOtherActivity)并显示哪个屏幕正好是MyView

  3. 由于MyOtherActivity的屏幕必须立即显示,我在AsyncTask中预先实例化MyView,而用户在主Activity中的其他位置(即他还没有点击那个MenuItem)。 MyView引用存储在静态数据成员中。

  4. 调用MyOtherActivity.onCreate() ,其构造函数代码从静态获取MyView,并通过addView(...)将其添加到其布局根层次结构中。

  5. (我知道静态变量可能会引入内存泄漏,所以一旦不需要,我就把它设置为null 。)

MyView是否在另一个线程中实例化(并在其构造函数中获取getApplicationContext()的返回值getApplicationContext()是不是问题(可能会引入意外问题)?

最终答案出现在View的文档中,标题为“事件处理和线程”:

注意:整个视图树是单线程的。 在任何视图上调用任何方法时,您必须始终位于UI线程上。 如果您正在处理其他线程并希望从该线程更新视图的状态,则应使用Handler。

所以它不仅仅是明显影响UI外观的东西,比如addView() ,而是“ 任何 View上的任何方法”。

关于 @CommonsWare链接到的Android开发人员的讨论 ,有来自Android框架团队的不止一位高级工程师确认这一点值得认真对待。

这是一个示例,介绍如何使用AsyncTask将视图添加到FrameLayout

 public void addFLview(View view) { MyAsyncTask as = new MyAsyncTask(); as.execute(view); } 

AsyncTask类

 private class MyAsyncTask extends AsyncTask { @Override protected View doInBackground(View... params) { return params[0]; } @Override protected void onPostExecute(View view) { super.onPostExecute(view); myFrameLayout.addView(view); } }