我对保存Android中碎片内部视图状态的最佳做法感到困惑。
我认为setRetainInstance(true)
可以做到这一点;但是,虽然这确实保留了View
中声明的旧全局Fragment
引用,但在扩展布局时不会使用这些视图。因此,我必须手动将属性从旧的全局视图引用转移到膨胀布局中的新视图。请参阅下面的代码,了解我是如何做到的。
public static class MyFragment extends Fragment {
// I need to save the state of two views in the fragment
ProgressBar mProgress;
TextView mText;
@Override public void onCreate(Bundle savedInstanceState) {
// savedInstanceState == null if setRetainInstance == true
super.onCreate(savedInstanceState);
// Retain the instance between configuration changes
setRetainInstance(true);
}
@Override public View onCreateView(LayoutInflater i, ViewGroup c, Bundle b) {
// Inflate xml layout for fragement (orientation dependent)
View v = i.inflate(R.layout.fragment_main, c, false);
// Grab Views from layout
ProgressBar tmpProgress = (ProgressBar) v.findViewById(R.id.progress);
TextView tmpText = (TextView) v.findViewById(R.id.text);
// If View References exist, transfer state from previous Views
if(mProgress != null){
tmpProgress.setProgress(mProgress.getProgress());
tmpText.setText(mText.getText());
}
// Replace View references
mProgress = tmpProgress;
mText = tmpText;
return v;
}
}
我觉得setRetainInstanceState(true)
应主要用于保持片段处于活动状态,以便后台进程可以保持与它的连接。如果是这种情况,我应该不使用这种方法来保留View
的状态吗?
更具体地说:
setRetainInstanceState
为true
,则上述代码是在定向调用之间保留View
状态的最佳方式吗?setRetainInstanceState(false)
并使用Bundle
来维护视图状态吗? (注意:bundles cannot be used if setRetainInstance == true
)答案 0 :(得分:4)
使用setRetainInstance
请勿将您的视图保留在内存中,只需根据您为片段提供的Singleton
或tag
保持同一实例ID
。这很好,因为当你Fragment
进入后台时,你的视图会被破坏,而不是不必要的记忆。
回答你的两个问题:
不要保持您的视图创建!每次调用onCreateView时重新创建视图。保持状态和更多使用全局变量。
不,一旦您将其设置为Fragment
,Android操作系统将为相同的标记或ID保留相同的实例,因此当它转到后台时请记住将Bundle
保存为视图状态在onSaveInstanceState
,以便在下次恢复查看状态。
在此处详细了解Fragments生命周期:http://developer.android.com/guide/components/fragments.html#Lifecycle
关于onSaveInstanceState
,请点击此处了解详情:http://developer.android.com/reference/android/app/Fragment.html#onSaveInstanceState(android.os.Bundle)
例如,您可以这样做:
package com.example.stackoverflowsandbox;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MyFragment extends Fragment {
public static String VIEW_STATE_A = "a";
public static String VIEW_STATE_B = "b";
public static String VIEW_STATE_C = "c";
private String currentState = MyFragment.VIEW_STATE_A;
private View view;
public void changeStateTo( final String newState ) {
if ( this.currentState != newState ) {
this.currentState = newState;
this.updateViewState( this.currentState );
}
}
@Override
public View onCreateView( final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState ) {
this.setRetainInstance( true );
this.view = inflater.inflate( R.layout.my_view, null );
this.updateViewState( this.currentState );
return this.view;
}
@Override
public void onDestroyView() {
this.view = null; // release the reference to GC
super.onDestroyView();
}
private void updateViewState( final String state ) {
// do what you want to do with your view here...
}
}
将您的fragment
州改为changeStateTo
。
答案 1 :(得分:-1)
以下是她选择setRetainInstance的一些很好的理由:Handling Configuration Changes with Fragments
public class SomeFragment extends Fragment {
/**
* This method will only be called once when the retained
* Fragment is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
}
}
然后在您的父Activity
中,在实例化新实例之前检查Fragment
的现有实例。
如果由于配置更改而再次调用活动onCreate(Bundle)
,则FragmentManager
将包含Fragment
的现有实例。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_priceindex);
// create a new Fragment only if we can't find an existing one
if (getSupportFragmentManager.findFragmentById(R.id.containerId) == null){
getSupportFragmentManager.beginTransaction().add(R.id.containerId,
new SomeFragment()).commit();
}
}
<强>编辑:强>
对于对暴露问题的不理解感到抱歉,但我相信即使没有与正在运行的任务的交互,仍有充分的理由 不要重新创建视图。
让我们假设一个典型的场景 - 期间的昂贵操作 活动创建(onCreate(Bundle)),同时显示一个 在您的应用程序正在进行繁重的工作时,屏幕会被丢失。你没有 但是,处理屏幕旋转。这将导致以下结果 用户体验:您的用户加载应用,看到加载屏幕, 旋转设备,再次看到相同的加载屏幕,旋转它 再次,看到另一个加载屏幕......好吧,你得到了图片。哦, 等等,你的应用程序还有可能崩溃:)