我知道UI元素(视图层次结构)可能只能从UI线程中操作。对于后台操作,可以使用AsyncTask,它提供事件处理程序以访问UI线程。
简而言之,是否允许在非UI线程中实例化视图(绑定到getApplicationContext()
)?此自定义View后代 - 一旦实例化 - 将从 UI线程添加到视图层次结构中。所以只有构造函数调用是在Asynctask.doInBackground()
内完成的;它附加(addView(...)
)到Activity的根布局层次结构仍然在UI线程中完成。
详情:
public MyView extends View {
public MyView(Context context) {
...
}
...
}
我制作了自定义视图,覆盖了onDraw(...)
等。
当用户点击我的主Activity中的某个MenuItem时,会创建另一个Activity(MyOtherActivity)并显示哪个屏幕正好是MyView
由于MyOtherActivity的屏幕必须立即显示,我在AsyncTask中预先实例化MyView,而用户在主Activity中的其他位置(即他还没有点击那个MenuItem)。 MyView引用存储在静态数据成员中。
调用MyOtherActivity.onCreate()
时,其构造函数代码从静态获取MyView,并通过addView(...)
将其添加到其布局根层次结构中。
(我知道静态变量可能会引入内存泄漏,所以一旦不需要,我就将其设置为null
。)
MyView是否在其他线程中实例化(并在其构造函数中获取getApplicationContext()
的返回值)是不是问题(可能会引入意外问题)?
答案 0 :(得分:3)
明确的答案出现在View的文档中,标题为“事件处理和线程”:
注意:整个视图树是单线程的。在任何视图上调用任何方法时,您必须始终位于UI线程上。 如果您正在处理其他线程并希望从该线程更新视图的状态,则应使用Handler
所以这不仅仅是明显影响用户界面外观的因素,例如addView()
,而是“任何任何视图”
@CommonsWare链接到的discussion on android-developers有来自Android框架团队的多名高级工程师,确认要认真对待。
答案 1 :(得分:0)
这是一个示例,介绍如何使用AsyncTask
将视图添加到FrameLayoutpublic void addFLview(View view) {
MyAsyncTask as = new MyAsyncTask();
as.execute(view);
}
AsyncTask类
private class MyAsyncTask extends AsyncTask<View, Void, View> {
@Override
protected View doInBackground(View... params) {
return params[0];
}
@Override
protected void onPostExecute(View view) {
super.onPostExecute(view);
myFrameLayout.addView(view);
}
}