42

我有一个非常简单的问题:

是否可以在后台线程中扩展视图(不将其添加到布局中)(例如:在doInBackgroundan 中AsyncTask)?

我知道这是可能的,因为我已经以这种方式在我的应用程序中实现了大多数活动并且从未遇到过问题,直到我在 Galaxy S 上遇到此问题: Android:android.view.InflateException:二进制 XML 文件第 13 行:错误SAMSUNG Galaxy S 中的充气类 <unknown>

有人告诉我,我不应该在后台线程中膨胀Views,但具体原因是什么?为什么我的方法在大多数设备中都有效,但在 Galaxy S 中无效?

4

3 回答 3

45

LayoutInflater不对它运行在哪个线程上做任何假设。在其文档中没有提到这一点。它的代码接缝也与线程无关。

另一方面,由 s 创建的视图可能会在其构造函数中LayoutInflater实例化s。Handler好吧,他们可能不应该那样做,但是没有要求他们不在Handler构造函数中创建/使用 s。

我的猜测是,三星 Galaxy S 对其进行了一些修改EditText,以某种方式触发了创建Handler(根据您的其他问题实例的崩溃日志,该实例GestureDetector被实例化,这反过来又创建了新的Handler)。虽然默认实现不这样做。


总的来说,我想说的是,因为没有明确要求s 在其构造函数View中不使用Handlers 和Loopers,所以你不能假设从非 UI 线程膨胀 View 是安全的。

您实际上可以在其中创建HandlerThread并尝试膨胀Views 。但我会说这是非常冒险的,因为在三星 Galaxy S 示例中,视图假定该线程在View生命周期内将处于活动状态,并将使用其处理所有消息Looper。这可能会导致以后崩溃。

于 2011-07-14T10:48:03.940 回答
17

使用最新的支持库,您可以使用android.support.v4.view.AsyncLayoutInflater异步扩展视图。请注意,如果不满足特定要求,它可能会退回到 UI 线程上的膨胀:

对于要异步膨胀的布局,它需要有一个其 generateLayoutParams(AttributeSet) 是线程安全的父级,并且作为膨胀的一部分构建的所有视图都不得创建任何处理程序或以其他方式调用 myLooper()。如果尝试膨胀的布局由于某种原因无法异步构造,AsyncLayoutInflater 将自动退回到 UI 线程上的膨胀。

于 2016-07-20T07:43:54.403 回答
5

是否可以在后台线程(例如:在 AsyncTask 的 doInBackground 中)扩展视图(不将其添加到布局中)?

可能,是的。受到推崇的?不。如文档中所述:

因此,Android 的单线程模型只有两条规则:

  1. 不要阻塞 UI 线程
  2. 不要从 UI 线程外部访问 Android UI 工具包

通过:进程和线程

更新 [02/06/19]:

显然,支持库有一个工具可以做到这一点: AsyncLayoutInflaterJetpack 版本)。它是在 2016 年左右的第 24 版中引入的(我回答后 2 年)

但是,正如其他答案所提到的,请小心使用此工具,因为它很容易适得其反。

于 2014-02-03T12:08:43.597 回答