0

Я пытался найти эту проблему, но я не смог найти решение. У меня проблема с сохранением элементов ListView в фрагменте. Дело в том, у меня есть несколько фрагментовКак сохранить элементы списка/адаптер в фрагменте и восстановить из заднего стека

Пусть говорят ФРАГМЕНТ A, ФРАГМЕНТ B и ФРАГМЕНТ C, и ФРАГМЕНТ А имеет ListView, элемент в ListView может быть изменен при прокрутке (так же, как сроки в социальной медиа-приложения). Когда я меняю фрагмент A, я использовал метод addToBackStack (null).

Проблема в том, как сохранить список и восстановить его, если нажата кнопка «Назад»?

onSaveInstanceState() никогда не вызывается, потому что хост активность никогда не убивают, только изменить фрагмент с помощью этого:

public void changeFragment(Fragment fragment, ColorDrawable colorDrawable){ 
    Fragment newFrag = fragment; 
    ColorDrawable newColor = colorDrawable; 

    String backStateName = fragment.getClass().getName(); 
    FragmentManager manager = getSupportFragmentManager(); 
    boolean fragmentPopped = manager.popBackStackImmediate (backStateName, 0); 
    if (!fragmentPopped){ //fragment not in back stack, create it. 
     FragmentTransaction ft = manager.beginTransaction(); 
     ft.replace(R.id.content_fragment, fragment); 
     ft.addToBackStack(backStateName); 
     ft.commit(); 
    } 

    //to change the actionbar color 
    getSupportActionBar().setBackgroundDrawable(newColor); 
} 

вот мой код пытается сохранить и восстановить ListView:

@Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     //try to save listview scroll 
     index = myList.getFirstVisiblePosition(); 
     View v = myList.getChildAt(0); 
     top = (v == null) ? 0 : (v.getTop() - myList.getPaddingTop()); 
     index = 1; 
     //try to save listview items 
     savedAdapter = adapter; 
     fromBackStack = true; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     myList.setSelectionFromTop(index, top); 
     myList.setAdapter(savedAdapter); 
    } 

здесь код, который я сделал до сих пор:

package com.ngapainya.ngapainya.fragment; 


import android.app.Activity; 
import android.graphics.drawable.ColorDrawable; 
import android.net.ParseException; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.widget.SwipeRefreshLayout; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.AbsListView; 
import android.widget.AdapterView; 
import android.widget.ListView; 

import com.ngapainya.ngapainya.R; 
import com.ngapainya.ngapainya.activity.volunteer.ContainerActivity; 
import com.ngapainya.ngapainya.adapter.HomeAdapter; 
import com.ngapainya.ngapainya.fragment.child.DetailPostFragment; 
import com.ngapainya.ngapainya.model.Home; 

import java.util.ArrayList; 

/** 
* A simple {@link Fragment} subclass. 
*/ 
public class HomeFragment extends Fragment implements AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener{ 
    private FragmentActivity myContext; 
    private View myFragmentView; 
    private ArrayList<Home> filelist; 
    private ListView myList; 
    private HomeAdapter adapter; 
    private SwipeRefreshLayout swipeRefreshLayout; 

    //try save instance listview 
    boolean fromBackStack = false; 
    int index; 
    int top; 
    HomeAdapter savedAdapter; 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     //try to save listview scroll 
     index = myList.getFirstVisiblePosition(); 
     View v = myList.getChildAt(0); 
     top = (v == null) ? 0 : (v.getTop() - myList.getPaddingTop()); 
     index = 1; 
     //try to save listview items 
     savedAdapter = adapter; 
     fromBackStack = true; 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     myList.setSelectionFromTop(index, top); 
     myList.setAdapter(savedAdapter); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     myContext = (FragmentActivity) activity; 
     super.onAttach(activity); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     // Inflate the layout for this fragment 
     myFragmentView = inflater.inflate(R.layout.fragment_home, container, false); 

     filelist = new ArrayList<Home>(); 

     //dummy data 
     filelist.add(new Home("post", 1)); //post image 
     filelist.add(new Home("post", 2)); //post location 
     filelist.add(new Home("post", 3)); //post url 
     filelist.add(new Home("post", 4)); //become friend with 
     filelist.add(new Home("post", 0)); //post status 

