当设备处于飞行模式时,我的应用会崩溃

时间:2018-05-20 08:02:07

标签: java android xml android-fragments

我测试了我的应用程序在飞行模式下设置设备,它崩溃了。

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)

1 个答案:

答案 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);
}