The question of the life cycle of an activity ( activity ) or a fragment ( fragment ) of an android application is extremely important for a practicing android player (android developer). Why? Because the order of executing callbacks of all methods related to the state of the life cycle ( onCreate () , onStart () , etc.) is rigidly defined and its incorrect use will lead to the application being disabled. What does the life cycle? - asks attentive habrochityvatel. After all, the title, it seems, is not about him? The answer is: there is something in common between the life cycle of the activity and the operation of the RecyclerView - it is the HARD ORDER of executing callback methods when using this widget, and, therefore, the need to IT IS RIGHT .
If this is not done, the lists can behave in a very mysterious way.
For example. There is such a list adapter with a standard minimum completion:
public class RvCustomAdapter extends RecyclerView.Adapter<RvCustomAdapter.CustomViewHolder> { private final Frag1 frag; private final LayoutInflater lInflater; private ArrayList<JSONDataSet> dataSet; ... ... ... public RvCustomAdapter(final Frag1 fragment) { this.frag = fragment; this.lInflater = (LayoutInflater) fragment.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.dataSet = new ArrayList<>(); } ... ... ... @Override public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // View view = lInflater.inflate(R.layout.recycler_view_data_item, parent, false); /** * * (size, margins, paddings .) */ RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams(); params.height = RecyclerView.LayoutParams.WRAP_CONTENT; view.setLayoutParams(params); return new CustomViewHolder(view); } // view ( layout manager-) @Override public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) { holder.showData(position); } @Override public int getItemCount() { return dataSet.size(); } /** * view holder- * * */ class CustomViewHolder extends RecyclerView.ViewHolder { ... ... ... @BindView(R.id.ll_Data) LinearLayout ll_Data; @BindView(R.id.cb_Data) CheckBox cb_Data; ... ... ... private JSONDataSet cur; CustomViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } /** * , * . */ ... ... ... }
In the code of the onBindViewHolder () method of the adapter of our list, whose elements contain a check box ( CheckBox ), there is a call to the handler method ( holder 'a), in which data from the collection connected to the adapter is read and set on its basis by the check box - the state, as well as the necessary listeners are connected to various interface elements:
')
void showData(final int position) { cur = dataSet.get(position); cb_Data.setChecked(cur.isChecked()); ... ... ... cb_Data.setOnCheckedChangeListener(cb_DataOnCheckedChangeListener); ll_Data.setOnClickListener(ll_DataOnClickListener); } private OnClickListener ll_DataOnClickListener = new OnClickListener() { @Override public void onClick(View view) { cur.setChecked(!cur.isChecked()); cb_Data.setChecked(cur.isChecked()); } }; private OnCheckedChangeListener cb_DataOnCheckedChangeListener = new OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { cur.setChecked(checked); compoundButton.setChecked(checked); setItemsColor(checked); if (checked) { if (...) { (frag).addSelectedItemsCounter(cur); } else { cur.setChecked(!checked); compoundButton.setChecked(!checked); setItemsColor(!checked); if (...) { createPrimaryDialog(); } else { createSecondaryDialog(); } } } else { (frag).remSelectedItemsCounter(cur); } } };
Listeners, when setting a flag and fulfilling a certain condition, change the data in the collection, and if it is not fulfilled, they display either one or another dialog box.
It turns out like this:
In Figure-1 - the list is generated. In Figure-2 - Checked list item. In Figure 3, a dialogue informs about the violation of the condition when the next element is marked.
To get the result with Pic-1 list layout manager ( LayoutManager ), the following order of the required functions is performed:
Everything is great! If not for "But." Rather BUT!
When scrolling through a long list containing at least a couple of dozen positions, we will receive a message from Figure-3 without any other actions.
The reason is that when writing the adapter code, WE DIDN'T LEARN ORDER THE PERFORMANCE OF THE callback functions listed here and here when scrolling. And he is:
But that is not all. With the “default” settings of the layout manager, each disconnected from the window list item does not long remain in the queue for quick access. As soon as there are 2 of them there, they are moved by the manager to the queue of reclaimed instances, which is marked by a call to the Rv_Adapter.onViewRecycled () method for each recycled list item and vice versa.
Therefore, Algorithm 3 actually looks like this:
// : - true, - false: bool direction; if(direction){ /** * * * ( directDetachedViews) */ Rv_Adapter.onViewDetachedFromWindow(holder); /** * * , max */ if(directDetachedViews.size() > max) { /** * (holder) * * * ( directRecycleredHolders) */ Rv_Adapter.onViewRecycled(holder); } /** * * (visiblePos) , */ if(visiblePos < Rv_Adapter.getItemCount()) { /** * * ( reverseDetachedViews) * (itemView), * ( visiblePos), */ if(reverseDetachedViews.content(itemView)){ /** * * ( reverseRecycleredHolders) * holder, * , visiblePos, */ Rv_Adapter.onCreateViewHolder(itemView) -> { holder = CustomViewHolder(itemView); }; } else { /** * - * (reverseRecycleredHolders) */ holder = reverseRecycleredHolders.getHolder(visiblePos); } /** * * */ Rv_Adapter.onBindViewHolder(holder, visiblePos); } else { /** * - * (reverseDetachedViews) */ holder = reverseDetachedViews.getHolder(visiblePos) } // Rv_Adapter.onViewAttachedToWindow(holder); } else { ... ... ... ... ... }
From the above Algorithm 3 ', it can be seen that if the list is scrolled by more than max, the number of positions will be re-created in it, for which the Rv_Adapter.onBindViewHolder (holder, visiblePos) method will be used, which will repeat the user's actions.
In order to avoid repetition of operations in the onBindViewHolder method (holder, visiblePos) when scrolling a list by a number of positions greater than max, you need:
For example:
@Override public void onViewRecycled(@NonNull CustomViewHolder holder) { super.onViewRecycled(holder); holder.cur.setRecycled(true); } @Override public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) { if (!holder.cur.isRecycled()){ ... ... ... } } @Override public void onViewAttachedToWindow(@NonNull CustomViewHolder holder) { super.onViewAttachedToWindow(holder); holder.cur.setRecycled(false); }
Source: https://habr.com/ru/post/430402/
All Articles