【问题标题】:Fragment still there (or recreated) after configuration change from landscape to portrait配置从横向更改为纵向后,片段仍然存在(或重新创建)
【发布时间】:2018-07-22 07:37:34
【问题描述】:

tl;博士

在横向平板电脑的主细节流中,将配置更改为纵向模式时:重新创建细节片段(尽管不可见)。我不希望这种情况发生。只有主列表活动可见。

如何防止在平板电脑上将配置从横向更改为纵向时重新创建细节片段/视频?


长版

我的 Android baking app 上有一个奇怪的案例 - 我正在为一门课程做一个项目。

我实现了主/详细流程(Android Studio 模板)。当我处于横向模式时,应用程序的功能与我所能测试的一样。
但是,当我处于纵向模式时(在播放视频时从横向旋转后),我意识到视频继续播放。在我看来,片段是重新创建的;我不知道这是怎么发生的以及为什么会发生。

主活动基本上是一个显示项目列表的回收站视图。第一项是关于成分,其余的是食谱的步骤。
当我单击一个项目(下图示例中的成分)时,片段会加载相应的片段。到目前为止一切都很好。

相关代码在RecipeStepAdapter。由于我们在平板电脑和横向上,因此执行的是 2 窗格模式部分。:

    //Click on item -> display the item
    //2 pane mode uses fragment
    //1 pane mode launches activity
    viewHolder.itemView.setOnClickListener(
            view -> {
                List<Step> steps = mRecipe.getSteps();
                Step step = steps.get(viewHolder.getAdapterPosition());
                if (mTwoPane) {

                    Bundle arguments = new Bundle();
                    arguments.putInt(RecipeStepDetailFragment.step_number_key, step.getStepNo());
                    arguments.putString(RecipeStepDetailFragment.step_description_key, step.getDescription());
                    arguments.putParcelableArrayList(
                            RecipeStepDetailFragment.list_of_ingredients_key,
                            IngredientParcelable.makeParcelable(mRecipe.getIngredients())
                    );
                    arguments.putString(
                            RecipeStepDetailFragment.video_url_key,
                            !TextUtils.isEmpty(step.getVideoURL()) ? step.getVideoURL() : step.getThumbnailURL()
                    );

                    RecipeStepDetailFragment fragment = new RecipeStepDetailFragment();
                    fragment.setArguments(arguments);
                    mParentActivity.getSupportFragmentManager().beginTransaction()
                            .replace(R.id.recipe_step_detail_container, fragment)
                            .commit();

                } else {
                    Context context = view.getContext();
                    Intent intent = new Intent(context, RecipeStepDetailActivity.class);
                    intent.putExtra(RECIPE_ID_KEY, step.getRecipeID());
                    intent.putExtra(RECIPE_STEP_NO_KEY, step.getStepNo());
                    context.startActivity(intent);

                }
            }
    );

现在,当我旋转到纵向时,会在视觉上显示正确的主列表视图。但是,我可以听到视频继续播放。
我相信片段可能只是从保存的实例中重新创建的。虽然不确定,但我仍在了解它的过程中...
到目前为止,我认为RecipeStepListActivity(主列表活动)已被销毁并重新创建以显示纵向模式的视图。
同时,横向模式的细节片段被重新创建,虽然我预计它不会。

主列表活动仅处理回收器视图、适配器和数据检索。我没有理由相信这里有问题。供参考。

package de.shaladi.bakingapp.ui;

import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Toast;

import de.shaladi.bakingapp.R;
import de.shaladi.bakingapp.adapters.RecipeStepAdapter;
import de.shaladi.bakingapp.db.RecipeDatabase;
import de.shaladi.bakingapp.viewmodel.RecipeStepListViewModelFactory;
import de.shaladi.bakingapp.viewmodel.RecipeStepViewModel;

/**
 * An activity representing a list of Instructions. This activity
 * has different presentations for handset and tablet-size devices. On
 * handsets, the activity presents a list of items, which when touched,
 * lead to a {@link RecipeStepDetailActivity} representing
 * item details. On tablets, the activity presents the list of items and
 * item details side-by-side using two vertical panes.
 */
public class RecipeStepsListActivity extends AppCompatActivity {

    private static final String TAG = RecipeStepsListActivity.class.getSimpleName();

    /**
     * Whether or not the activity is in two-pane mode, i.e. running on a tablet
     * device.
     */
    private boolean mTwoPane;

    private int mRecipeId;

    private RecipeStepAdapter mRecipeStepAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recipe_steps_list);

        if (getIntent().hasExtra(MainActivity.RECIPE_ID_KEY)) {

            Toolbar toolbar = findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

            // Show the Up button in the action bar.
            ActionBar actionBar = getSupportActionBar();
            if (actionBar != null) {
                actionBar.setDisplayHomeAsUpEnabled(true);
            }

            if (findViewById(R.id.recipe_step_detail_container) != null) {
                // The detail container view will be present only in the
                // large-screen layouts (res/values-w900dp).
                // If this view is present, then the
                // activity should be in two-pane mode.
                mTwoPane = true;
            }


            mRecipeId = getIntent().getIntExtra(MainActivity.RECIPE_ID_KEY, -1);
            if (mRecipeId == -1)
                throw new IllegalArgumentException("Recipe ID should be > 0.");


            RecipeDatabase db = RecipeDatabase.getsInstance(this);
            RecipeStepListViewModelFactory factory = new RecipeStepListViewModelFactory(db, mRecipeId);
            RecipeStepViewModel viewModel =
                    ViewModelProviders.of(this, factory).get(RecipeStepViewModel.class);
            viewModel.getRecipe().observe(this, recipe -> {
                mRecipeStepAdapter.setRecipe(recipe);
                getSupportActionBar().setTitle(recipe.getName());
            });


            RecyclerView mRecyclerView = findViewById(R.id.recipe_steps_list);
            mRecyclerView.setHasFixedSize(true);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

            mRecipeStepAdapter = new RecipeStepAdapter(
                    this,
                    mTwoPane);
            mRecyclerView.setAdapter(mRecipeStepAdapter);


        } else {
            Log.e(TAG, "Intent does not have an 'extra'. Recipe object cannot be retrieved. Activity ended.");
            Toast.makeText(this,
                    "Intent does not have an 'extra'. Recipe object cannot be retrieved. Activity ended.",
                    Toast.LENGTH_SHORT).show();
            finish();
        }

    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt(MainActivity.RECIPE_ID_KEY, mRecipeId);
        super.onSaveInstanceState(outState);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

}

我希望我清楚地解释了本质。我的问题是:

如何防止在平板电脑上将配置从横向更改为纵向时重新创建细节片段/视频?

【问题讨论】:

    标签: android master-detail


    【解决方案1】:

    我现在确信行为符合设计。要对此进行测试,只需使用 Android Studio 创建一个 Master/Detail 流应用程序,并在 onCreate、onCreateView、onStart、onResume、onPause、onStop 等事件中记录一些输出。

    更好的解决方案不是阻止片段/视频被重新创建或保存在内存中,而是在这种情况下停止播放器。

    所以在我的情况下,如果片段不可见,请确保视频不会自动开始播放。我在onPause/onStop 方法/s 中添加了这个。

        if (!this.isVisible()) {
            Log.d(TAG, "Fragment not visible. mPlayWhenReady set to false");
            mPlayWhenReady = false;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多