在工作线程中创build视图

我有一个需要从EditText生成一个位图,然后对其执行一些操作。 我主要关心的不是在UI线程上调用View.buildDrawingCache()方法,可能会阻止它,特别是在谈论大屏幕(如Nexus 10)时,因为EditText将占用大约80%的可用屏幕尺寸。

我在ThreadPoolExecutor执行Runnable ,这些将在工作线程上虚拟视图,并为它们设置所有必需的属性,然后调用buildDrawingCache()getDrawingCache()来生成一个位图。

这在一些设备上工作完美,但最近我遇到了一些设备,崩溃与以下消息:

 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 

我明白为什么会发生这种情况,因为有些电话必须修改EditText实现来创buildHandler ,因此需要Looper.prepare()调用Looper.prepare()

从我在线阅读的内容来看,在工作线程中调用Looper.prepare()是没有问题的,尽pipe有些人说这是非常不值得推荐的,但我找不到原因。

除此之外,与这个问题有关的大多数post都说你不应该在后台线程中夸大视图,可能是由于Android官方文档(进程和线程)的以下内容 :

 "Do not access the Android UI toolkit from outside the UI thread" 
  • 处理这个问题的build议方法是什么?

  • 从主线程调用build / get drawingcache是​​否有任何伤害? (性能明智)

  • 在我的工作线程中调用Looper.prepare()会解决这个问题吗?

编辑

为了详细说明我的具体要求,我有一个用户界面,包括一个ImageView和一个自定义的EditText,EditText可以根据用户的select改变它的字体和颜色,可以使用“捏放大“的手势,也可以拖动,让用户重新放置在图像的顶部。

最后我做的是在我的工作线程中使用当前在UI上的完全相同的值(宽度,高度,位置)创build一个虚拟视图,然后生成它的drawingcache,原始图像的位图再次从本地文件解码。

一旦这两个位图准备就绪,我将它们合并到一个位图中以供将来使用。

所以简单来说,执行下面的代码(从后台线程中 )有什么问题:

调用Looper.prepare()使用应用程序上下文创build一个新视图,手动调用measure()layout() ,然后构build+从中获取drawingcache,即:

 Looper.prepare(); EditText view = new EditText(appContext); view.setText("some text"); view.setLayoutParams(layoutParams); view.measure( View.MeasureSpec.makeMeasureSpec(targetWidth, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(targetHeight, View.MeasureSpec.EXACTLY)); view.layout(0, 0, targetWidth, targetHeight); view.buildDrawingCache(); Bitmap bitmap = view.getDrawingCache(); 

这是如何适用于不从UI线程外部访问Android UI工具包的限制,可能会出现什么问题?

Solutions Collecting From Web of "在工作线程中创build视图"

在你的情况下,你当然可以做,但只要从UI数据读取值,以避免同步错误。

你也不应该从后台线程重新创buildEditText,直接访问已经存在的EditText会更有效率:

 Looper.prepare(); myEditText.setDrawingCacheEnabled(true); Bitmap bitmap = myEditText.getDrawingCache(); 

如果你的问题是:为什么不是由android的指导方针, 这是一个很好的回答你的问题。

调用View.buildDrawingCache()调用Bitmap.nativeCreate可以是一个大的分配,所以是的,这可能会对主线程运行有潜在的危害。 我没有看到在后台线程中调用Looper.prepare()的问题。 但是,目前还不清楚你正在努力达到什么目标,可能会有更好的解决scheme来解决你的问题。

你不应该从其他线程的UI工具包的原因是,它不被写为线程安全的,它是在只有一个线程运行它的假设下编写的。 这意味着真的很难说出什么地方会出错,如果有什么坏的影响,主要是由于线程的具体时间而发生不可重复的。 你对你所做的描述不太清楚。 在你的情况下,我只是分配一个大的位图,并绘制文本。 为什么你首先使用EditText? 这似乎是一种黑客,黑客往往最终打破。

为什么View.buildDrawingCache() ? 如何使用View.draw(Canvascanvas)手动渲染到由Bitmap支持的Canvas ? 方法似乎很简单,不会导致后台线程的问题。

 EditText edit = (EditText)findViewById(R.id.edit); edit.buildDrawingCache(); ImageView img = (ImageView)findViewById(R.id.test); img.setImageBitmap(edit.getDrawingCache()); 

当您尝试在onCreate方法中构buildcaching时,Lalit绘图尚未发生,因此drawingCache应该没有任何内容。 将onDrawingChache方法放在onClick方法中。 或者在onCreate中使用下面的代码。

 ViewTreeObserver vto = editText.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { editText.buildDrawingCache(); } }); 

我也遇到了几次这个错误:

 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 

我的解决scheme

 new Thread(new Runnable(){ @Override public void run(){ //add implementations that DOES NOT AFFECT the UI here new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run(){ //manage your edittext and Other UIs here } }); } }).start(); 

只需在您的工作线程中创build一个处理程序,将数据更改应用于您的用户界