简体   繁体   English

在配置更改时保留片段

[英]Retaining fragment on configuration change

I have PhotosFrgament class hosted by a MainActivity with a tablayout. 我有一个由MainActivity托管的PhotosFrgament类,带有布局。 The PhotoFragment allows a user to select multiple photos from a custom gallery and displays them in a ListView. PhotoFragment允许用户从自定义图库中选择多张照片,并将它们显示在ListView中。 However on screen rotation, the PhotosFragment is cleared. 但是,在屏幕旋转时,将清除PhotosFragment。 According to my understanding, I should use on setRetainInstance(true) but it doesnt seem to work, any ideas? 根据我的理解,我应该在setRetainInstance(true)上使用,但是它似乎不起作用,有什么想法吗?

public class MainActivity extends AppCompatActivity {

private TabLayout tabLayout;
private ViewPager viewPager;
private static int TAB_ITEMS=1;

@Override
protected void onCreate(Bundle savedInstanceState){

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    // Set a Toolbar to replace the ActionBar.
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    setTitle(R.string.photos);

    tabLayout = (TabLayout)findViewById(R.id.tabs);
    viewPager = (ViewPager)findViewById(R.id.viewpager);

    /**
     *Set an Apater for the View Pager
     */
    viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));

    /**
     * Now , this is a workaround ,
     * The setupWithViewPager dose't works without the runnable .
     * Maybe a Support Library Bug .
     */

    tabLayout.post(new Runnable() {
        @Override
        public void run() {
            tabLayout.setupWithViewPager(viewPager);
        }
    });

    //check for parent activity defined in the manifest before
    //displaying caret
    if(NavUtils.getParentActivityName(this) != null)
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);



}//end method onCreate


class MyAdapter extends FragmentPagerAdapter {

    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    /**
     * Return fragment with respect to Position .
     */

    @Override
    public Fragment getItem(int position)
    {
        switch (position){
            case 0 :
                return new Photos();


        }
        return null;
    }

    @Override
    public int getCount() {

        return TAB_ITEMS;

    }

    /**
     * This method returns the title of the tab according to the position.
     */

    @Override
    public CharSequence getPageTitle(int position) {

        switch (position){
            case 0 :
                return "Photos";



        }
        return null;
    }


}//end class MyAdapter


@Override
public boolean onOptionsItemSelected(MenuItem item){

    switch(item.getItemId()){

        case android.R.id.home:
            //if there is a parent activity declared in the manifest
            //then navigate to the parent activity
            if(NavUtils.getParentActivityName(this) != null)
                NavUtils.navigateUpFromSameTask(this);

            return true;
        default:
            return super.onOptionsItemSelected(item);//implement superclass
        //implementation
    }

}//end method onOptionsItemSelected



}//end class MainActivity


public class PhotosFragment extends ListFragment {


private static final int SELECT_MULTIPLE_PHOTOS = 0;//Set Intent Id
public static final String CustomGalleryIntentKey = "ImageArray";//Set  Intent Key Value
private static final String TAG = "PhotosFragment";

private EditText mImagesDescriptionEditText;
private RelativeLayout mImagesDescriptionRelativeLayout;
private ListView mSelectedImagesListView;


@Override
public void onCreate(Bundle savedInstanceState){

    super.onCreate(savedInstanceState);
    setRetainInstance(true);//retain fragment on configuration changes
    setHasOptionsMenu(true);//fragment will be implementing menu call backs
    //on behalf of activity

}//end method onCreate

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


 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup parent
        ,Bundle savedInstanceState){

    View v = inflater.inflate(R.layout.fragment_photos, parent,false);

    mSelectedImagesListView = (ListView)v.findViewById(android.R.id.list);
    mImagesDescriptionRelativeLayout = (RelativeLayout)
            v.findViewById(R.id.photos_descriptionRelativeLayout);
    mImagesDescriptionEditText = (EditText)v.findViewById(R.id.photos_descriptionEditText);
    mImagesDescriptionRelativeLayout.setVisibility(View.INVISIBLE);



    return v;
}//end method onCreateView


@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){

    super.onCreateOptionsMenu(menu,inflater);
    inflater.inflate(R.menu.fragment_photos, menu);
}//end method onCreateOptionsMenu

