Android - RecyclerView умножается каждый раз, когда устройство поворачивается
У меня есть альбомная конфигурация для одного из действий моего приложения. Это действие содержит фрагмент, и этот фрагмент содержит одно текстовое представление и одно повторное представление. Каждый раз, когда я переключаюсь между портретным и ландшафтным режимами, просмотрщик-ретранслятор оставляет вид самого себя, как это было до того, как я включил устройство. Это может быть немного трудно понять, что я пытаюсь спросить здесь, поэтому я записал GIF для этого.
https://giphy.com/gifs/3Wv7NAtT8ezP1SQhDu
Это моя деятельность
public class RecipeStepsActivity extends AppCompatActivity {
static Recipe recipe;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe_steps);
if (StepDetailActivity.SDA_TAG.equals(StepDetailActivity.NEGATIVE))
recipe = getIntent().getParcelableExtra("recipe");
Bundle b = new Bundle();
b.putParcelable("recipe", recipe);
ActionBar ab = getSupportActionBar();
if (ab != null)
ab.setTitle(recipe.getName());
RecipeStepsFragment recipeStepsFragment = new RecipeStepsFragment();
recipeStepsFragment.setArguments(b);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.frame_layout_steps, recipeStepsFragment).commit();
}
}
Это мой фрагмент
public class RecipeStepsFragment extends Fragment {
@BindView(R.id.recipe_steps_rv)
RecyclerView recyclerView;
@BindView(R.id.ingredients_tv)
TextView tv_ingredients;
List<Step> steps;
public RecipeStepsFragment(){}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recipe_steps, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.bind(this, view);
List<Ingredients> ingredients;
Recipe recipe = getArguments().getParcelable("recipe");
steps = recipe.getSteps();
initRecyclerView();
ingredients = recipe.getIngredients();
String ingredientsAppended = "INGREDIENTS" + "\n\n";
if (ingredients == null){
ingredientsAppended = "Not Available";
} else {
for (int a = 0 ; a < ingredients.size() ; a++) {
Ingredients i = ingredients.get(a);
ingredientsAppended += String.valueOf(i.getQuantity()) + " " +
i.getMeasure() + " " +
i.getIngredient();
if (a+1 != ingredients.size()){
ingredientsAppended += '\n';
}
}
}
tv_ingredients.setText(ingredientsAppended);
if(savedInstanceState != null){
recyclerView.scrollToPosition(savedInstanceState.getInt("position"));
}
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putInt("position", recyclerView.getVerticalScrollbarPosition());
super.onSaveInstanceState(outState);
}
private void initRecyclerView(){
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL));
RecipeStepsRecyclerAdapter recipeStepsRecyclerAdapter =
new RecipeStepsRecyclerAdapter(steps, new RecipeStepsRecyclerAdapter.ClickListener() {
@Override
public void onItemClick(int clickedItemPosition) {
Intent intentToStepDetail = new Intent(getActivity(), StepDetailActivity.class);
Step step = steps.get(clickedItemPosition);
intentToStepDetail.putExtra("step", step);
startActivity(intentToStepDetail);
}
}, getContext());
recyclerView.setAdapter(recipeStepsRecyclerAdapter);
recipeStepsRecyclerAdapter.notifyDataSetChanged();
}
}
Это мой адаптер
public class RecipeStepsRecyclerAdapter extends RecyclerView.Adapter<RecipeStepsRecyclerAdapter.ViewHolder> {
private List<Step> stepList;
private LayoutInflater mInflater;
final private ClickListener clickListener;
public RecipeStepsRecyclerAdapter(List<Step> stepList, ClickListener clickListener, Context context){
this.stepList = stepList;
this.clickListener = clickListener;
mInflater = LayoutInflater.from(context);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recipe_steps_recyclerview_adapter, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Step step = stepList.get(position);
String stepContent = step.getShortDescription();
holder.listingNumber.setText(String.valueOf(position+1));
holder.stepContent.setText(stepContent);
}
@Override
public int getItemCount() {
return stepList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView listingNumber;
TextView stepContent;
private ViewHolder(View itemView) {
super(itemView);
listingNumber = itemView.findViewById(R.id.list_number_tv);
stepContent = itemView.findViewById(R.id.step_content_tv);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
int clickedPosition = getAdapterPosition();
clickListener.onItemClick(clickedPosition);
}
}
public interface ClickListener{
void onItemClick(int clickedItemPosition);
}
}
Файлы макета, как я уже объяснил выше. Я думаю, ничего особенного, чтобы опубликовать здесь.
Заранее спасибо.
3 ответа
Проблема в том, что вы добавляете новый фрагмент в Activity
каждый раз, когда он создается. Вот вам конец onCreate(...)
:
RecipeStepsFragment recipeStepsFragment = new RecipeStepsFragment();
recipeStepsFragment.setArguments(b);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().add(R.id.frame_layout_steps, recipeStepsFragment).commit();
FragmentManager
сохраняет ссылку на фрагмент, который вы добавляете к нему, даже если хост Activity
уничтожен Таким образом, вы продолжаете добавлять новые экземпляры RecipeStepsFragment
в конечном счете накладывая друг на друга и производя видимое поведение.
Не волнуйтесь, исправление довольно простое: используйте replace(...)
вместо add(...)
:
fm.beginTransaction().replace(R.id.frame_layout_steps, recipeStepsFragment).commit();
PS: Обратите внимание, однако, что замена текущего фрагмента новым каждый раз, когда активность хоста уничтожается, не является хорошей идеей. Вы должны проверить, если savedInstanceState
является null
(что указывает на то, что это не воссозданный Activity
) или если данный фрагмент уже добавлен (определите тег при добавлении фрагмента и попробуйте найти его в onCreate(...)
до замены старого).
Каждый раз, когда вы меняете поворот экрана, ваша деятельность разрушается и воссоздается. Вот почему ваш список пополняется новыми элементами каждый раз, когда вы переключаетесь между своей ориентацией.
Поэтому важно, чтобы вы создавали экземпляры своих объектов только один раз, а не продолжали их воссоздавать каждый раз, когда ваше приложение воссоздается. Который затем добавляет их в свой список.
Вы можете использовать onSaveInstanceState и onRestoreInstanceState.
Если вы хотите, чтобы ваше приложение позволяло изменять ориентацию, применяйте логику, чтобы ваш список не получал новые элементы каждый раз при создании активности.
Поместите атрибут configChanges в вашу деятельность в файле с описанием
<activity android:name=".VideoActivity" android:configChanges="keyboardHidden|orientation|screenSize"/>