【问题标题】:Spinner not saving selected item on rotation [duplicate]微调器未在旋转时保存所选项目[重复]
【发布时间】:2018-04-03 00:30:10
【问题描述】:

我试图让我的微调器在屏幕转动时保存其位置。我已经尝试遵循解决方案here,但是它不起作用并给了我一个空指针异常。任何想法如何解决它?

package tk.talcharnes.popularmovies;

import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.Spinner;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * A placeholder fragment containing a simple view.
 */
public class PostersFragment extends Fragment {
    private static List<MovieModel> movieModelList;
    private static int movieModelListLength;
    GridView gridView;
    ImageAdapter adapter;
    Spinner spinner;
    private String sort_method;
    public PostersFragment() {
        //sort_method = "popularity.desc";
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_main, container, false);

            updatePosters();
        // should find gridview on the view which you are creating
        gridView = (GridView) view.findViewById(R.id.gridview);



         DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        int width = (int) (displayMetrics.widthPixels / displayMetrics.density);
//
//        //For Tabs
////        boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
////        width = isLandscape ? (width / 2) : width;
//        int numcolumns =(int) (width/(185));
////
////        float dpHeight = displayMetrics.heightPixels / displayMetrics.density;
////        float dpWidth = displayMetrics.widthPixels / displayMetrics.density;
////        int numcolumns = (int)((185*dp)/dpWidth);
//        gridView.setNumColumns(numcolumns);
        if (getResources().getConfiguration().orientation
                == 1) {
            gridView.setNumColumns(2);


        } else if ( getResources().getConfiguration().orientation
                == 2) {
            gridView.setNumColumns(3);

        }

        adapter = new ImageAdapter(getContext());
        gridView.setAdapter(adapter);
        updatePosters();
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View v,
                                    int position, long id) {
                Toast.makeText(getContext(), "You clicked " + movieModelList.get(position).getTitle(),
                        Toast.LENGTH_SHORT).show();
                MovieModel movieModel = movieModelList.get(position);
                Intent intent = new Intent(getActivity(), MovieDetails.class);
                intent.putExtra("Movie_number", position);
                startActivity(intent);

            }
        });
        return view;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("spinner", spinner.getSelectedItemPosition());
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);

        if(savedInstanceState != null) {
            spinner.setSelection(savedInstanceState.getInt("spinner", 0));
        }
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        //commented out until a settings menu is implemented
      //  super.onCreateOptionsMenu(menu, inflater);
      //  getActivity().getMenuInflater().inflate(R.menu.menu_main, menu);
        inflater.inflate(R.menu.menu_refresh, menu);


        MenuItem item = menu.findItem(R.id.spinnerr);
         spinner = (Spinner) MenuItemCompat.getActionView(item);


        String[] sortingCriteria = {"Popular", "Highest Rated"};
        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(getContext(), R.layout.spinner, sortingCriteria);
        spinner.setAdapter(spinnerAdapter);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
                if(position == 0){
                    sort_method = "popularity.desc";
                    updatePosters();
                }
                else if (position == 1){
                    sort_method = "vote_average.desc";
                    updatePosters();
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parentView) {
                // does nothing
            }

        });

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        int id = item.getItemId();

        //noinspection SimplifiableIfStatement

        if (id == R.id.action_refresh) {
            Toast.makeText(getActivity(), "Refreshing",
                    Toast.LENGTH_SHORT).show();

           updatePosters();
            gridView.setAdapter(adapter);
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    public void updatePosters(){
        FetchPostersTask updatePosters = new FetchPostersTask();
        updatePosters.execute();
    }









    //Get movie posters and data
    public class FetchPostersTask extends AsyncTask<Void,Void,Void> {
        private final String LOG_TAG = FetchPostersTask.class.getSimpleName();
        //will contain raw Json data
        String posterJsonString = null;

        public Void parseMovieJson()
                throws JSONException{
            JSONObject jsonParentObject = new JSONObject(posterJsonString);
            JSONArray movieJSonArray = jsonParentObject.getJSONArray("results");

            movieModelList = new ArrayList<>();
            for(int i = 0; i < movieJSonArray.length(); i++){
                JSONObject movieJsonObject = movieJSonArray.getJSONObject(i);
                MovieModel movieModel = new MovieModel();
                movieModel.setTitle(movieJsonObject.getString("title"));
                movieModel.setOverview(movieJsonObject.getString("overview"));
                movieModel.setPoster_path(movieJsonObject.getString("poster_path"));
                movieModel.setRelease_date(movieJsonObject.getString("release_date"));
                movieModel.setVote_average(movieJsonObject.getString("vote_average"));
                movieModelListLength++;

                movieModelList.add(movieModel);
            }
            return null;
        }

        @Override
        protected Void doInBackground(Void ...params) {

            HttpURLConnection urlConnection = null;
            BufferedReader reader = null;

            //will contain raw Json data
            try{

                //open connection to api

                final String BASE_URL = "https://api.themoviedb.org/3/discover/movie?";
                final String SORT_PARAM ="sort_by";



                Uri builtUri = Uri.parse(BASE_URL).buildUpon()
                        .appendQueryParameter(SORT_PARAM, sort_method)
                        .appendQueryParameter("api_key", BuildConfig.MOVIE_DB_API_KEY).build();

                URL url = new URL(builtUri.toString());
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();

                //read input into string
                InputStream inputStream = urlConnection.getInputStream();
                StringBuffer buffer = new StringBuffer();
                if(inputStream == null){
                    //nothing else to do in this case
                    return null;
                }
                reader = new BufferedReader(new InputStreamReader(inputStream));
                String line;
                while((line = reader.readLine())!= null){
                    buffer.append(line + "\n");
                }

                if(buffer.length()==0){
                    //nothing here, don't parse
                    return null;
                }

                posterJsonString = buffer.toString();
            }
            catch(MalformedURLException e){
                e.printStackTrace();
            }
            catch(IOException e){
                Log.e(LOG_TAG, "Error", e);
                return null;
            }
            finally {
                if(urlConnection != null){
                    urlConnection.disconnect();
                }
                if(reader != null){
                    try{
                        reader.close();

                    }
                    catch (final IOException e){
                        Log.e(LOG_TAG,"Error closing stream", e);
                    }
                }
            }
            try{
                parseMovieJson();;
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);

            String[] asc = new String[movieModelList.size()];
            for(int i = 0; i < asc.length; i++){
                asc[i]=(getMovieModelList().get(i).getPoster_path());

            }
            adapter.setImageArray(asc);
            adapter.notifyDataSetChanged();
        }
    }
    public static List<MovieModel> getMovieModelList(){
        return movieModelList;
    }
    public static int getMovieModelListLength(){
        return movieModelListLength;
    }

}

