我试图让我的微调器在屏幕转动时保存它的位置。我已尝试按照解决方案here,但它不起作用并给我一个nullpointerexception。任何想法如何解决它?
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)
答案 0 :(得分:2)
每当您的方向发生变化,屏幕尺寸也会发生变化, 在AndroidManifest.xml文件中添加以下行,以便在旋转或大小更改时不想重新创建活动
android:configChanges="orientation|screenSize"
这样您的Activity就不会自动重启。有关更多信息,请参阅documentation
<强>机器人:configChanges 强>
列出活动将自行处理的配置更改。在运行时发生配置更改时,默认情况下会关闭并重新启动活动,但声明具有此属性的配置将阻止活动重新启动。相反,活动仍在运行,并调用其onConfigurationChanged()方法。
答案 1 :(得分:1)
如您所知,在方向更改后重新创建整个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));
}
答案 2 :(得分:1)
记住在创建
上保存的实例包中的选定位置if(savedInstanceState != null) {
savedSelection = savedInstanceState.getInt("spinner", 0);
}
并在
之后设置MenuItem item = menu.findItem(R.id.spinnerr);
spinner = (Spinner) MenuItemCompat.getActionView(item);
spinner.setSelection(savedSelection);
答案 3 :(得分:0)
使用最新的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>
的strings.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>