为什么在横向到纵向切换后从细节 activity 返回显示空白屏幕?

Why does pressing back from detail activity after landscape-to-portrait-switch show an empty screen?

下面是我正在使用的 MainActivity class。该代码检查 phone 是横向还是纵向。如果它是纵向的,它只会在主 activity 中显示主片段(主片段是 main_activity.xml 文件中的静态片段)。然后,如果单击 "Recipe",它将打开一个带有自己片段的详细信息 activity。如果 phone 处于横向模式,它将并排显示主要片段和详细片段。一切正常,但是当我按照下面的步骤操作时,我得到的是白屏而不是主屏幕 activity:

程序:

  1. 切换到横向
  2. 切换回纵向
  3. 选择一个项目并等待详情activity打开
  4. 按回
  5. 这里不是主要的 activity window 我得到一个白屏

如果我不切换到横向,而只是从纵向模式开始,一切都很好。似乎切换到横向会导致问题,我无法弄清楚是什么。任何有关正在发生的事情或在哪里看的提示都将不胜感激。

public class MainActivity extends AppCompatActivity implements RecipesFragment.OnRecipeClickListener {

    private String RECIPE_PARCEL_KEY;
    private boolean mTwoPane;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RECIPE_PARCEL_KEY = getString(R.string.ParcelKey_RecipeParcel);
        if (findViewById(R.id.linearLayoutTwoPane) != null) {
            mTwoPane = true;
            if (savedInstanceState == null) {
                RecipeFragment recipeFragment = new RecipeFragment();
                FragmentManager fragmentManager = getSupportFragmentManager();
                fragmentManager.beginTransaction()
                        .add(R.id.recipeFrameForTwoPane, recipeFragment)
                        .commit();
            }
        } else {
            mTwoPane = false;
        }
    }

    @Override
    public void OnRecipeClick(Recipe recipe) {
        if (mTwoPane) {
            RecipeFragment recipeFragment = new RecipeFragment();
            recipeFragment.setRecipe(recipe);
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.recipeFrameForTwoPane, recipeFragment)
                    .commit();
        } else {
            Class destinationClass = DetailActivity.class;
            Intent intentToStartDetailActivity = new Intent(this, destinationClass);
            intentToStartDetailActivity.putExtra(RECIPE_PARCEL_KEY, recipe);
            startActivity(intentToStartDetailActivity);
        }
    }
}

编辑: 在下面添加 RecipeFragment 的代码:

public class RecipeFragment extends Fragment {

    private Recipe mRecipe;
    @BindView(R.id.tv_recipeName) TextView recipeNameTextView;

    public RecipeFragment(){
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.recipe_fragment,container,false);
        ButterKnife.bind(this,view);
        if(mRecipe!=null) {
            recipeNameTextView.setText(mRecipe.getName());
        }else{
            recipeNameTextView.setText(getString(R.string.messageSelectARecipe));
        }
        return view;
    }

    public void setRecipe(Recipe recipe){
        mRecipe = recipe;
    }
}

编辑: 我听从了@mt0s 的建议,为片段和活动创建了不同的背景颜色,最后将问题缩小到我的 recyclerview 适配器代码中的一行。我的适配器代码如下。在 URL url = new URL(getString(R.string.URL_RecipeJSON)); 行的 loadInBackground() 中,我得到一个 Fragment RecipesFragment{96e9b6a} not attached to Activity 异常.我不明白为什么我会收到此异常以及解决此问题的最佳方法是什么。我是否在正确的片段方法中放置了正确的代码(即 OnCreate vs OnActivityCreated vs OnCreateView vs etc)?

public class RecipesFragment extends Fragment
        implements RecipeAdapter.RecipeAdapterOnClickHandler,
        LoaderManager.LoaderCallbacks<ArrayList<Recipe>> {

    @BindView(R.id.rv_recipes) RecyclerView mRecyclerView;
    private RecipeAdapter mRecipeAdapter;
    private static final int LOADER_ID = 1000;
    private static final String TAG = "RecipesFragment";

    private OnRecipeClickListener mOnRecipeClickListener;

    public RecipesFragment(){
    }

    public interface OnRecipeClickListener {
        void OnRecipeClick(Recipe recipe);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.recipes_fragment, container, false);
        ButterKnife.bind(this, view);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setHasFixedSize(true);
        mRecipeAdapter = new RecipeAdapter(this);
        mRecyclerView.setAdapter(mRecipeAdapter);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getLoaderManager().initLoader(LOADER_ID, null, this);
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void OnClick(Recipe recipe) {
        mOnRecipeClickListener.OnRecipeClick(recipe);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try{
            mOnRecipeClickListener = (OnRecipeClickListener) context;
        } catch (ClassCastException e){
            Log.e(TAG, "onAttach: Host activity class must implement OnRecipeClickListener.");
        }
    }

    @Override
    public Loader<ArrayList<Recipe>> onCreateLoader(int i, Bundle bundle) {
        return new AsyncTaskLoader<ArrayList<Recipe>>(getActivity()) {

            @Override
            protected void onStartLoading() {
                super.onStartLoading();
                forceLoad();
            }

            @Override
            public ArrayList<Recipe> loadInBackground() {
                String response;
                ArrayList<Recipe> recipes = null;
                try {
                    URL url = new URL(getString(R.string.URL_RecipeJSON)); //***I get an exception here***
                    response = NetworkUtils.getResponseFromHttpUrl(url, getActivity());
                    recipes = RecipeJsonUtils.getRecipeFromJson(getActivity(), response);
                } catch (Exception e) {
                    Log.e(TAG, "loadInBackground: " + e.getMessage());
                }
                return recipes;
            }
        };
    }

    @Override
    public void onLoadFinished(Loader<ArrayList<Recipe>> loader, ArrayList<Recipe> recipes) {
        mRecipeAdapter.setRecipeData(recipes);
    }

    @Override
    public void onLoaderReset(Loader<ArrayList<Recipe>> loader) {

    }
}

当您从横向切换到纵向或相反时,Android OS 破坏您的 activity 并重新创建它。这可能会引发您的问题

终于找到问题所在和解决办法了。问题是 AsyncTaskLoader 中的 onStartLoading() 匿名 class 中的 RecipesFragment class 每次恢复片段时都会调用 是否包含 Loader是否被调用。这导致了问题。我需要控制何时调用 onStartLoading(),我只希望它被调用 当且仅当正在初始化或重新启动封闭的加载器时 。因此,我销毁了片段的 onPause() 中的加载器并在 onResume() 中重新启动了它。因此,我将以下代码添加到 RecipesFragment class:

@Override
public void onPause() {
    super.onPause();
    getLoaderManager().destroyLoader(LOADER_ID);
}

@Override
public void onResume() {
    super.onResume();
    getLoaderManager().restartLoader(LOADER_ID, null, this);
}

我还从 onCreate() 中删除了 initLoader()。这样,每次恢复(或创建)片段时,都会调用 onStartLoading()。我试过了,它解决了我的问题。