这里是错误代码:

FATAL EXCEPTION: main
                                                                             Process: tk.talcharnes.popularmovies, PID: 16847
                                                                             java.lang.RuntimeException: Unable to start activity ComponentInfo{tk.talcharnes.popularmovies/tk.talcharnes.popularmovies.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Spinner.setSelection(int)' on a null object reference
                                                                                 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2306)
                                                                                 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2366)
                                                                                 at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3945)
                                                                                 at android.app.ActivityThread.access$900(ActivityThread.java:149)
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1290)
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                 at android.os.Looper.loop(Looper.java:135)
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5290)
                                                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                                                 at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
                                                                              Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Spinner.setSelection(int)' on a null object reference
                                                                                 at tk.talcharnes.popularmovies.PostersFragment.onCreate(PostersFragment.java:115)
                                                                                 at android.support.v4.app.Fragment.performCreate(Fragment.java:1939)
                                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1029)
                                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1248)
                                                                                 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1230)
                                                                                 at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2037)
                                                                                 at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:154)
                                                                                 at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:289)
                                                                                 at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:61)
                                                                                 at tk.talcharnes.popularmovies.MainActivity.onCreate(MainActivity.java:13)
                                                                                 at android.app.Activity.performCreate(Activity.java:6020)
                                                                                 at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
                                                                                 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2259)
                                                                                 at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2366) 
                                                                                 at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3945) 
                                                                                 at android.app.ActivityThread.access$900(ActivityThread.java:149) 
                                                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1290) 
                                                                                 at android.os.Handler.dispatchMessage(Handler.java:102) 
                                                                                 at android.os.Looper.loop(Looper.java:135) 
                                                                                 at android.app.ActivityThread.main(ActivityThread.java:5290) 
                                                                                 at java.lang.reflect.Method.invoke(Native Method) 
                                                                                 at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908) 
                                                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703) 

【问题讨论】:

  • 当设备改变其方向时,活动正在重新创建,这就是片段丢失状态的原因。在加载片段的活动中使用这些标志。 android:configChanges="keyboardHidden|orientation|screenSize"

标签: java android spinner


【解决方案1】:

每当您的方向发生变化时,您的屏幕尺寸也会发生变化, 在您不想在旋转或大小更改时重新创建的活动中的 AndroidManifest.xml 文件中添加以下行

android:configChanges="orientation|screenSize"

这样您的 Activity 不会自动重新启动。请参阅documentation 了解更多信息

android:configChanges

列出活动将自行处理的配置更改。当运行时发生配置更改时,默认情况下会关闭并重新启动 Activity,但使用该属性声明配置会阻止 Activity 重新启动。相反,活动保持运行并调用其 onConfigurationChanged() 方法。

