Intereting Posts
Android-событие для изменения состояния подключения к Интернету Угловой и ионный импульс не работают на Android Приложение для Android, подключающееся к веб-сервису – не работает Log.e не печатает трассировку стека UnknownHostException Ionic2 / Cordova build публикует приложение с различными функциями. Пример: бесплатный и оплаченный Как увеличить список элементов из центра пинча Разница между представлением AppCompat и обычным представлением Android Кнопки действий не отображаются на панели действий? Разный открытый ключ RSA, созданный на Android Не удается запустить приложение Android на эмуляторе / устройстве – активности не существует? Выпадающая кнопка Android Храните большое количество текстов для Android-приложений Ошибка AndEngine при загрузке библиотеки Android-контроллер мультимедиа отображает отображение на короткое время Отображение символов Unicode в TextView Android

Сохранить / Восстановить фрагменты состояния Android

Я пытаюсь создать приложение, которое использует библиотеку ViewPager Джека Уортона ( здесь ), используя только изображения для каждой страницы (что-то вроде главного экрана Prixing ( здесь )). Все работает нормально, за исключением saveInstance в фрагменте.

В примере Джека Уортона он хранит текст в переменной String с именем mContent и восстанавливает его в onCreate, но в моем случае, что мне делать? Сохранить / Восстановить растровое изображение ?! Любой объективный ответ был бы очень признателен!

Я совершенно новичок в этом фрагменте, используя приложения, потому что каждый пример, на который я смотрю, представляет только основы, и это становится сложнее для более сложных.

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) 

Это происходит всякий раз, когда я приостанавливаю / останавливаю действие, содержащее этот фрагмент, например, нажатие кнопки «Домой».

**

EDIT с кодом:

**

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

Solutions Collecting From Web of "Сохранить / Восстановить фрагменты состояния Android"

Чтобы достичь того, что вы хотите, вы должны использовать целочисленное значение для хранения текущей позиции в вашем 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); } 

Я думаю, что это должно работать, не рекомендуется сохранять изображения / растровые изображения в комплекте (и я не думаю, что вы это сделаете).

Это работало для меня легко и просто внутри вашей основной деятельности

  @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); onCreate(savedInstanceState); } 

И внутри вашего манифеста

  <activity android:configChanges="orientation|screenSize"/> 

Хорошо сначала id, чтобы очистить что-то, что может решить вашу путаницу в отношении сохраненного состояния. Savedinstancestate может обрабатывать только примитивы (int, double, float, byte ..) и String. Это должно быть все, что вам нужно, но в некоторых случаях вы также хотите сохранить экземпляры других объектов. Для этого вам понадобится другой шаблон для выполнения задания, например, шаблон фабрики, в котором содержится массив всех ваших растровых изображений. Например, создайте класс ImageFactory, который содержит статический ArrayList растровых изображений. Всякий раз, когда вы вращаете свое устройство, методы oncreateview и onactivitycreated вызываются снова, и на этот момент нужно проверить, хотите ли вы получать информацию с вашего завода или нет. например

If (savedInstanceState! = Null) {// у нас есть сохраненное состояние, так что, возможно, будут сохранены изображения ImageFactory.getBMPs (); }

Надеюсь, что вы сможете что-то сделать с этой информацией. удачи

Я создал свой собственный метод для сохранения данных фрагмента, а вкладка изменена с использованием 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; } } 

Родительский элемент является ключевой точкой. Обычно, когда onCreateView, мы просто используем return rootView. Но теперь я добавляю rootView в parentView, а затем возвращаю parentView. Чтобы предотвратить «У указанного дочернего элемента уже есть родительский элемент. Вы должны вызвать removeView () на …», нам нужно вызвать «parentView.removeView (rootView)», или метод, который я поставил, бесполезен. Я также хотел бы поделиться тем, как я его нашел. Во-первых, я настроил логическое значение, чтобы указать, существует ли экземпляр. Когда экземпляр существует, rootView снова не будет завышен. Но тогда logcat дал ребенку уже родительский предмет, поэтому я решил использовать другого родителя в качестве промежуточного родительского представления. Вот как это работает. Надеюсь, это вам полезно.

Позвольте мне написать свой способ справиться с этой проблемой. Я сохраняю в объекте переменную объекта фрагмента для последующего взаимодействия. В методе 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); } } 

В моем классе фрагмента я переопределяю метод 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 для них.