在后台线程中膨胀视图
我有一个非常简单的问题:
是否可以在后台线程中膨胀视图(不将其添加到布局中)(例如:在AsyncTask
)?
我知道这是可能的,因为我已经以这种方式在应用程序中实现了大多数活动并且从未遇到过问题,直到我在 Galaxy S 上遇到此问题: Android: android.view.InflateException: 二进制 XML 文件行 #13: 错误膨胀类<未知>在 SAMSUNG Galaxy S 中,
我被告知我不应该在后台线程中膨胀视图
,但是具体原因是什么以及为什么我的方法在大多数设备,但 Galaxy S 中没有?
I have a very simple question:
Is or is it not possible to inflate a view (not add it to layout) in a background thread (ex: in the doInBackground
of an AsyncTask
)?
I know that it is possible, because I have implemented most Activities in my application this way and never had a problem, until I had this problem on a Galaxy S: Android: android.view.InflateException: Binary XML file line #13: Error inflating class <unknown> in SAMSUNG Galaxy S
I've been told that I should not inflate Views
in background threads, but what are the specific reasons and why does my aproach work in most devices but not in Galaxy S?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
LayoutInflater
不会对其运行的线程做出任何假设。它的文档中没有提到这一点。而且它的代码似乎与线程无关。另一方面,由 LayoutInflater 创建的视图可能会在其构造函数中实例化 Handler。好吧,他们可能不应该这样做,但是没有要求他们不在构造函数中创建/使用 Handler 。
我的猜测是,三星 Galaxy S 在其
EditText
中进行了一些修改,以某种方式触发了Handler
的创建(根据GestureDetector
的其他问题实例的崩溃日志) code> 被实例化,进而创建了新的Handler
)。虽然默认实现不会这样做。总的来说,我想说,因为没有明确要求
View
在其构造函数中不使用Handler
和Looper
,所以您可以不要假设从非 UI 线程膨胀视图是安全的。您实际上可以创建
HandlerThread
并尝试膨胀View
位于其中。但我想说这是非常危险的,因为在三星 Galaxy S 示例中,视图假设该线程在View
生命周期内处于活动状态,并将使用其Looper
处理所有消息。这可能会导致稍后崩溃。The
LayoutInflater
does not make any assumptions about what thread it runs on. And nothing is mentioned about this in its documentation. Also its code seams to be thread-agnostic.On the other hand, Views that are created by
LayoutInflater
might instantiateHandler
s in their constructors. Well, they probably shouldn't do that, but there is no requirement for them to not create/useHandler
s in their constructors.My guess is that Samsung Galaxy S had some modifications in its
EditText
that somehow triggers creation ofHandler
(according to crash log from your other question instance ofGestureDetector
was instantiated which in turn created newHandler
). While default implementation doesn't do this.Overall, I'd say that because there is no explicit requirement for
View
s to not useHandler
s andLooper
s in their constructors you can't assume inflating Views from non-UI thread is safe.You can actually create
HandlerThread
and try inflatingView
s inside it. But I'd say this is very risky, as in Samsung Galaxy S example the view assumes that this thread will be alive duringView
lifetime and will process all messages using itsLooper
. Which might result in crash later on.使用最新的支持库,您可以使用
android.support.v4 .view.AsyncLayoutInflater
异步膨胀视图。但请注意,如果不满足特定要求,它可能会回退到 UI 线程上进行膨胀:With latest support lib you can use
android.support.v4.view.AsyncLayoutInflater
to inflate views asynchronously. Be careful though that it can fallback to inflating on UI thread if specific requirements are not met:有可能,是的。受到推崇的?否。正如文档中所述:
通过以下方式从 UI 线程外部访问 Android UI 工具包: 进程和线程
更新 [02/06/19]:
显然,支持库有一个工具可以做到这一点:
AsyncLayoutInflater (Jetpack 版本)。它是在 2016 年左右的版本 24 中引入的(我的回答两年后)
但是,正如其他答案中提到的,要小心这个工具,因为它很容易适得其反。
Possible, yes. Recommended? No. As mentioned in the documentation:
via: Processes and Threads
Update [02/06/19]:
Apparently, the support library has a tool to do this:
AsyncLayoutInflater (Jetpack version). It was introduced in version 24, around 2016 (2 years after my answer)
But, as mentioned on other answers, be careful with this tool as it can very easily backfire.