【讨论】:

  • 这是否只允许像风景这样的一种模式?或者这究竟是如何工作的?
  • 更新了我的答案...请检查
  • 这就像OP在问为什么奶牛不产奶,而您是在建议不要驯服奶牛。没有冒犯的兄弟。这也是一个更好的主意。
【解决方案2】:

如您所知,整个Activity 会在方向更改后重新创建。您已经在onCreate 方法中编写了代码,但当时spinner 尚未初始化。

那么你现在可以做的是

创建一个具有 Bundle 数据类型的变量并将其设为全局变量,并将savedInstanceState 保存到该变量

if(savedInstanceState != null) {
            this.myBundle = savedInstanceState;
    }

然后在onCreateOptionsMenu 内部检查this.myBundle 是否为空,然后再调用spinner.setSelection。你的代码看起来像这样,在spinner.setAdapter(spinnerAdapter);语句之后写下这行代码。

 MenuItem item = menu.findItem(R.id.spinnerr);
 spinner = (Spinner) MenuItemCompat.getActionView(item);

 //rest of your codes

spinner.setAdapter(spinnerAdapter);

if(this.myBundle != null){
 spinner.setSelection(myBundle.getInt("spinner", 0));
}

【讨论】:

  • 谢谢!这有助于旋转!虽然我只是注意到当我按下操作栏中的向上按钮时,它会在不保存的地方出现同样的问题。当我按下手机上的(物理)后退按钮时,虽然它确实保存了微调器的位置。有什么想法吗?
  • savedInstanceState 每次正常时都会被调用。如果您想防止这种情况发生,您可以覆盖 onpause 并清除捆绑包。
  • 我确实希望它保存。我的意思是当我按下菜单栏上的后退按钮时,我希望它也保存我的位置并转到该位置。
  • 然后执行相同的覆盖 onpause 并将 int 保存到 myBundle...如果提出问题,请发表评论...目前我正在休假,明天我会赶上这个...
【解决方案3】:

在创建时记住从保存的实例包中选择的位置

if(savedInstanceState != null) {
    savedSelection = savedInstanceState.getInt("spinner", 0);
}

然后设置

MenuItem item = menu.findItem(R.id.spinnerr);
spinner = (Spinner) MenuItemCompat.getActionView(item);
spinner.setSelection(savedSelection);

【讨论】:

    【解决方案4】:

    使用目前最新的 api,在一个活动中,它已经在旋转时保持微调器的选定项目,但不是在片段中。这是一个在屏幕旋转时将微调器的选定项持久保存在片段上的示例。

    MainActivity.kt

    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
    
            if (savedInstanceState == null) {
                val frag = SpinnerFragment()
                supportFragmentManager
                        .beginTransaction()
                        .replace(R.id.fl_container, frag)
                        .commit()
            }
    
        }
    
    }
    

    SpinnerFragment.kt

    class SpinnerFragment : Fragment(), AdapterView.OnItemSelectedListener {
    
            override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
                return inflater.inflate(R.layout.fragment_spinner, container, false)
            }
    
            override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
                super.onViewCreated(view, savedInstanceState)
    
    
                val adapter = ArrayAdapter.createFromResource(activity, R.array.planets_array, android.R.layout.simple_spinner_item)
                adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                planets_spinner.adapter = adapter
                planets_spinner.onItemSelectedListener = this
    
                var selectedIndex = 0
                if (savedInstanceState != null) {
                    selectedIndex = savedInstanceState.getInt("planets_spinner", 0)
                }
                planets_spinner.setSelection(selectedIndex)
            }
    
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) {
                // An item was selected. You can retrieve the selected item using
                // parent.getItemAtPosition(pos)
            }
    
            override fun onNothingSelected(parent: AdapterView<*>?) {
                // Another interface callback
            }
    
    
            override fun onSaveInstanceState(outState: Bundle?) {
                outState?.putInt("planets_spinner", planets_spinner.getSelectedItemPosition());
                super.onSaveInstanceState(outState)
    
            }
        }
    

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.myapplication.MainActivity">
        <FrameLayout
            android:id="@+id/fl_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </android.support.constraint.ConstraintLayout>
    

    fragment_spinner.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.myapplication.MainActivity">
    
        <Spinner
            android:id="@+id/planets_spinner"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    
    
    </android.support.constraint.ConstraintLayout>
    

    字符串.xml

    <resources>
        <string name="app_name">My Application</string>
    
    
        <string-array name="planets_array">
            <item>Mercury</item>
            <item>Venus</item>
            <item>Earth</item>
            <item>Mars</item>
            <item>Jupiter</item>
            <item>Saturn</item>
            <item>Uranus</item>
            <item>Neptune</item>
        </string-array>
    </resources>
    

    【讨论】:

    • 我在看为什么微调器的位置保留在活动中而不是片段中,您有参考文档吗?
    猜你喜欢
    • 2012-07-03
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多