lio*_*ibe 5 performance multithreading android android-layout android-fragments
Android在AsyncLayoutInflater
支持libaray 24.0及更高版本的基础上增加了一个新类,可在Android SDK 4.0或更高版本(几乎所有可用的设备)中使用。
根据Android的文档;
用于异步扩大布局的Helper类。若要使用,请在UI线程上构造AsyncLayoutInflater的实例,然后调用inflate(int,ViewGroup,OnInflateFinishedListener)。膨胀请求完成后,将在UI线程上调用AsyncLayoutInflater.OnInflateFinishedListener。
这适用于延迟创建的UI部分或响应用户交互的部分UI。这允许UI线程在执行相对较重的膨胀时继续响应和设置动画。
我实际上发现这很有用,正如您可能意识到或未意识到的那样,在一个时间上夸大一个复杂的视图是一项昂贵的操作,有时需要100毫秒。因此,当它在主线程上膨胀时,UI可能会变慢。
我发现的另一个好处是,Activities的加载时间更快,因为UI线程可以继续加载下一步,而视图是单独膨胀的。有时,我可以使用这种方法大大加快App启动时间。
话虽这么说,但使用单独的线程来充实视图时可能会发生陷阱。我们将在答案中对其进行解释。
根据Android文档;
为了使布局异步膨胀,它需要具有一个父节点,其parent的generateLayoutParams(AttributeSet)是线程安全的,并且构造为膨胀的所有View均不得创建任何Handler或调用myLooper()。如果由于某种原因而无法异步构造要膨胀的布局,则AsyncLayoutInflater将自动退回到UI线程上膨胀。
这是您必须注意的事情。尽管您的应用程序不会崩溃,但由于AsyncLayoutInflater会自动回退到UI线程上的膨胀,所以现在需要花费两倍的时间来进行膨胀,首先是在单独的线程上,然后是在UI线程上。因此,请仔细观察LogCat,看看AsyncLayoutInflater是否抱怨它在UI线程上膨胀,并对其进行处理。
您可能必须在多个设备和操作系统版本上进行测试,因为可能(未确认)同一视图在某些设备中创建了处理程序,而在其他设备中未创建处理程序。好消息是您不必太完美,因为在最坏的情况下,它不会崩溃,因为AsyncLayoutInflater可以处理它。
通常情况下,问题在于创建处理程序的单个自定义视图。一个非常简单的解决方法是用替换该视图ViewStub
,然后在OnInflateFinishedListener
调用回调时简单地将其膨胀。例如:
<ViewStub android:id="@+id/stub"
android:inflatedId="@+id/subTree"
android:layout="@layout/mySubTree"
android:layout_width="120dip"
android:layout_height="40dip" />
Run Code Online (Sandbox Code Playgroud)
然后在回调中
ViewStub stub = findViewById(R.id.stub);
View inflated = stub.inflate();
Run Code Online (Sandbox Code Playgroud)
还有另一个可怜的危险,这花了我很多小时的调试时间。它与Android活动和片段生命周期有关。众所周知,Android可以在不处于活动状态的任何时候终止其活动。发生这种情况时,Android将在需要显示活动时重新创建活动。它使用savedInstance
捆绑包将“活动”和“片段”还原到其先前状态。
但是活动和片段之间有很大的区别。对于“活动”,操作系统不会重新创建视图,应用必须重新创建视图。重新创建视图后,操作系统将通过调用还原每个视图的状态onRestoreState
。
但是通过Fragments,操作系统实际上重新创建了整个Fragment View,而应用程序仅需初始化类成员。
这在使用AsyncLayoutInflater时会引起严重的问题,因为第一次创建Activity时,尽管onCreate
函数在View膨胀之前已经完成(因为它在单独的线程中膨胀),但是我们仍然不会创建并附加任何片段,直到OnInflateFinishedListener
调用回调。因此,在创建Fragment时,我们已经具有完整的工作Activity和工作视图。
但是,当操作系统重新创建活动时,一旦活动onCreate
功能完成(在视图膨胀之前(因为它在单独的线程中膨胀)),操作系统就会认为是时候重新创建Fragment了。然后它将调用onCreateView
,甚至onActivityCreated
,即使该活动尚未将其视图放大和设置。这将导致许多崩溃,以及不可见的碎片!
解决方案是检查活动的onCreate
功能(如果正在重新创建),方法是检查所savedBundle
传递的不是null
,在这种情况下不使用AsyncLayoutInflater。为此,您将AsyncLayoutInflater.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)
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,现在就这样。如果您有任何建议或意见,请随时在下面发表评论。祝你好运,狮子座
归档时间: |
|
查看次数: |
1862 次 |
最近记录: |