Я более подробно с надеждой, что вопрос будет на самом деле легче понять.Как сохранить пользовательское состояние ListFragment с изменением ориентации
Цель деятельности: позволяет пользователям выбирать изображения из галереи; отобразить эскиз изображения в ListFragment вместе с именем пользователя, дал изображение; когда пользователь закончил сохранять uri и заголовок каждого изображения, а имя пользователя дало эту коллекцию изображений.
Задача: Когда устройство повернуто, FragmentList теряет все изображения и названия, которые пользователь уже выбрал, то есть все строки списка отсутствуют.
Покушение решения проблем:
Реализована RetainedFragment, чтобы сохранить коллекцию List при повороте устройства. Раньше я этого не делал и вычислял «А, адаптер получает пустую коллекцию списков при создании. Я сохраню состояние списка, а затем, когда вызывается функция onCreate, я могу скопировать сохраненный список в конструктор адаптера, и он «Я буду работать». Но это не так.
Тогда я подумал: «Конечно, он не работает, вы не уведомили об этом переходник!» Поэтому я положил
adapter.notifyDataSetChanged()
в onCreate. Это не сработало.Затем я переместил
adapter.notifyDataSetChanged()
вonStart
, думая, что мне может потребоваться уведомить адаптер позже о жизненном цикле деятельности. Не работает.
Примечания: У меня есть другая активность в этом же приложении, которые используют это же обычай ListViewFragment и состояние ListFragment в настоящее время сохраняются при изменении ориентации устройства. Эта деятельность имеет два принципиальных отличия: фрагмент жестко закодирован в .xml (я не думаю, что это изменило бы ситуацию, кроме, может быть, нативная сохранность XML-фрагментов для Android отличается от программно добавленных); и эта активность использует Loader и LoaderManager и получает свои данные от Провайдера, который я создал (который собирает данные из моей базы данных SQLite). Если посмотреть на различия между этими двумя действиями, это заставило меня думать, что «вы не обрабатываете данные, которые правильно адаптируют адаптер», и вдохновил меня на использование RetainedFragment для сохранения коллекции List при повороте устройства.
... который побуждает меня думать о том, выяснить, как, как и Android говорит на их Loader странице о LoaderManager:
«Абстрактный класс, связанный с деятельностью или фрагментом для управления одним или более Экземпляры загрузчика. Это помогает приложению управлять более длительными операциями в сочетании с жизненным циклом активности или фрагмента, наиболее часто используемым с помощью CursorLoader, однако приложения могут свободно писать свои собственные загрузчики для загрузки других типов данных ».
Это «загрузка других типов данных» часть, которая имеет меня думать «Могу ли я использовать LoaderManager, чтобы загрузить данные списка по двум причинам я уклоняюсь от этого: 1) то, что я уже, по крайней мере, концептуально , должен работать, 2) то, что я делаю в настоящее время, на самом деле не является «более продолжительной операцией», я не думаю.
Исследование:
StackOverflow Fool proof way to handle Fragment on orientation change
- сохранить состояние фрагмента.
- Я думаю, что RetainedFragment я использую сохраняет то, что должно быть сохранено. (?)
Once for all, how to correctly save instance state of Fragments in back stack?
Сохранить фрагменты backstack.
Не показано в моем коде, наклеенный ниже, но моя деятельность динамически создает три другие фрагменты, и я использую следующий, если
savedInstanceState !=null
и состояние этих фрагментов сохраняется без выполнения каких-либо работ вonSaveInstanceState()
(это отчасти, почему он чувствует, как мои проблема заключается не в том, чтобы что-то делать вonSaveInstanceState
, потому что Android управляет сохранением моего состояния других фрагментов, так что не стоит ли это делать с ListFragment? Кажется, это должно быть).if(savedInstanceState.containsKey(AddActivity_Frag1.F1_TAG)){ frag1 = (AddActivity_Frag1)getFragmentManager().getFragment(savedInstanceState, AddActivity_Frag1.F1_TAG); }
Многие StackOverflow вопросы, касающиеся моего запроса, кажется, в основном о том, как сохранить положение прокрутки ListFragment с изменением ориентации, но мне не нужно делать что (хотя я прочитал их, ища советы, которые могут помочь).
- Android Loaders
- Android Caching Bitmaps (RetainFragment stuff)
активность - со многими, надеюсь, не связанных между собой вещей, Удалено:
public class AddActivity extends Activity{
// data collection
List<ImageBean> beanList;
// adapter
AddCollectionAdapter adapter;
// ListViewFragment tag
private static final String LVF_TAG = "list fragment tag";
// fragment handles
ListViewFragment listFrag;
// Handles images; LruCache for bitmapes
ImageHandler imageHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add2);
// Create ImageHandler that holds LruCache
imageHandler = new ImageHandler(this, getFragmentManager());
// Obtain retained List<ImageBean> or create new List<ImageBean>.
RetainedFragment retainFragment = RetainedFragment.findOrCreateRetainFragment(getFragmentManager());
beanList = retainFragment.list;
if(beanList == null){
beanList = new ArrayList<ImageBean>();
retainFragment.list = beanList;
}
// create fragments
if(savedInstanceState == null){
listFrag = new ListViewFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.add_fragFrame, listFrag, LVF_TAG);
ft.commit();
}else{
listFrag = (ListViewFragment)getFragmentManager().findFragmentByTag(LVF_TAG);
}
// create adapter
adapter = new AddCollectionAdapter(this, beanList);
// set list fragment adapter
listFrag.setListAdapter(adapter);
}
@Override
protected void onStart() {
// TESTING: If device orientation has changed List<ImageBean> was saved
// with a RetainedFragment. Seed the adapter with the retained
// List.
adapter.notifyDataSetChanged();
super.onStart();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// Android automatically saves visible fragments here. (?)
super.onSaveInstanceState(outState);
}
/*
* ImageBean.
*/
public static class ImageBean{
private String collectionName; // Title of image collection
private String imageUri; // Image URI as a string
private String imageTitle; // Title given to image
public ImageBean(String name, String uri, String title){
collectionName = name;
imageUri = uri;
imageTitle = title;
}
public String getCollectionName() {
return collectionName;
}
public String getImageUri() {
return imageUri;
}
public String getImageTitle() {
return imageTitle;
}
}
/*
* Called when user is finished selecting images.
*
* Performs a bulk insert to the Provider.
*/
private void saveToDatabase() {
int arraySize = beanList.size();
final ContentValues[] valuesArray = new ContentValues[arraySize];
ContentValues values;
String imageuri;
String title;
int counter = 0;
for(ImageBean image : beanList){
imageuri = image.getImageUri();
title = image.getImageTitle();
values = new ContentValues();
values.put(CollectionsTable.COL_NAME, nameOfCollection);
values.put(CollectionsTable.COL_IMAGEURI, imageuri);
values.put(CollectionsTable.COL_TITLE, title);
values.put(CollectionsTable.COL_SEQ, counter +1);
valuesArray[counter] = values;
counter++;
}
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... arg0) {
getContentResolver().bulkInsert(CollectionsContentProvider.COLLECTIONS_URI, valuesArray);
return null;
}
@Override
protected void onPostExecute(Void result) {
// End this activity.
finish();
}
};
task.execute();
}
public ImageHandler getImageHandler(){
return imageHandler;
}
}
class RetainedFragment extends Fragment{
private static final String TAG = "RetainedFragment";
// data to retain
public List<AddActivity.ImageBean> list;
public static RetainedFragment findOrCreateRetainFragment(FragmentManager fm){
RetainedFragment fragment = (RetainedFragment)fm.findFragmentByTag(TAG);
if(fragment == null){
fragment = new RetainedFragment();
fm.beginTransaction().add(fragment, TAG);
}
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
}
ListFragment:
public class ListViewFragment extends ListFragment {
ListFragListener listener;
public interface ListFragListener{
public void listFragListener(Cursor cursor);
}
@Override
public void onCreate(Bundle savedInstanceState) {
// Retain this fragment across configuration change
setRetainInstance(true);
super.onCreate(savedInstanceState);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Set listener
if(activity instanceof ListFragListener){
listener = (ListFragListener)activity;
}else{
//Instantiating activity does not implement ListFragListener.
}
}
@Override
public void onListItemClick(ListView listView, View v, int position, long id) {
// no action necessary
}
}
адаптер:
public class AddCollectionAdapter extends BaseAdapter {
// data collection
List<ImageBean> beanList;
// layout inflator
private LayoutInflater inflater;
// context
Context context;
public AddCollectionAdapter(Context context, List<ImageBean> beanList){
this.context = context;
this.beanList = beanList;
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return beanList.size();
}
@Override
public Object getItem(int position) {
return beanList.get(position);
}
@Override
public long getItemId(int arg0) {
// collection not from database nor is going directly to database; this is useless.
return 0;
}
// holder pattern
private class ViewHolder{
ImageView imageView;
TextView titleView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View xmlTemplate = convertView;
if(xmlTemplate == null){
//inflate xml
xmlTemplate = inflater.inflate(R.layout.frag_listview_row, null);
// initilaize ViewHolder
holder = new ViewHolder();
// get views that are inside the xml
holder.imageView = (ImageView)xmlTemplate.findViewById(R.id.add_lvrow_image);
holder.titleView = (TextView)xmlTemplate.findViewById(R.id.add_lvrow_title);
// set tag
xmlTemplate.setTag(holder);
}else{
holder = (ViewHolder)xmlTemplate.getTag();
}
// Get image details from List<ImageBean>
ImageBean bean = beanList.get(position);
String imageUri = bean.getImageUri();
String title = bean.getImageTitle();
// Set Holder ImageView bitmap; Use parent activity's ImageHandler to load image into Holder's ImageView.
((AddActivity)context).getImageHandler().loadBitmap(imageUri, holder.imageView, Constants.LISTVIEW_XML_WIDTH, Constants.LISTVIEW_XML_HEIGHT);
// Set Holder's TextView.
holder.titleView.setText(title);
// return view
return xmlTemplate;
}
}