为什么在横向到纵向切换后显示空屏幕后从详细活动中回退?

时间:2017-12-28 13:55:35

标签: android android-fragments android-activity android-fragmentactivity android-lifecycle

下面是我正在使用的MainActivity类。代码检查手机是横向还是纵向。如果它是纵向的,它将仅显示主活动中的主要片段(主要片段是main_activity.xml文件中的静态片段)。然后,如果单击“配方”,它将打开具有其自己的片段的详细活动。如果手机处于横向模式,它将并排显示主片段和细节片段。一切都很好,但是当我按照下面的步骤操作时,我会得到一个白色的屏幕,而不是主要的活动:

步骤:

  1. 切换到横向
  2. 切换回肖像
  3. 选择一个项目并等待详细活动打开
  4. 按回来
  5. 此处取代主要活动窗口,我得到一个白色的屏幕
  6. 如果我不切换到横向,只是从肖像模式开始一切都很好。看起来像切换到横向做了导致问题的事情,我无法弄清楚是什么。任何有关正在发生的事情或在哪里寻找的提示都会非常感激。

    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适配器代码中的一行。我的适配器代码如下。在loadInBackground()URL url = new URL(getString(R.string.URL_RecipeJSON));内,我得到 Fragment RecipesFragment {96e9b6a}未附加到活动 例外。我不明白为什么我得到这个例外以及解决这个问题的最佳方法是什么。我是否在正确的片段方法中放置了正确的代码(即OnCreate vs OnActivityCreated vs OnCreateView vs)?

    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) {
    
        }
    }
    

2 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

当您从横向切换到纵向或相反时,Android操作系统会破坏您的活动并重新创建它。这可能会引发你的问题

相关问题