     swipeRefreshLayout = (SwipeRefreshLayout) myFragmentView.findViewById(R.id.swipe_refresh_layout); 
     swipeRefreshLayout.setOnRefreshListener(this); 
     /** 
     * Showing Swipe Refresh animation on activity create 
     * As animation won't start on onCreate, post runnable is used 
     */ 
     swipeRefreshLayout.post(new Runnable() { 
            @Override 
            public void run() { 
             swipeRefreshLayout.setRefreshing(true); 
             //do something 
             swipeRefreshLayout.setRefreshing(false); 
            } 
           } 
     ); 

     myList = (ListView) myFragmentView.findViewById(R.id.list_home); 
     //myList.setAdapter(new HomeAdapter(myContext, filelist)); 
     adapter = new HomeAdapter(myContext, filelist); 
     myList.setOnItemClickListener(this); 

     if(!fromBackStack) { 
      new RemoteDataTask().execute(); 
     } 

     return myFragmentView; 
    } 

    /** 
    * This method is called when swipe refresh is pulled down 
    */ 
    @Override 
    public void onRefresh() { 
     //do something 
     myList.setAdapter(adapter); 
     ArrayList<Home> new_filelist = new ArrayList<>(); 
     new_filelist.add(new Home("Post", 4)); 

     filelist.addAll(0, new_filelist); 
     adapter.notifyDataSetChanged(); 
     swipeRefreshLayout.setRefreshing(false); 
    } 

    @Override 
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
     Home tmp = (Home) parent.getItemAtPosition(position); 
     DetailPostFragment detailPostFragment = new DetailPostFragment(); 
     Bundle args = new Bundle(); 
     switch (tmp.type) { 
      case 0: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 1: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 2: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 3: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 4: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
     } 
    } 

    private class RemoteDataTask extends AsyncTask<String, Void, ArrayList<Home>> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
     } 

     @Override 
     protected ArrayList<Home> doInBackground(String... urls) { 
      try { 
       ArrayList<Home> new_filelist = new ArrayList<Home>(); 
       new_filelist.add(new Home("post", 3)); //post url 
       new_filelist.add(new Home("post", 4)); //become friend with 
       new_filelist.add(new Home("post", 0)); //post status 
       filelist.addAll(new_filelist); 
      } catch (ParseException e) { 
       Log.e("Error", e.getMessage()); 
       e.printStackTrace(); 
      } 
      return filelist; 
     } 

     @Override 
     protected void onPostExecute(ArrayList<Home> organization) { 
      myList.setAdapter(new HomeAdapter(myContext, filelist)); 
      // Create an OnScrollListener 
      myList.setOnScrollListener(new AbsListView.OnScrollListener() { 

       @Override 
       public void onScrollStateChanged(AbsListView view, 
               int scrollState) { // TODO Auto-generated method stub 
        int threshold = 1; 
        int count = myList.getCount(); 

        if (scrollState == SCROLL_STATE_IDLE) { 
         if (myList.getLastVisiblePosition() >= count 
           - threshold) { 
          // Execute LoadMoreDataTask AsyncTask 
          new LoadMoreDataTask().execute(); 
         } 
        } 
       } 

       @Override 
       public void onScroll(AbsListView view, int firstVisibleItem, 
            int visibleItemCount, int totalItemCount) { 
        // TODO Auto-generated method stub 

       } 

      }); 
     } 
    } 

    public class LoadMoreDataTask extends AsyncTask<String, Void, ArrayList<Home>> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
     } 

     @Override 
     protected ArrayList<Home> doInBackground(String... urls) { 
      try { 
       // web service request 
       ArrayList<Home> new_filelist = new ArrayList<Home>(); 
       new_filelist.add(new Home("post", 0)); //post status 
       if(new_filelist != null && new_filelist.size() > 0){ 
        filelist.addAll(new_filelist); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return filelist; 
     } 

     @Override 
     protected void onPostExecute(ArrayList<Home> organization) { 
      int position = myList.getLastVisiblePosition(); 
      adapter = new HomeAdapter(myContext, filelist); 
      myList.setAdapter(adapter); 
      adapter.notifyDataSetChanged(); 
      myList.setSelectionFromTop(position, 0); 
     } 
    } 

} 

Я надеюсь, что кто-то может помочь мне, спасибо.

Обновленный код Это мой код до сих пор, она работает, когда я пытаюсь спасенных пунктов ListView и его адаптер, возможно, это немного сложнее. Если у кого-то есть какая-то идея, это будет оценено по достоинству.

