How do I preserve the state of a selected spinner/

2019-01-24 05:33发布

问题:

I am using a spinner dropdown in my code , in which I have 4 to 5 dynamically populated values, say if I have "apples" set to default and I select "oranges" from the dropdown and rotate my screen to landscape from portrait, it goes back to default "apples" along with the view associated with it.How do I save the state such that when I select "oranges" and rotate to landscape, it populates the selected value/remains in the same selected state and keeps the view intact/populates the view that was selected in the portrait mode corresponding to the selected value. Here's the adapter code I use for the same:

public class MarketsSpinnerAdapter extends CustomRowAdapter<AdapterRow> {


    private List<AdapterRow> mRenderList;

    public MarketsSpinnerAdapter(final Context context, final List<AdapterRow> renderList) {
        super(context);


        mRenderList = new ArrayList<AdapterRow>();
        mRenderList.addAll(renderList);
    }

    @Override
    protected void setEntries(final List<AdapterRow> renderList) {
        mRenderList = renderList;
    }

    @Override
    protected List<AdapterRow> getEntries() {
        return mRenderList;
    }

    @Override
    public View getDropDownView(final int position, final View convertView, final ViewGroup parent) {
        return getEntries().get(position).getDropDownView(mContext, convertView);
    }

}

Corresponding usage in the respective fragment:

 private void populateCategoryRows(final Cursor cursor) {
            mCategories.clear();
            mAllCategories.clear();
            cursor.moveToPosition(-1);
            Map<String, String> categoryParentNames = new HashMap<String, String>();

            int selectedPosition = 0;
            String previousHeader = "";
            String previousAllHeader = "";

            while (cursor.moveToNext()) {
                final int categoryLevel = cursor.getInt(cursor.getColumnIndex(MarketsCategory.Columns.LEVEL));
                final String categoryName = cursor.getString(cursor.getColumnIndex(MarketsCategory.Columns.NAME));
                final String categoryDisplayName = cursor.getString(cursor.getColumnIndex(MarketsCategory.Columns.DISPLAY_NAME));

                if (categoryLevel == 1) {
                    categoryParentNames.put(categoryName, categoryDisplayName);
                }
            }

            cursor.moveToPosition(-1);
            while (cursor.moveToNext()) {
                final int categoryLevel = cursor.getInt(cursor.getColumnIndex(MarketsCategory.Columns.LEVEL));
                final boolean categoryIsDefault = cursor.getInt(cursor.getColumnIndex(MarketsCategory.Columns.IS_DEFAULT)) == 1;
                final boolean categoryIsSelected = cursor.getInt(cursor.getColumnIndex(MarketsCategory.Columns.IS_SELECTED)) == 1;
                final String categoryParent = cursor.getString(cursor.getColumnIndex(MarketsCategory.Columns.PARENT));
                final String categoryName = cursor.getString(cursor.getColumnIndex(MarketsCategory.Columns.NAME));
                final String categoryDisplayName = cursor.getString(cursor.getColumnIndex(MarketsCategory.Columns.DISPLAY_NAME));


                if (categoryLevel == 2 ) {
                    String categoryParentDisplayName = categoryParentNames.get(categoryParent);
                        if (!categoryParent.equals(previousHeader)) {
                            if (categoryIsSelected) {

                                mCategories.add(new CategoryHeader(categoryParentDisplayName));
                                previousHeader = categoryParent;
                            }
                        }

                        if (!categoryParent.equals(previousAllHeader)) {
                            mAllCategories.add(new CategoryHeader(categoryParentDisplayName));
                            previousAllHeader = categoryParent;
                        }

                        if (categoryIsSelected) {
                            mCategories.add(new SpinnerMarketCategoryRow(categoryName, categoryDisplayName, categoryParent));
                        }
                        mAllCategories.add(new MarketsCategoryCheckableRow(categoryName, categoryDisplayName, categoryIsSelected, categoryIsDefault));

                        if(categoryIsDefault){
                            selectedPosition = mCategories.size()-1;
                        }
                }
            }

            mSpinnerAdapter = new MarketsSpinnerAdapter(Application.getAppContext(), mCategories);
            headerView.setSpinnerAdapter(mSpinnerAdapter);
            headerView.setSpinnerSelectedItemPosition(selectedPosition);
        }
        if (selectedItem instanceof SpinnerMarketCategoryRow) {
            selectedCategory = (SpinnerMarketCategoryRow) mSpinnerAdapter.getItem(position);
        } else {
            if (mSpinnerAdapter.getCount() - 1 >= position + 1) {
                selectedCategory = (SpinnerMarketCategoryRow) mSpinnerAdapter.getItem(position + 1);
            } else {
                selectedCategory = (SpinnerMarketCategoryRow) mSpinnerAdapter.getItem(position - 1);
            }
        }

        final MarketsFragment parentFragment = (MarketsFragment) getParentFragment();
        parentFragment.onCategorySelected(selectedCategory.getCategoryName(), selectedCategory.getCategoryParentName());
    }
