Reputation: 2506
I have ViewPager with 200+ tabs. Every tab includes recyclerview with dynamically loading data via retrofit2. Data are loading after every onTabSelected()
action.
But because of viewpager loading position-1 (if any), position, position+1 (if any)
I am getting 2-3 tabs with identical data.
The question is - how can I load only one fragment that is currently selected without neighbor positions?
I've thought that BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
in my FragmentPagerAdapter
will solve my issue by simply passing it to the constructor:
public Adapter_programmes(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_some = new Fragment_Some();
}
but nothing has changed.
UPD: I think I've found solution here: ViewPager offscreen page limit
But I can not understand it: load your grid with placeholder images, and do not load the real images until the page is changed.
**UPD2: ** setOffscreenPageLimit(1) did not solving my issue.
My code:
Fragment:
public static Fragment_some newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
Fragment_some fragment = new Fragment_some();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
}
arrayNames.clear();
arrayTimes.clear();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mContext=context;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "");
//creating fragment
rootView = inflater.inflate(R.layout.content_list, container, false);
loadProgrammes(CID); //doing retrofit query for data, using argument which I've got from onTabSelected by SharedPreferences
//data loaded succecfully
Handler handler = new Handler();
handler.postDelayed(() -> {
adapterItem = new Adapter_programme_item(mContext, arrayTimes, arrayNames);
RecyclerView RV = rootView.findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(mContext);
RV.setLayoutManager(layoutManager);
RV.setAdapter(adapterItem);
}, 3000); //3 seconds waiting
return rootView;
}
FragmentPagerAdapter:
public Adapter_programmes(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_some = new Fragment_some();
}
@Override public int getCount() {
return PAGE_COUNT;
}
@Override public Fragment getItem(int position) {
return fragment_some.newInstance(position + 1);
}
@Override public CharSequence getPageTitle(int position) {
return tabTitles[position];
}
public void updateTitleData(String[] titles) {
...
notifyDataSetChanged();
}
MainActivity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = new Adapter_programmes(getSupportFragmentManager(), MainActivity.this);
ViewPager viewPager = findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
loaderFromURL(); //getting tab titles via retrofit
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
Log.d(TAG, "onTabSelected");
String mCID = listm3u.get(tab.getPosition()).getItemCID();
AppPreferences.setCurrentCID(MainActivity.this, mCID);
String iconURL = listm3u.get(tab.getPosition()).getItemIcon();
ImageView IVChanelLogo = findViewById(R.id.IVChanelLogo);
Picasso.with(MainActivity.this).load(iconURL).into(IVChanelLogo);
}
});
}
Upvotes: 1
Views: 120
Reputation: 10222
Because you are populating the recyclerview in onCreateView
of the Fragment changing to BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
will have no affect.
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
instead of bring the current Fragment +/- the OffscreenPageLimit (which defaults to 1) to "Resumed" state it brings only the current Fragment to "Resumed" state and any other Fragment to "Started" state in the Fragment Lifecycle.
As "Started" is past onCreateView
your recyclerviews are being populated too early.
Solution is in the Fragment's onCreateView
create the recyclerview adapter with no data in it, find the recyclerView, set it's layoutmanger and adapter, etc.
Then in the Fragment's onResume
method, get your data for the recyclerView and update the recyclerview adapter with this new data, then notify the RecyclerView that it data has changed.
You can then remove the onTabSelected
stuff
There is not enough example code to give a working example BUT below is an example Fragment that shows the updating of textview2
with the current time when "Resumed" compared to textview1
which is set when it is brought to "Started" state(You would create 3 copies of this Fragment in a Viewpager with BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
set)
package com.test.viewpager;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class TextFragment extends Fragment {
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private int mParam1;
private View view;
public TextFragment() {
// Required empty public constructor
}
public static TextFragment newInstance(int param1) {
TextFragment fragment = new TextFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
fragment.setArguments(args);
Log.d("Frag", "newInstance");
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getInt(ARG_PARAM1);
}
Log.d("Frag", "onCreate");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.d("Frag", "onCreateView:" + mParam1);
view = inflater.inflate(R.layout.fragment_text, container, false);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
Log.d("Frag", "onViewCreated:" + mParam1);
Bundle args = getArguments();
TextView textView1 = view.findViewById(R.id.textview1);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss.sss", Locale.US);
String dt = df.format(Calendar.getInstance().getTime());
textView1.setText(dt);
}
public void updateView(){
Log.d("Frag", "updateView");
TextView textView2 = view.findViewById(R.id.textview2);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss.sss", Locale.US);
String dt = df.format(Calendar.getInstance().getTime());
textView2.setText(dt);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d("Frag", "onAttach:" + mParam1);
}
@Override
public void onDetach() {
super.onDetach();
Log.d("Frag", "onDetach:" + mParam1);
}
@Override
public void onResume() {
super.onResume();
Log.d("Frag", "onResume:" + mParam1);
updateView();
}
@Override
public void onPause() {
super.onPause();
Log.d("Frag", "onPause:" + mParam1);
}
}
Upvotes: 2