danyapd
danyapd

Reputation: 2506

Updating only current viewpager fragment

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

Answers (1)

Andrew
Andrew

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

Related Questions