@Override
public boolean onOptionsItemSelected(MenuItem item){

    switch(item.getItemId()){

        case R.id.menu_item_upload_photo:

            //Start Custom Gallery Activity by passing intent id
            Intent i = new Intent(getActivity(),CustomGalleryActivity.class);
            startActivityForResult(i,SELECT_MULTIPLE_PHOTOS);

            return true;

        default:
            return super.onOptionsItemSelected(item);
    }//end switch
}//end onOptionsItemSelected

 @Override
 public void onActivityResult(int requestCode, int resultCode,
                                Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

   if(resultCode != Activity.RESULT_OK)
       return;

   if(requestCode == SELECT_MULTIPLE_PHOTOS){

       String imagesArray = data.getStringExtra(CustomGalleryIntentKey);//get Intent data

       //Convert string array into List by splitting by ',' and substring after '[' and before ']'
       List<String> selectedImages = Arrays.asList(imagesArray.substring(1, imagesArray.length() - 1).split(", "));
       loadSelectedImagesListView(new ArrayList<String>(selectedImages));

   }
}


private void loadSelectedImagesListView(ArrayList<String> imagesArray){

    try{
        mImagesDescriptionRelativeLayout.setVisibility(View.VISIBLE);

    }catch (Throwable e){
        e.printStackTrace();
    }

    SelectedImagesAdapter adapter = new SelectedImagesAdapter(imagesArray);
    mSelectedImagesListView.setAdapter(adapter);


}

//custom adapter as inner class
private class SelectedImagesAdapter extends ArrayAdapter<String>{

    public SelectedImagesAdapter(ArrayList<String> imagesArray){

        super(getActivity(),0,imagesArray);

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){

        //if we arent given a view inflate one
        //if there's no recycled view passed in inflate one
        if(convertView == null)
            convertView = getActivity()
                    .getLayoutInflater()
                    .inflate(R.layout.list_item_selected_image, null);

        //configure the view for this image
        String imagePath = getItem(position);

        ImageView imageView = (ImageView)convertView.findViewById(R.id.selected_imageImageView);
        Bitmap bm = BitmapFactory.decodeFile(imagePath);

        //get the screen width  at run time
        int screenWidth = DeviceDimensionsHelper.getDisplayWidth(getActivity());

        //load resized bitmap into an ImageView
        imageView.setImageBitmap(BitmapScaler.scaleToFitWidth(bm, screenWidth));

        EditText caption = (EditText)convertView.findViewById(R.id.selected_imageCaption);


        return convertView;//return view object to the list view

    }
}//end private class ImagesAdapter


}//end class PhotosFragment

Whilst you can store your selected items in a Bundle with onSaveInstanceState , they have to implement the Parcelable interface. 虽然您可以使用onSaveInstanceState将选定的项目存储在Bundle中,但它们必须实现Parcelable接口。

If you don't want to be bound by what you retain, consider using a headless fragment. 如果您不想被保留的东西所束缚,请考虑使用无头碎片。

public class RetainedFragment extends Fragment {

    // data object we want to retain
    private MyDataObject data;

    // this method is only called once for this fragment
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }

    public void setData(MyDataObject data) {
        this.data = data;
    }

    public MyDataObject getData() {
        return data;
    }
}

You can find out more here , it explains why the use of headless fragments is preferable to just setting the "configChanges" attribute. 您可以在此处找到更多信息 ,它解释了为什么使用无头片段比仅设置“ configChanges”属性更可取。

PS. PS。 as a general rule of thumb, only use setRetainInstance(true) for fragments that don't display a view! 作为一般经验法则,仅将setRetainInstance(true)用于不显示视图的片段!

Solved the problem. 解决了问题。 I used onSaveInstanceSate, then retrieved the saved bundle in method onCreateView. 我使用了onSaveInstanceSate,然后在onCreateView方法中检索了保存的捆绑软件。

@Override
public void onSaveInstanceState(Bundle savedInstanceState){

    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putStringArrayList(KEY_IMAGE_LIST, mSelectedImages);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent
        ,Bundle savedInstanceState){

    View v = inflater.inflate(R.layout.fragment_photos, parent,false);

    mSelectedImagesListView = (ListView)v.findViewById(android.R.id.list);
    mImagesDescriptionRelativeLayout = (RelativeLayout)
            v.findViewById(R.id.photos_descriptionRelativeLayout);
    mImagesDescriptionEditText = (EditText)v.findViewById(R.id.photos_descriptionEditText);
    mImagesDescriptionRelativeLayout.setVisibility(View.INVISIBLE);

    if(savedInstanceState != null){

        mSelectedImages = savedInstanceState.getStringArrayList(KEY_IMAGE_LIST);
        loadSelectedImagesListView(mSelectedImages);
    }



    return v;
}//end method onCreateView

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM