gpt4 book ai didi

android - 即使 offsetlimit 是默认值(0),ViewPager2 也会预加载下一个 fragment

转载 作者:行者123 更新时间:2023-12-03 16:11:47 35 4
gpt4 key购买 nike

我正面临 viewPager2 这个相当奇怪的问题。
我做了一些阅读,发现 viewPager2 的默认偏移限制为 0,这非常适合我的应用程序。
我将它与选项卡布局一起使用,我有 3 个 fragment (主页、个人资料、通知)。
当 Activity 加载和第一个 fragment (主页)加载时,我可以在我的 logcat 中看到下一个 fragment (配置文件)没有按预期加载。
但是当我单击配置文件选项卡时,会发生一些奇怪的事情,下一个选项卡(通知)被预加载。方法
调用通知选项卡的 onAttach、onCreate、onCreateView、onActivityCreated、onStart。
为什么这样做以及如何解决这个问题?
Logcat Screenshot
我在这里附上了我的 logcat 的屏幕截图。
先感谢您。

最佳答案

我假设你的意思是 OFFSCREEN_PAGE_LIMIT_DEFAULT不是 offsetlimit正如您所说的 fragment 问题的预加载。

默认值为-1不为零 https://developer.android.com/reference/androidx/viewpager2/widget/ViewPager2.html#OFFSCREEN_PAGE_LIMIT_DEFAULT

和默认的意思

Value to indicate that the default caching mechanism of RecyclerView should be used instead of explicitly prefetch and retain pages to either side of the current page.



由于这是对 recyclerview 的性能优化,我会说它不能保证它不会预加载你的 fragment ,它只是留给 recyclerview 的缓存机制来决定。

有许多因素会影响 recyclerview 的缓存机制。

如果您的 fragment 的预加载是一个问题,因为您在其中有动态数据,您只想在页面显示时加载,那么最好移动您的 fragment 以使用“延迟加载”方法,即仅在以下情况下加载数据它显示出来了。

我对原始的 viewpager 有类似的问题,并通过“延迟加载”解决了这个问题。如果加载动态数据的时间是问题,那么更新问题,然后我可以概述一个可能的解决方案。

更新:3

看起来 Viewpager2 实际上与原始 Viewpager 不同的是在 Fragments 生命周期中正常工作,因此您可以调用 updateView()如 fragment onResume 中的 update2 示例所示无需使用 pageSelected 的方法通过 Adapter 回调触发 View 的更新。

更新:

我相信查看 viewpager2 代码的实际原因是,选择 Tab 会进行平滑滚动的假拖动,并且平滑滚动会将所选项目 +1 添加到缓存中,如果您自己从 Tab0 滑动到 Tab1 它不会创建 Tab2

ViewPager2 有点不同,我用于原始 ViewPager 的“延迟加载”方法并不完全适合,但是有一种稍微不同的方法可以做到这一点。

原始 ViewPager 的主要思想是仅在使用 onPageChangeListener 选择页面时更新 View ,但 ViewPager2 使用回调代替

因此,在创建 ViewPager2 后添加以下内容(通常在 Activity onCreate 中)

        viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
// Tell the recyclerview that position 2 has changed when selected
// Thus it recreates it updating the dynamic data
if (position == 2) {
// the adapter for the ViewPager needs to a member of the Activity class so accessible here
adapter.notifyItemChanged(position);
}
}
});

这更简单,但有一个小缺点,即动态数据在预加载时加载,然后在实际显示时再次加载。

更新 2:
第一种方法的更有效的补充,更类似于我原来的方法

这是一个完整的工作示例,因为它更容易解释。

主要思想是在您的 fragment 中,您只希望在显示时加载的动态数据是创建一个空的“占位符” View 项,并且您不使用 fragment onViewCreated 中的数据填充它, 在本例中是第二个 textview没有文本,但可以是零对象或任何其他类型的 View 的回收 View 。

然后在您的 Fragment 中创建一个方法来使用数据更新“占位符”(在这种情况下,该方法称为 updateView(),它将 textview 文本设置为当前日期和时间)

然后在您的 fragment 适配器中,您存储对它在 ArrayList 中创建的每个 fragment 的引用。 (这允许您取回 fragment )然后您创建一个 updateFragment()适配器中使用位置获取 fragment 的方法,以便能够调用 updateView()在上面。

最后再次使用 onPageSelected调用 updateFragment与您要动态更新的位置。

所以 textview1显示创建 fragment 的数据和时间以及 textview2仅显示在第三个选项卡上,并且在选择页面时具有日期和时间。请注意 texview1在“Tab 2”和“Tab 3”上同时单击“Tab 2”标题以更改选项卡(这是问题中的问题)

MainActivity.java

package com.test.viewpager2;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;

import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

public class MainActivity extends AppCompatActivity {

TabLayout tabLayout;
ViewPager2 viewPager2;
ViewPager2Adapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

viewPager2 = findViewById(R.id.viewpager2);
tabLayout = findViewById(R.id.tabLayout);

viewPager2.setAdapter(createCardAdapter());

new TabLayoutMediator(tabLayout, viewPager2,
new TabLayoutMediator.TabConfigurationStrategy() {
@Override public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText("Tab " + (position + 1));
}
}).attach();

viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
// Tell the recyclerview that position 2 has changed when selected
// Thus it recreates it updating the dynamic data
if (position == 2) {
adapter.updateFragment(position);
}
}
});
}

private ViewPager2Adapter createCardAdapter() {
adapter = new ViewPager2Adapter(this);
return adapter;
}

}


ViewPager2Adapter.java

package com.test.viewpager2;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.ArrayList;

public class ViewPager2Adapter extends FragmentStateAdapter {

private static final int numOfTabs = 3;
private ArrayList<Fragment> fragments = new ArrayList<>();

public ViewPager2Adapter(@NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);
}

@NonNull @Override public Fragment createFragment(int position){
Fragment fragment = TextFragment.newInstance(position);
fragments.add(fragment);
return fragment;
}

@Override
public int getItemCount(){
return numOfTabs;
}

public void updateFragment(int position){
Fragment fragment = fragments.get(position);
// Check fragment type to make sure it is one we know has an updateView Method
if (fragment instanceof TextFragment){
TextFragment textFragment = (TextFragment) fragment;
textFragment.updateView();
}
}
}

文本 fragment .java

package com.test.viewpager2;

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");
view = inflater.inflate(R.layout.fragment_text, container, false);

return view;
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
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");
}

@Override
public void onDetach() {
super.onDetach();
Log.d("Frag", "onDetach");
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tabLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".TextFragment">

<TextView
android:id="@+id/textview1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/textview2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textview1" />/>

</androidx.constraintlayout.widget.ConstraintLayout>

关于android - 即使 offsetlimit 是默认值(0),ViewPager2 也会预加载下一个 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60252055/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com