@Override
    public void showResults(final Uri uri) {
        LayoutUtils.showResults(getView(), headerView.getSpinnerId());
        headerView.setVisibility(View.VISIBLE);
    }

    @Override
    public void showNoResults(final Uri uri) {
        final MarketsFragment parentFragment = (MarketsFragment) getParentFragment();
        parentFragment.hideSpinner();
        //LayoutUtils.showNoResult(getView(), headerView.getSpinnerId());
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        headerView.setSelected(false);
    }
    @Override
    public void onNothingSelected(IcsAdapterView<?> parent) {
    }

Any ideas?

Thanks!

回答1:

You can do this like...

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("yourSpinner", yourSpinner.getSelectedItemPosition());
    // do this for each or your Spinner
    // You might consider using Bundle.putStringArray() instead
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // initialize all your visual fields        
    if (savedInstanceState != null) {
        yourSpinner.setSelection(savedInstanceState.getInt("yourSpinner", 0));
        // do this for each of your text views
    }
}

Hope this helps



回答2:

If the configuration of the device (as defined by the Resources.Configuration class) changes, then anything displaying a user interface will need to update to match that configuration and therefor your Activity Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal Activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate.

If the activity had been in the foreground or visible to the user, once onDestroy() is called in that instance then a new instance of the activity will be created, with whatever savedInstanceState the previous instance had generated from onSaveInstanceState(Bundle).

This is done because any application resource, including layout files, can change based on any configuration value. In some special cases(Just like your, if i am getting right, if you are having only spinner/dropdown on current UI & you need not to undergo complete Activity life cycle), you may want to bypass restarting of your activity based on one or more types of configuration changes. This is done with the android:configChanges attribute in its manifest and/or you may also use onSaveInstanceState(Bundle) which is caller when activity is destroyed and recreated from the begening.

You simply have two way to resolve this problem_

1_

    1. Add android:configChanges="orientation" in Manifest file of your Activity tag.
 <?xml version="1.0" encoding="utf-8"?>
 <manifest ...
 >
 <application ...
   >      
    <activity
        android:name="SpinnerActivity"
        android:configChanges="orientation" >
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
 </application>

 </manifest>
  • 2, Override onConfigurationChanged, which is called by the system when the device configuration changes while your activity is running.
 @Override
 public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    int orientation = newConfig.orientation;

    switch (orientation) {
    case Configuration.ORIENTATION_LANDSCAPE:
        // do what you want when user is in LANDSCAPE
        break;

    case Configuration.ORIENTATION_PORTRAIT:
        // do what you want when user is in PORTRAIT
        break;
    }

}

2_

Use the put methods to store values in onSaveInstanceState():

protected void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    //Put your spinner values to restore later...
    savedInstanceState.putLong("yourSpinnerValKey", yourSpinner.getSelectedItemPosition());
}

And restore the values in onCreate():

public void onCreate(Bundle savedInstanceState) {
    if (savedInstanceState!= null) {
     //get your values to restore...
        value = savedInstanceState.getLong("param");
    }
}

This will surely solves your problem and it will not refresh your spinner when screen orientation changed. I hope this will help you and all! :)