仅更新当前的 viewpager 片段
Updating only current viewpager fragment
我的 ViewPager 有 200 多个标签。每个选项卡都包含通过 retrofit2 动态加载数据的 recyclerview。每次 onTabSelected()
操作后都会加载数据。
但是由于 viewpager 加载 position-1 (if any), position, position+1 (if any)
我得到 2-3 个具有相同数据的标签。
问题是 - 我怎样才能只加载一个当前选择的没有相邻位置的片段?
我认为 FragmentPagerAdapter
中的 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
只需将其传递给构造函数即可解决我的问题:
public Adapter_programmes(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_some = new Fragment_Some();
}
但什么都没有改变。
更新:
我想我在这里找到了解决方案:ViewPager offscreen page limit
但我无法理解:
加载带有占位符图像的网格,在页面更改之前不要加载真实图像。
**UPD2:**
setOffscreenPageLimit(1) 没有解决我的问题。
我的代码:
片段:
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();
}
主要活动:
@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);
}
});
}
因为你正在填充onCreateView
中的recyclerview fragment更改为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
不会有任何影响。
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
而不是将当前 Fragment +/- OffscreenPageLimit(默认为 1)带到 "Resumed" 状态,它只将当前 Fragment 带到 "Resumed" 状态和任何其他片段生命周期中的片段到 "Started" 状态。
由于 "Started" 已经过去 onCreateView
,您的回收站视图填充得太早了。
解决方案是在 Fragment 的 onCreateView
创建没有数据的 recyclerview 适配器,找到 recyclerView,设置它的布局管理器和适配器等。
然后在 Fragment 的 onResume
方法中,获取 recyclerView 的数据并使用此新数据更新 recyclerview 适配器,然后通知 RecyclerView 它的数据已更改。
然后您可以删除 onTabSelected
东西
没有足够的示例代码来给出一个工作示例,但下面是一个示例片段,显示 "Resumed" 与 textview1
相比,textview2
与当前时间的更新当它进入 "Started" 状态时设置(您将在 Viewpager 中创建此片段的 3 个副本并设置 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
)
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);
}
}
我的 ViewPager 有 200 多个标签。每个选项卡都包含通过 retrofit2 动态加载数据的 recyclerview。每次 onTabSelected()
操作后都会加载数据。
但是由于 viewpager 加载 position-1 (if any), position, position+1 (if any)
我得到 2-3 个具有相同数据的标签。
问题是 - 我怎样才能只加载一个当前选择的没有相邻位置的片段?
我认为 FragmentPagerAdapter
中的 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
只需将其传递给构造函数即可解决我的问题:
public Adapter_programmes(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
fragment_some = new Fragment_Some();
}
但什么都没有改变。
更新: 我想我在这里找到了解决方案:ViewPager offscreen page limit
但我无法理解: 加载带有占位符图像的网格,在页面更改之前不要加载真实图像。
**UPD2:** setOffscreenPageLimit(1) 没有解决我的问题。
我的代码:
片段:
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();
}
主要活动:
@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);
}
});
}
因为你正在填充onCreateView
中的recyclerview fragment更改为BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
不会有任何影响。
BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
而不是将当前 Fragment +/- OffscreenPageLimit(默认为 1)带到 "Resumed" 状态,它只将当前 Fragment 带到 "Resumed" 状态和任何其他片段生命周期中的片段到 "Started" 状态。
由于 "Started" 已经过去 onCreateView
,您的回收站视图填充得太早了。
解决方案是在 Fragment 的 onCreateView
创建没有数据的 recyclerview 适配器,找到 recyclerView,设置它的布局管理器和适配器等。
然后在 Fragment 的 onResume
方法中,获取 recyclerView 的数据并使用此新数据更新 recyclerview 适配器,然后通知 RecyclerView 它的数据已更改。
然后您可以删除 onTabSelected
东西
没有足够的示例代码来给出一个工作示例,但下面是一个示例片段,显示 "Resumed" 与 textview1
相比,textview2
与当前时间的更新当它进入 "Started" 状态时设置(您将在 Viewpager 中创建此片段的 3 个副本并设置 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT
)
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);
}
}