Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 不同步的,不规则的_Android_Multithreading_Performance_Android Layout_Android Fragments - Fatal编程技术网

Android 不同步的,不规则的

Android 不同步的,不规则的,android,multithreading,performance,android-layout,android-fragments,Android,Multithreading,Performance,Android Layout,Android Fragments,Android在其支持libaray版本24.0及更高版本中添加了一个新的AsyncLayoutFlater类,可用于Android SDK 4.0或更高版本(几乎所有可用设备)。 根据Android的文档 用于异步扩展布局的帮助器类。使用、建造 UI线程和调用上的AsyncLayoutFlater实例 充气(int、ViewGroup、OnInflateFinishedListener)。这个 将在上调用AsyncLayoutFlater.OnInflateFinishedListener 充

Android在其支持libaray版本24.0及更高版本中添加了一个新的
AsyncLayoutFlater
类,可用于Android SDK 4.0或更高版本(几乎所有可用设备)。
根据Android的文档

用于异步扩展布局的帮助器类。使用、建造 UI线程和调用上的AsyncLayoutFlater实例 充气(int、ViewGroup、OnInflateFinishedListener)。这个 将在上调用AsyncLayoutFlater.OnInflateFinishedListener 充气请求完成时的UI线程

这是为了 延迟创建或响应用户请求的UI部分 互动。这允许UI线程继续响应& 在执行相对较重的充气时设置动画

事实上,我发现这很有用,正如您可能意识到的,或者您可能没有意识到的那样,在时间上膨胀复杂视图是一项昂贵的操作,有时需要100毫秒。因此,当它在主线程上膨胀时,UI可能会变得迟钝。

我发现的另一个好处是,活动的加载时间更快,因为UI线程可以继续加载的下一步,而视图会单独膨胀。我有时能够使用此方法显著加快应用程序启动时间。


也就是说,当使用单独的线程膨胀视图时,可能会出现陷阱。我们将在回答中解释它们。

根据Android文档

对于要异步膨胀的布局,它需要有一个父级 其generateLayoutParams(AttributeSet)是线程安全的,并且所有 作为通货膨胀一部分构建的视图不得创建任何 处理程序或以其他方式调用myLooper()。如果正在尝试的布局 无论出于何种原因,都不能异步构造, 充气机将自动退回到充气状态 用户界面线程

这是你必须注意的事情。虽然您的应用程序不会崩溃,因为AsyncLayoutFlater将自动退回到UI线程上的膨胀,但现在膨胀所需的时间将增加一倍,首先在单独的线程上,然后在UI线程上。因此,仔细观察日志,看看AsyncLayoutFlater是否抱怨它在UI线程上膨胀,并处理它。

您可能需要在多个设备和操作系统版本上进行测试,因为同一视图可能(未确认)在某些设备中创建处理程序,而在其他设备中不创建处理程序。好消息是,您不必做到完美,因为在最坏的情况下,它仍然不会崩溃,因为AsyncLayoutFlater会处理它。

通常,问题是创建处理程序的单个自定义视图。对此,一个非常简单的解决方法是将该视图替换为
ViewStub
,然后在调用
OnInflateFinishedListener
回调时将其膨胀。 例如:

<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />

还有一个危险的可怜虫,它花费了我很多小时的调试。它与Android活动和片段生命周期有关。正如我们所知,Android可以随时在不在前台的情况下杀死某个活动。当这种情况发生时,Android将在需要显示时重新创建活动。它使用
savedInstance
捆绑包将活动和片段恢复到以前的状态。

但是活动和片段之间有很大的区别。对于活动,操作系统不会重新创建视图,应用程序必须重新创建视图。重新创建视图后,操作系统将通过调用
onRestoreState

恢复每个视图的状态 但通过片段,操作系统实际上会重新创建整个片段视图,应用程序只需初始化类成员。

这在使用AsyncLayoutFlater时会导致一个严重的问题,因为当第一次创建活动时,虽然
onCreate
函数在视图膨胀之前完成(因为它在单独的线程上膨胀),但我们仍然不会创建和附加任何片段,直到调用
OnInflateFinishedListener
回调。因此,当片段被创建时,我们已经有了一个完整的工作活动和一个工作视图。

但是当操作系统重新创建活动时,一旦Activity
onCreate
函数完成,也就是视图膨胀之前(在单独的线程中膨胀),操作系统就会认为是时候重新创建片段了。然后,它将调用
onCreateView
,甚至调用
onActivityCreated
,即使活动的视图尚未膨胀和设置。这将导致许多崩溃和不可见的碎片

解决方法是检查活动的
onCreate
函数(如果正在重新创建),方法是检查传递的
savedBundle
是否为
null
,并且在这种情况下不使用AsyncLayoutFlater。为此,将
AsyncLayoutFlater.OnInflateFinishedListener
实例分配给一个变量,并在膨胀视图后直接调用它。这将导致代码稍微复杂一些,但不会太复杂。它看起来像这样

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)
    }
}
好了,现在就这样。如果您有任何建议或意见,请随时在下面发表评论。 祝你好运 狮子座

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)
    }
}