package com.ngapainya.ngapainya.fragment; 
import android.app.Activity; 
import android.graphics.drawable.ColorDrawable; 
import android.net.ParseException; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.widget.SwipeRefreshLayout; 
import android.util.Log; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.AbsListView; 
import android.widget.AdapterView; 
import android.widget.ListView; 

import com.ngapainya.ngapainya.R; 
import com.ngapainya.ngapainya.activity.volunteer.ContainerActivity; 
import com.ngapainya.ngapainya.adapter.HomeAdapter; 
import com.ngapainya.ngapainya.fragment.child.DetailPostFragment; 
import com.ngapainya.ngapainya.model.Home; 

import java.util.ArrayList; 

/** 
* A simple {@link Fragment} subclass. 
*/ 
public class HomeFragment extends Fragment implements AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener{ 
    private FragmentActivity myContext; 
    private View myFragmentView; 
    private ArrayList<Home> filelist; 
    private ListView myList; 
    private HomeAdapter adapter; 
    private SwipeRefreshLayout swipeRefreshLayout; 

    /* 
    * these variables used to restore the listview 
    * when calling the fragment from backstack 
    * */ 
    private boolean fromBackStack = false; 
    private HomeAdapter savedAdapter; 
    private ArrayList<Home> savedFilelist; 

    @Override 
    public void onDestroyView() { 
     super.onDestroyView(); 
     savedAdapter = adapter; 
     savedFilelist = filelist; 
     fromBackStack = true; 
     Log.e("onDestroyView", "onDestroyView"); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     myContext = (FragmentActivity) activity; 
     super.onAttach(activity); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
          Bundle savedInstanceState) { 
     // Inflate the layout for this fragment 
     myFragmentView = inflater.inflate(R.layout.fragment_home, container, false); 

     Log.e("onCreateView", "onCreateView"); 

     swipeRefreshLayout = (SwipeRefreshLayout) myFragmentView.findViewById(R.id.swipe_refresh_layout); 
     swipeRefreshLayout.setOnRefreshListener(this); 
     /** 
     * Showing Swipe Refresh animation on activity create 
     * As animation won't start on onCreate, post runnable is used 
     */ 
     /*swipeRefreshLayout.post(new Runnable() { 
            @Override 
            public void run() { 
             swipeRefreshLayout.setRefreshing(true); 
             //do something 
             swipeRefreshLayout.setRefreshing(false); 
            } 
           } 
     );*/ 

     myList = (ListView) myFragmentView.findViewById(R.id.list_home); 
     //myList.setAdapter(new HomeAdapter(myContext, filelist)); 

     myList.setOnItemClickListener(this); 

     filelist = new ArrayList<Home>(); 
     adapter = new HomeAdapter(myContext, filelist); 

     if(fromBackStack) { 
      filelist = savedFilelist; 
      adapter = savedAdapter; 
     } 

     new RemoteDataTask().execute(); 
     return myFragmentView; 
    } 

    /** 
    * This method is called when swipe refresh is pulled down 
    */ 
    @Override 
    public void onRefresh() { 
     ArrayList<Home> new_filelist = new ArrayList<>(); 
     new_filelist.add(new Home("Post", 4)); 

     filelist.addAll(0, new_filelist); 
     adapter.notifyDataSetChanged(); 
     swipeRefreshLayout.setRefreshing(false); 

     Log.e("onRefresh", "onRefresh"); 
    } 

    /* 
    * This method is called whenever the listview item is clicked 
    * */ 

