![](/img/trans.png)
[英]Android - Honeycomb - Action Bar tab fragments save/restore state
[英]Save/Restore fragments state android
我正在嘗試使用Jack Wharton的ViewPager庫( 此處 )創建一個應用程序,僅使用每個頁面的圖像(類似於Prixing( 此處 )主屏幕)。 一切正常,除了片段中的saveInstance。
在Jack Wharton的例子中,他將文本存儲在名為mContent的String變量中,並在onCreate中恢復它,但在我的情況下,我該怎么辦? 保存/恢復位圖?! 任何客觀的答案將不勝感激!
我對使用應用程序的Fragment很新,因為我看到的每一個例子,只展示了基礎知識,而且對於更復雜的問題,它變得越來越困難。
PS。 如果有用的知道,我正在使用CirclePageIndicator。
目前的片段代碼:
public final class SpecialOfferFragment extends Fragment {
private int imageResourceId;
public static SpecialOfferFragment newInstance(int i) {
//probably I'll use a bitmap(downloaded) as parameter instead of using static images
SpecialOfferFragment fragment = new SpecialOfferFragment();
fragment.imageResourceId = i;
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// if ((savedInstanceState != null) { }
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ImageView image = new ImageView(getActivity());
image.setImageResource(imageResourceId);
image.setScaleType(ScaleType.FIT_XY);
LinearLayout layout = new LinearLayout(getActivity());
layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
layout.setGravity(Gravity.CENTER);
layout.addView(image);
return layout;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//smth to save here..
}
}
在應用程序的當前狀態中,我得到以下異常:
04-12 07:28:17.760: E/AndroidRuntime(31903): FATAL EXCEPTION: main
04-12 07:28:17.760: E/AndroidRuntime(31903): java.lang.NullPointerException
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.java:1576)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.java:1617)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.java:481)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.Activity.performSaveInstanceState(Activity.java:1113)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1188)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:2804)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.ActivityThread.handleStopActivity(ActivityThread.java:2862)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.ActivityThread.access$900(ActivityThread.java:127)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1175)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.os.Handler.dispatchMessage(Handler.java:99)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.os.Looper.loop(Looper.java:137)
04-12 07:28:17.760: E/AndroidRuntime(31903): at android.app.ActivityThread.main(ActivityThread.java:4511)
04-12 07:28:17.760: E/AndroidRuntime(31903): at java.lang.reflect.Method.invokeNative(Native Method)
04-12 07:28:17.760: E/AndroidRuntime(31903): at java.lang.reflect.Method.invoke(Method.java:511)
04-12 07:28:17.760: E/AndroidRuntime(31903): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
04-12 07:28:17.760: E/AndroidRuntime(31903): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
04-12 07:28:17.760: E/AndroidRuntime(31903): at dalvik.system.NativeStart.main(Native Method)
每當我暫停/停止包含此片段的活動時,就會發生這種情況,例如按Home鍵。
**
**
public class MainMenu extends FragmentActivity {
//private List<CategoriesHolder> categoriesList = new ArrayList<CategoriesHolder>();
//private CategoriesAdapter categoriesAdapter = null;
//private GridView gv_mainmenu_categories;
SpecialOfferFragmentAdapter mAdapter;
ViewPager mPager;
PageIndicator mIndicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainmenu);
linkUI();
setAction();
// just for testing
String[] imagesUrls = null;
mAdapter = new SpecialOfferFragmentAdapter(getSupportFragmentManager(),
this, imagesUrls);
//categoriesAdapter = new CategoriesAdapter(this, categoriesList);
// used for Categories GridView
//gv_mainmenu_categories.setAdapter(categoriesAdapter);
// used for ViewPager
mPager.setAdapter(mAdapter);
mIndicator.setViewPager(mPager);
}
private void linkUI() {
mPager = (ViewPager) findViewById(R.id.vp_mainmenu_special_offers);
mIndicator = (CirclePageIndicator) findViewById(R.id.indicator);
//gv_mainmenu_categories = (GridView) findViewById(R.id.gv_mainmenu_categories);
}
private void setAction() {
}
}
public class SpecialOfferFragmentAdapter extends FragmentPagerAdapter implements
IconPagerAdapter {
private int[] mCarouselImages = new int[] { R.drawable.pic1,
R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5
};
private String[] imagesUrls;
private Context context;
public static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar, R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms, R.drawable.perm_group_location };
private int mCount = mCarouselImages.length;
public SpecialOfferFragmentAdapter(FragmentManager fm, Context context,
String[] imagesUrls) {
super(fm);
this.context = context;
this.imagesUrls = imagesUrls;
}
@Override
public Fragment getItem(int position) {
return SpecialOfferFragment.newInstance(mCarouselImages[position]);
}
@Override
public int getCount() {
return mCount;
}
@Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
要實現您想要的東西,您應該使用整數值來存儲ViewPager
的當前位置,然后使用此值為ViewPager
設置正確的位置。
例如,在FragmentActivity
執行類似的操作:
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("mMyCurrentPosition", mPager.getPosition());
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mMyCurrentPosition = savedInstanceState.getInt("mMyCurrentPosition");
// where mMyCurrentPosition should be a public value in your activity.
}
這將保存您的ViewPager的最后位置。 然后在你的onResume()
,你可以檢查
if(mMyCurrentPosition != 0){
mPager.setCurrentItem(mMyCurrentPosition);
}
我認為這應該有用,將圖像/位圖保存在捆綁中並不是一個好習慣(我認為你不能這樣做)。
好的,首先想要清除一些可能解決你對saveinstancestate的困惑的事情。 Savedinstancestate只能處理原語(int,double,float,byte ..)和String對象。 這應該是您所需要的,但在某些情況下,您還希望保存其他對象的實例。 為此,您需要一些其他模式來完成工作,例如工廠模式包含所有位圖的數組。 比如創建一個類ImageFactory,它包含一個靜態的位圖ArrayList。 無論何時旋轉設備,都會再次調用oncreateview和onactivitycreated方法,這是檢查是否要從工廠檢索信息的時刻。 例如
if(savedInstanceState!= null){//我們有一個savedinstancestate所以可能有保存的圖像ImageFactory.getBMPs(); }
希望你能用這個信息做些什么。 祝好運
在你的主要活動中,這對我來說簡單易行
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
onCreate(savedInstanceState);
}
在你的清單里面
<activity
android:configChanges="orientation|screenSize"/>
我在使用SharedPreference更改選項卡時創建了自己保存片段數據的方法:
方法如:
public void saveData() {
Log.d("msg", "Save Instance");
SharedPreferences.Editor outState = getActivity().getSharedPreferences("order", Context.MODE_APPEND).edit();
orderDate = orderDateEditText.getText().toString();
orderBy = orderByEditText.getText().toString();
orderMobileNo = orderMobileNoEditText.getText().toString();
orderTransport = orderTransportEditText.getText().toString();
orderInvoicePer = orderInvoicePerEditText.getText().toString();
orderCharge = orderChargeEditText.getText().toString();
orderGoodsDispatch = orderGoodsDispatchEditText.getText().toString();
orderOthers = orderOthersEditText.getText().toString();
orderIsDirect = orderIsDirectCheckBox.isChecked() ? 1 : 0;
outState.putBoolean("saved", true);
outState.putString("orderDate", orderDate);
outState.putString("orderBy", orderBy);
outState.putString("orderMobileNo", orderMobileNo);
outState.putString("orderTransport", orderTransport);
outState.putString("orderInvoicePer", orderInvoicePer);
outState.putString("orderCharge", orderCharge);
outState.putString("orderGoodsDispatch", orderGoodsDispatch);
outState.putString("orderOthers", orderOthers);
outState.putInt("orderIsDirect", orderIsDirect);
outState.commit();
}
在何時調用此方法
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
saveData();
}
使用EditText替換保存的數據:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
/***** PUT DATA IN EDITTEXT is ITS AVAILABLE IN BUNDLE *****/
SharedPreferences orderData = getActivity().getSharedPreferences("order", Context.MODE_APPEND);
Log.d("msg", ""+orderData.getBoolean("saved", false));
if(orderData.getBoolean("saved", false))
{
orderDate = orderData.getString("orderDate", "");
orderBy = orderData.getString("orderBy", "");
orderMobileNo = orderData.getString("orderMobileNo", "");
orderTransport = orderData.getString("orderTransport", "");
orderInvoicePer = orderData.getString("orderInvoicePer", "");
orderCharge = orderData.getString("orderCharge", "");
orderGoodsDispatch = orderData.getString("orderGoodsDispatch", "");
orderOthers = orderData.getString("orderOthers", "");
orderIsDirect = orderData.getInt("orderIsDirect", 0);
orderDateEditText.setText(orderDate);
orderByEditText.setText(orderBy);
orderMobileNoEditText.setText(orderMobileNo);
orderTransportEditText.setText(orderTransport);
orderInvoicePerEditText.setText(orderInvoicePer);
orderChargeEditText.setText(orderCharge);
orderGoodsDispatchEditText.setText(orderGoodsDispatch);
orderOthersEditText.setText(orderOthers);
if(orderIsDirect == 0)
orderIsDirectCheckBox.setChecked(false);
else
orderIsDirectCheckBox.setChecked(true);
}
}
願這段代碼對你有幫助......
謝謝...
我不太確定這個問題是否仍然困擾着你,因為已經有好幾個月了。 但我想分享一下我是如何處理這個問題的。 這是源代碼:
int FLAG = 0;
private View rootView;
private LinearLayout parentView;
/**
* The fragment argument representing the section number for this fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section number.
*/
public static Fragment2 newInstance(Bundle bundle) {
Fragment2 fragment = new Fragment2();
Bundle args = bundle;
fragment.setArguments(args);
return fragment;
}
public Fragment2() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.e("onCreateView","onCreateView");
if(FLAG!=12321){
rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false);
changeFLAG(12321);
}
parentView=new LinearLayout(getActivity());
parentView.addView(rootView);
return parentView;
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onDestroy()
*/
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Log.e("onDestroy","onDestroy");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStart()
*/
@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
Log.e("onstart","onstart");
}
/* (non-Javadoc)
* @see android.support.v4.app.Fragment#onStop()
*/
@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();
if(false){
Bundle savedInstance=getArguments();
LinearLayout viewParent;
viewParent= (LinearLayout) rootView.getParent();
viewParent.removeView(rootView);
}
parentView.removeView(rootView);
Log.e("onStop","onstop");
}
@Override
public void onPause() {
super.onPause();
Log.e("onpause","onpause");
}
@Override
public void onResume() {
super.onResume();
Log.e("onResume","onResume");
}
這是MainActivity:
/**
* Fragment managing the behaviors, interactions and presentation of the
* navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in
* {@link #restoreActionBar()}.
*/
public static boolean fragment2InstanceExists=false;
public static Fragment2 fragment2=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
switch(position){
case 0:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit();
break;
case 1:
Bundle bundle=new Bundle();
bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY);
if(!fragment2InstanceExists){
fragment2=Fragment2.newInstance(bundle);
fragment2InstanceExists=true;
}
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, fragment2).commit();
break;
case 2:
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit();
break;
default:
break;
}
}
parentView是關鍵點。 通常,在onCreateView上,我們只使用return rootView。 但是現在,我將rootView添加到parentView,然后返回parentView。 要防止“指定的子節點已經有父節點。你必須在...上調用removeView()”錯誤,我們需要調用“parentView.removeView(rootView)”,否則我提供的方法就沒用了。 我也想分享我是如何找到它的。 首先,我設置一個布爾值來指示實例是否存在。 當實例存在時,rootView將不會再次膨脹。 但是后來,logcat給孩子已經有了父東西,所以我決定用另一個父親作為中間父視圖。 這就是它的工作原理。 希望它對你有所幫助。
讓我寫下我處理這個問題的方法。 我在Activity中保留了一個片段對象變量,以便以后進行交互。 在onCreate()方法中,我檢查是否存在savedInstanceState(由屏幕旋轉或其他原因引起)。
public class MainActivity extends AppCompatActivity {
PlaceAddFragment mFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
mFragment = new PlaceAddFragment();
mFragment.setProfileImages(incomingPics);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.form_fragment_holder, mFragment, PlaceAddFragment.TAG)
.commit();
}else{
mFragment = (PlaceAddFragment) getSupportFragmentManager().findFragmentByTag(PlaceAddFragment.TAG);
}
}
在我的fragment類中,我重寫onSaveInstanceState方法,並在其中添加setRetainInstance(true),如下所示:
public class PlaceAddFragment extends Fragment {
public static final String TAG = ".PlaceAddFragment";
private ProfileImageAdapter mAdapter;
private List<ProfileImage> mProfileImages;
private Context mContext;
public PlaceAddFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mContext = getContext();
View view = inflater.inflate(R.layout.fragment_place_add, container, false);
RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.hw_pictures_holder);
mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
mAdapter = new ProfileImageAdapter(mContext, mProfileImages);
mRecyclerView.setAdapter(mAdapter);
return view;
}
@Override
public void onSaveInstanceState(final Bundle outState) {
super.onSaveInstanceState(outState);
setRetainInstance(true);
}
@Override
public void onDestroy() {
super.onDestroy();
mAdapter = null;
mProfileImages = null;
}
public void setProfileImages(List<ProfileImage> incomingPics) {
this.mProfileImages = incomingPics;
}
public List<ProfileImage> getProfileImages() {
return this.mProfileImages;
}
}
如果您希望此代碼工作,您應該為這些代碼實現ProfileImageAdapter mAdapter,ProfileImage對象和所有xml布局。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.