gpt4 book ai didi

android - AsyncLayoutInflator 陷阱

转载 作者:行者123 更新时间:2023-12-04 14:09:10 37 4
gpt4 key购买 nike

Android 新增了 AsyncLayoutInflater类到他们的支持库版本 24.0 和更高版本,并且可以在 Android SDK 4.0 或更高版本(几乎所有可用的设备)中使用。
根据 Android 的文档;

Helper class for inflating layouts asynchronously. To use, constructan instance of AsyncLayoutInflater on the UI thread and callinflate(int, ViewGroup, OnInflateFinishedListener). TheAsyncLayoutInflater.OnInflateFinishedListener will be invoked on theUI thread when the inflate request has been completed.

This is intended forparts of the UI that are created lazily or in response to userinteractions. This allows the UI thread to continue to be responsive &animate while the relatively heavy inflate is being performed.


实际上,我发现这很有用,正如您可能意识到或可能没有意识到的那样,膨胀复杂的 View 在时间上是一项昂贵的操作,有时需要 100 毫秒。因此,当它在主线程上膨胀时,UI 可能会变得迟缓。
我发现的另一个好处是 Activity 的加载时间更快,因为 UI 线程可以继续加载的下一步,而 View 正在单独膨胀。我有时能够使用这种方法显着加快应用程序的启动时间。
话虽如此,当使用单独的线程来膨胀 View 时可能会发生陷阱。我们将在答案中解释它们。

最佳答案

根据 Android 文档;

For a layout to be inflated asynchronously it needs to have a parent whose generateLayoutParams(AttributeSet) is thread-safe and all the Views being constructed as part of inflation must not create any Handlers or otherwise call myLooper(). If the layout that is trying to be inflated cannot be constructed asynchronously for whatever reason, AsyncLayoutInflater will automatically fall back to inflating on the UI thread.



这是你必须注意的事情。尽管您的应用程序不会崩溃,因为 AsyncLayoutInflater 会自动退回到 UI 线程上的充气,但现在充气需要双倍的时间,首先是在单独的线程上,然后是在 UI 线程上。所以仔细观察 LogCat,看看 AsyncLayoutInflater 是否提示它在 UI 线程上膨胀,并处理它。您可能需要在多个设备和操作系统版本上进行测试,因为可能(未确认)同一个 View 在某些设备中创建处理程序,而在其他设备中没有。好消息是您不必完美无缺,因为在最坏的情况下,它仍然不会崩溃,因为 AsyncLayoutInflater 会处理它。
很多时候,问题是创建处理程序的单个自定义 View 。一个非常简单的解决方法是用 ViewStub 替换该 View 。 ,然后在 OnInflateFinishedListener回调被调用。
例如:
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />

然后在回调中
 ViewStub stub = findViewById(R.id.stub);
View inflated = stub.inflate();

还有一个危险的可怜,花费了我好几个小时的调试时间。它与 Android Activity 和 Fragment 生命周期有关。众所周知,Android 可以随时杀死不在前台的 Activity。发生这种情况时,Android 将在需要显示时重新创建 Activity。它使用 savedInstance bundle 将 Activity 和 Fragments 恢复到之前的状态。
但是Activities和Fragments之间有很大的区别。对于 Activity ,操作系统不会重新创建 View ,应用程序必须重新创建它们。一旦重新创建它们,操作系统就会通过调用 onRestoreState 来恢复每个 View 的状态。 .
但是通过 Fragments,操作系统实际上重新创建了整个 Fragment View,而应用程序只需要初始化类成员。

这在使用 AsyncLayoutInflater 时会导致一个严重的问题,因为当第一次创建 Activity 时,尽管 onCreate函数在 View 膨胀之前完成(因为它在单独的线程上膨胀),我们仍然不创建和附加任何 fragment ,直到 OnInflateFinishedListener回调被调用。因此,当创建 Fragment 时,我们已经有了一个完整的工作 Activity 和一个工作 View 。
但是当操作系统重新创建 Activity 时,只要 Activity onCreate函数完成,这是在 View 膨胀之前(因为它在单独的线程中膨胀),操作系统认为是时候重新创建 fragment 了。然后它将调用 onCreateView甚至 onActivityCreated ,即使 Activity 尚未对其 View 进行膨胀和设置。这将导致许多崩溃和不可见的 fragment !
解决方案是检查 onCreate Activity 的功能,如果它正在被重新创建,通过检查 savedBundle通过不是 null ,并且在这种情况下不使用 AsyncLayoutInflater。为此,您将分配 AsyncLayoutInflater.OnInflateFinishedListener实例到一个变量,并在膨胀 View 后直接调用它。这会导致代码稍微复杂一些,但并不多。它看起来像这样;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
final AsyncLayoutInflater.OnInflateFinishedListener callback = new AsyncLayoutInflater.OnInflateFinishedListener()
{
@Override
public void onInflateFinished(View view, int resid, ViewGroup parent)
{
// setup here
}
};
if (savedInstanceState == null) {
AsyncLayoutInflater inflater = new AsyncLayoutInflater(this);
inflater.inflate(R.layout.main, null, callback);
} else {
View view = getLayoutInflater().inflate(R.layout.main, null);
Callback.onInflateFinished(view, R.layout.main, null)
}
}

好吧,现在就是这样。如果您有任何建议或意见,请随时在下面发表评论。
祝你好运,
狮书

关于android - AsyncLayoutInflator 陷阱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45108410/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com