    @Override 
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 
     Home tmp = (Home) parent.getItemAtPosition(position); 
     DetailPostFragment detailPostFragment = new DetailPostFragment(); 
     Bundle args = new Bundle(); 
     switch (tmp.type) { 
      case 0: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 1: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 2: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 3: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
      case 4: 
       args.putInt("postType", tmp.type); 
       detailPostFragment.setArguments(args); 
       ((ContainerActivity) getActivity()).changeFragment(detailPostFragment, new ColorDrawable(getResources().getColor(R.color.ColorPrimary))); 
       break; 
     } 
    } 

    /* 
    * This method is called in onCreateView method 
    * Used to load data from server and populate them into 
    * the listview 
    * */ 

    private class RemoteDataTask extends AsyncTask<String, Void, ArrayList<Home>> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
     } 

     @Override 
     protected ArrayList<Home> doInBackground(String... urls) { 
      try { 
       ArrayList<Home> new_filelist = new ArrayList<Home>(); 
       //dummy data 
       new_filelist.add(new Home("post", 1)); //post image 
       new_filelist.add(new Home("post", 2)); //post location 
       new_filelist.add(new Home("post", 3)); //post url 
       new_filelist.add(new Home("post", 4)); //become friend with 
       new_filelist.add(new Home("post", 0)); //post status 
       new_filelist.add(new Home("post", 3)); //post url 
       new_filelist.add(new Home("post", 4)); //become friend with 
       new_filelist.add(new Home("post", 0)); //post status 
       filelist.addAll(new_filelist); 
      } catch (ParseException e) { 
       Log.e("Error", e.getMessage()); 
       e.printStackTrace(); 
      } 
      return filelist; 
     } 

     @Override 
     protected void onPostExecute(ArrayList<Home> organization) { 
      myList.setAdapter(adapter); 
      // Create an OnScrollListener 
      myList.setOnScrollListener(new AbsListView.OnScrollListener() { 

       @Override 
       public void onScrollStateChanged(AbsListView view, 
               int scrollState) { // TODO Auto-generated method stub 
        int threshold = 1; 
        int count = myList.getCount(); 

        if (scrollState == SCROLL_STATE_IDLE) { 
         if (myList.getLastVisiblePosition() >= count 
           - threshold) { 
          // Execute LoadMoreDataTask AsyncTask 
          new LoadMoreDataTask().execute(); 
         } 
        } 
       } 

       @Override 
       public void onScroll(AbsListView view, int firstVisibleItem, 
            int visibleItemCount, int totalItemCount) { 
        // TODO Auto-generated method stub 

       } 

      }); 
     } 
    } 

    /* 
    * This method is called when the listview pulled down 
    * it will trigger this method to load more items from server 
    * */ 

    public class LoadMoreDataTask extends AsyncTask<String, Void, ArrayList<Home>> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
     } 

     @Override 
     protected ArrayList<Home> doInBackground(String... urls) { 
      try { 
       // web service request 
       ArrayList<Home> new_filelist = new ArrayList<Home>(); 
       new_filelist.add(new Home("post", 0)); //post status 
       new_filelist.add(new Home("post", 1)); 
       if(new_filelist != null && new_filelist.size() > 0){ 
        filelist.addAll(new_filelist); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      return filelist; 
     } 

     @Override 
     protected void onPostExecute(ArrayList<Home> organization) { 
      int position = myList.getLastVisiblePosition(); 
      //adapter = new HomeAdapter(myContext, filelist); 
      myList.setAdapter(adapter); 
      adapter.notifyDataSetChanged(); 
      myList.setSelectionFromTop(position, 0); 
     } 
    } 

} 

ответ

0

Наконец я понял это ... я не знаю, это ли лучшее решение или нет, но он работает до сих пор для меня. Мне нужен только один метод и несколько переменных, например.

@Override 
public void onDestroyView() { 
    super.onDestroyView(); 
    savedAdapter = adapter; 
    savedFilelist = filelist; 
    fromBackStack = true; 
    Log.e("onDestroyView", "onDestroyView"); 
} 

Спасибо.

+0

Вы должны сохранить состояние (если необходимо) в onSaveInstanceState(), а не в onDestroy(). Что касается вашего адаптера, вам нужно инициализировать его в onCreate() вместо этого, при необходимости заполняя его ранее сохраненным состоянием. Он будет сохранен, когда представление будет уничтожено и создано повторно. Положение прокрутки будет восстановлено автоматически, как только вы установите инициализированный адаптер в ListView. – BladeCoder

+0

@BladeCoder Проблема в том, что мой фрагмент не разрушен, но отсоединяется, поэтому onSaveInstanceState() никогда не вызывается. Если я могу использовать onSaveInstanceState() вместо метода onDestroy(), возможно, это было бы лучшим решением. Есть ли у вас какие-либо идеи сэр, как сделать так называемый onSaveInstanceState в этом случае? –

+0

Вам не нужно, чтобы это вызывалось, если вид фрагмента только что уничтожен повторно созданным. Все ваши переменные экземпляра все еще будут инициализированы при повторном создании представления, поэтому вы можете просто повторно подключить существующий адаптер, который вы инициализировали в onCreate(). – BladeCoder