我测试了我的应用程序在飞行模式下设置设备,它崩溃了。
MoviesListFragment.java
package com.example.android.popularmoviesstage_1;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
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.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* A Class that extends Fragment to implement the Movie List structure
* A Fragment represents a behavior or a portion of user interface in a FragmentActivity.
*/
public class MoviesListFragment extends Fragment{
public static ProgressBar mLoadingIndicator;
public static TextView mErrorMessageDisplay;
public static SwipeRefreshLayout mSwipeContainer;
public static PosterAdapter mMoviesAdapter;
private Context mContext;
private MoviesRecyclerView mScrollListener;
private int mPage;
private int mSorting;
private static final int SORTING_POPULAR = 1;
private static final int SORTING_RATED = 2;
private static final String BUNDLE_MOVIES_KEY = "movieList";
private static final String BUNDLE_PAGE_KEY = "currentPage";
private static final String BUNDLE_SORTING_KEY = "currentSorting";
private static final String BUNDLE_ERROR_KEY = "errorShown";
private static final String TAG = MoviesListFragment.class.getSimpleName();
@Override
public void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setHasOptionsMenu(true); //Allowing menu options in the ActionBar
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){
Boolean errorShown = false;
if (savedInstanceState != null){
errorShown = savedInstanceState.getBoolean(BUNDLE_ERROR_KEY);
}
if (savedInstanceState != null && !errorShown){
mPage = savedInstanceState.getInt(BUNDLE_PAGE_KEY);
mSorting = savedInstanceState.getInt(BUNDLE_SORTING_KEY);
} else {
mPage = 1;
mSorting = 1;
}
//inflating the movies in this fragment
View rootView = inflater.inflate(R.layout.movie_list_fragment, container, false);
mContext = getContext();
final int columns = getResources().getInteger(R.integer.grid_columns);
// Laying the movie items in grid formation.
GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, columns, GridLayoutManager.VERTICAL, false);
RecyclerView recyclerView = rootView.findViewById(R.id.rv_posters);
recyclerView.setLayoutManager(gridLayoutManager);
//setting the size for all movie items
recyclerView.setHasFixedSize(true);
mMoviesAdapter = new PosterAdapter();
recyclerView.setAdapter(mMoviesAdapter);
//progress indicator catching movie data from the internet
mLoadingIndicator = rootView.findViewById(R.id.pb_loading_indicator);
mScrollListener = new MoviesRecyclerView(gridLayoutManager, mPage) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Log.d(TAG, "Loading page: " + String.valueOf(page));
mPage = page;
loadCards(mSorting);
}
};
recyclerView.addOnScrollListener(mScrollListener);
//The SwipeRefreshLayout is used whenever the user refresh the contents of a view via a vertical swipe gesture.
mSwipeContainer = rootView.findViewById(R.id.sr_swipe_container);
mSwipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mErrorMessageDisplay.setVisibility(View.INVISIBLE);
clearGridView();
loadCards(mSorting);
}
});
mSwipeContainer.setColorSchemeResources(R.color.colorAccent);
mErrorMessageDisplay = rootView.findViewById(R.id.tv_error_message_display);
if (savedInstanceState != null && !errorShown){
ArrayList<Movie> movieArrayList = savedInstanceState.getParcelableArrayList(BUNDLE_MOVIES_KEY);
mMoviesAdapter.setMoviesData(movieArrayList);
} else {
loadCards(mSorting);
}
return rootView;
}
//onSaveInstanceState() is called before your activity is paused.
// So any info that it needs after it is potentially destroyed can be retrieved from the saved Bundle
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
List<Movie> movieList = mMoviesAdapter.getMoviesData();
if (movieList != null){
ArrayList<Movie> movieArrayList = new ArrayList<>(mMoviesAdapter.getMoviesData());
outState.putParcelableArrayList(BUNDLE_MOVIES_KEY, movieArrayList);
outState.putInt(BUNDLE_PAGE_KEY, mPage);
outState.putInt(BUNDLE_SORTING_KEY, mSorting);
} else {
if (mErrorMessageDisplay.isShown()){
outState.putBoolean(BUNDLE_ERROR_KEY, true);
}
}
}
/**
* A method that invokes the AsyncTask to populate the RecyclerView,
* it's based on the sorting option selected by the user. Default is "popular movies"
*
* @param sorting the way of sorting selected by the user
*/
private void loadCards(int sorting){
if(NetworkUtils.isOnline(mContext)){
String method;
switch (sorting){
case SORTING_POPULAR:
method = NetworkUtils.getMoviesPopular();
break;
case SORTING_RATED:
method = NetworkUtils.getMoviesTopRated();
break;
default:
method = NetworkUtils.getMoviesPopular();
break;
}
String[] posters = new String[]{method, String.valueOf(mPage)};
new FetchMovieTask().execute(posters);
} else {
showErrorMessage(R.string.error_no_connectivity);
if (mSwipeContainer.isRefreshing()) {
mSwipeContainer.setRefreshing(false);
}
}
}
/**
* Reset the GridView properties and adapter
*/
private void clearGridView(){
mScrollListener.resetState();
mPage = 1;
mMoviesAdapter.clear();
}
/**
* Display the specific error message in the TextView
*
* @param messageId the resource id of the error string
*/
public static void showErrorMessage(int messageId){
mErrorMessageDisplay.setText(Resources.getSystem().getText(messageId));
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}
//onCreateOptionsMenu() to specify the options menu for an activity.
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
switch (mSorting) {
case SORTING_POPULAR:
menu.findItem(R.id.sort_popular).setChecked(true);
break;
case SORTING_RATED:
menu.findItem(R.id.sort_rated).setChecked(true);
break;
default:
menu.findItem(R.id.sort_popular).setChecked(true);
break;
}
}
/*
*When the user selects an item from the options menu (including action items in the app bar),
* the system calls our activity's onOptionsItemSelected() method.
* This method passes the MenuItem selected. We can identify the item by calling getItemId(),
* which returns the unique ID for the menu item (defined by the android:id attribute in the menu
* resource or with an integer given to the add() method). We can match this ID against known menu
* items to perform the appropriate action.
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.sort_popular || id == R.id.sort_rated) {
if (!item.isChecked()) {
mSorting = item.getOrder();
item.setChecked(true);
clearGridView();
loadCards(mSorting);
}
return true;
}
return super.onOptionsItemSelected(item);
}
}
MainActivity.java
package com.example.android.popularmoviesstage_1;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
/**
* MainActivity, which is presented to the user when the app is launched.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//MoviesListFragment is used here
}
}
activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.android.popularmoviesstage_1.MainActivity">
<!-- This fragment is used in MainActivity -->
<fragment
android:name="com.example.android.popularmoviesstage_1.MoviesListFragment"
android:id="@+id/f_movie_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/movie_list_fragment" />
</FrameLayout>
movie_list_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/padding_ten"
android:paddingRight="@dimen/padding_ten">
<TextView
android:id="@+id/tv_error_message_display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/padding_sixteen"
android:text="@string/error_message"
android:drawableRight="@android:drawable/stat_notify_error"
android:drawableEnd="@android:drawable/stat_notify_error"
android:drawableTint="@android:color/holo_red_dark"
android:drawablePadding="@dimen/padding_four"
android:textSize="@dimen/movie_detail_text_size"
android:background="@android:color/white"
android:visibility="invisible" />
<ProgressBar
android:id="@+id/pb_loading_indicator"
android:layout_width="@dimen/padding_fourty_two"
android:layout_height="@dimen/padding_fourty_two"
android:layout_gravity="center"
android:indeterminateTint="@android:color/holo_blue_bright"
android:visibility="invisible" />
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sr_swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_posters"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
</FrameLayout>
的strings.xml
<resources>
<string name="app_name">Popular Movies</string>
<string name="sort_popular">Most Popular</string>
<string name="sort_rated">Top Rated</string>
<string name="poster_image_alt">Poster Image</string>
<string name="error_message">An error has occurred. Please try again by swiping down</string>
<string name="error_no_connectivity">Your device is not connected to the Internet.</string>
<string name="error_moviedb_list">Error from the MovieDB Service. Swipe down to try again</string>
<string name="error_movie_poster">Error loading the poster, sorry!</string>
<string name="no_internet_connection">No Internet connection</string>
<string name="button_retry">RETRY</string>
<string name="checkInternetConnection">Check Internet</string>
</resources>
这是错误说明:
FATAL EXCEPTION: main
Process: com.example.android.popularmoviesstage_1, PID: 21294
android.content.res.Resources$NotFoundException: String resource ID #0x7f0d0026
以下是此错误的堆栈跟踪:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.popularmoviesstage_1, PID: 21294
android.content.res.Resources$NotFoundException: String resource ID #0x7f0d0026
at android.content.res.Resources.getText(Resources.java:331)
at com.example.android.popularmoviesstage_1.MoviesListFragment.showErrorMessage(MoviesListFragment.java:185)
at com.example.android.popularmoviesstage_1.MoviesListFragment.loadCards(MoviesListFragment.java:161)
at com.example.android.popularmoviesstage_1.MoviesListFragment.access$300(MoviesListFragment.java:28)
at com.example.android.popularmoviesstage_1.MoviesListFragment$2.onRefresh(MoviesListFragment.java:104)
at android.support.v4.widget.SwipeRefreshLayout$1.onAnimationEnd(SwipeRefreshLayout.java:188)
at android.support.v4.widget.CircleImageView.onAnimationEnd(CircleImageView.java:106)
at android.view.ViewGroup.finishAnimatingView(ViewGroup.java:6278)
at android.view.View.draw(View.java:17027)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.draw(View.java:17086)
at android.view.View.updateDisplayListIfDirty(View.java:16065)
at android.view.View.draw(View.java:16849)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.updateDisplayListIfDirty(View.java:16060)
at android.view.View.draw(View.java:16849)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.updateDisplayListIfDirty(View.java:16060)
at android.view.View.draw(View.java:16849)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.updateDisplayListIfDirty(View.java:16060)
at android.view.View.draw(View.java:16849)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.updateDisplayListIfDirty(View.java:16060)
at android.view.View.draw(View.java:16849)
at android.view.ViewGroup.drawChild(ViewGroup.java:3768)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3554)
at android.view.View.draw(View.java:17086)
at com.android.internal.policy.DecorView.draw(DecorView.java:751)
at android.view.View.updateDisplayListIfDirty(View.java:16065)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:657)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:663)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:771)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2808)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2616)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2223)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1258)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6348)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
at android.view.Choreographer.doCallbacks(Choreographer.java:683)
at android.view.Choreographer.doFrame(Choreographer.java:619)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
答案 0 :(得分:2)
为了在片段中获取String,请使用以下代码
getResources().getString(R.id.error_no_connectivity).
这将为您解决崩溃问题。您没有正确引用strings.xml中的字符串
你的方法应该是(删除静态关键字)
public void showErrorMessage(int messageId){
mErrorMessageDisplay.setText(getResources().getString(messageId));
mErrorMessageDisplay.setVisibility(View.VISIBLE);
}