每次单击底部导航选项卡时,防止片段加载数据
Prevent fragment from loading data every time on bottomnavigation tab click
我正在使用带有 5 个选项卡的 BottomNavigationView。最初,我在应用程序启动后加载第一个选项卡。当我单击任何其他选项卡时,会进行 API 调用并加载数据。现在,当我再次单击上一个选项卡(在启动时加载)时,会调用 API 以再次加载相同的数据。
我不想再次加载数据,并且想在没有新 API 调用的情况下显示具有相同数据的片段。
我的代码:
public class MainActivity extends AppCompatActivity implements NavigationBarView.OnItemSelectedListener {
private BottomNavigationView bottomNavigationView;
public static ViewPager2 viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewpager);
bottomNavigationView = findViewById(R.id.navigation);
bottomNavigationView.setOnItemSelectedListener(this);
getTabs();
}
public void getTabs() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentAdapterMain adapter = new FragmentAdapterMain(fragmentManager, getLifecycle());
viewPager.setAdapter(adapter);
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
switch (position) {
case 0:
bottomNavigationView.getMenu().findItem(R.id.one).setChecked(true);
break;
case 1:
bottomNavigationView.getMenu().findItem(R.id.two).setChecked(true);
break;
case 2:
bottomNavigationView.getMenu().findItem(R.id.three).setChecked(true);
break;
case 3:
bottomNavigationView.getMenu().findItem(R.id.four).setChecked(true);
break;
case 4:
bottomNavigationView.getMenu().findItem(R.id.five).setChecked(true);
break;
}
}
});
}
@SuppressLint("NonConstantResourceId")
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.one:
viewPager.setCurrentItem(0, false);
break;
case R.id.two:
viewPager.setCurrentItem(1, false);
break;
case R.id.three:
viewPager.setCurrentItem(2, false);
break;
case R.id.four:
viewPager.setCurrentItem(3, false);
break;
case R.id.five:
viewPager.setCurrentItem(4, false);
break;
}
return true;
}
}
我不想使用 viewPager.setOffscreenPageLimit(size)
因为它会在启动时同时加载所有 5 个片段中的数据(我不想在启动时调用所有 5 个 API)。
这可能是一个比您希望的更复杂的解决方案,但是将数据与 UI 分离是可行的方法。意思是使用 MVVM 之类的东西,然后只保留 ViewModel 数据(而不是人为地使片段保持活动状态)
另一种 easier/faster 解决方案是只使用存储库并将加载的数据保存在其中 class,然后片段可以只检查存储库是否已经加载数据,然后相应地显示内容.
我不知道这是否可行,因为无论何时使用导航组件,它都会弹出片段堆栈。
但是为了保存数据,我认为有一种方法是使用 ViewModel,即使片段被销毁也能保持活动状态。
- 要开始使用 ViewModel,请将此添加到 build.grade(模块:应用程序)中的依赖项部分:
dependencies {
...
implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.1"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
...
}
- 您现在应该能够创建一个扩展 ViewModel 的 class,例如我将其称为 myViewModel,在 ViewModel 构造函数中您将调用为您加载数据的方法:
public class MyViewModel extends ViewModel {
DataClass myData ;
public MyViewModel () {
super();
getData();
}
void getData(){
...
assign myData here
...
}
}
- 然后在第一个片段的 onCreate 中,您将使用以下代码创建 ViewModel:
MyViewModel myViewMode= new ViewModelProvider(requireActivity()).get(MyViewModel .class);
现在您会期望每次从零创建片段时也会从头创建 ViewModel,但这里有一个转折点,只要您提供的对象引用,ViewModel 就会保持活动状态通过 ViewModelProvider 是活的,在我们的例子中是主要的 activity.
这样,ViewModel 将在应用程序的整个生命周期内仅调用一次构造函数,只要您的 activity 没有被销毁,之后每次您请求 ViewModel在您的 onCreate 片段中,它只会为您提供对先前创建的片段的引用,而不是创建一个新片段(如果您之前遇到过设计模式,则类似于单例设计模式)。
您稍后可以将 getter 添加到您的 ViewModel 以在您的片段中随时获取数据。
N.B :您在 ViewModel 中带来和存储的数据会从您的 RAM 中消耗,因此请避免拥有大量数据并仅存储必要的数据,以便一个示例,而不是存储位图,存储它的 uri/ 而不是存储具有属于数据库的 key/id 的对象,只存储 key/id 并且只要你需要,只需将它从数据库中带到内存中.
之前的通知对于避免在您的应用程序使用期间出现 OutOfMemoryError 异常非常重要。
如果你对 ViewModels 有好奇心,你可以通过这个 link
开始阅读它们
我正在使用带有 5 个选项卡的 BottomNavigationView。最初,我在应用程序启动后加载第一个选项卡。当我单击任何其他选项卡时,会进行 API 调用并加载数据。现在,当我再次单击上一个选项卡(在启动时加载)时,会调用 API 以再次加载相同的数据。
我不想再次加载数据,并且想在没有新 API 调用的情况下显示具有相同数据的片段。
我的代码:
public class MainActivity extends AppCompatActivity implements NavigationBarView.OnItemSelectedListener {
private BottomNavigationView bottomNavigationView;
public static ViewPager2 viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.viewpager);
bottomNavigationView = findViewById(R.id.navigation);
bottomNavigationView.setOnItemSelectedListener(this);
getTabs();
}
public void getTabs() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentAdapterMain adapter = new FragmentAdapterMain(fragmentManager, getLifecycle());
viewPager.setAdapter(adapter);
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
switch (position) {
case 0:
bottomNavigationView.getMenu().findItem(R.id.one).setChecked(true);
break;
case 1:
bottomNavigationView.getMenu().findItem(R.id.two).setChecked(true);
break;
case 2:
bottomNavigationView.getMenu().findItem(R.id.three).setChecked(true);
break;
case 3:
bottomNavigationView.getMenu().findItem(R.id.four).setChecked(true);
break;
case 4:
bottomNavigationView.getMenu().findItem(R.id.five).setChecked(true);
break;
}
}
});
}
@SuppressLint("NonConstantResourceId")
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.one:
viewPager.setCurrentItem(0, false);
break;
case R.id.two:
viewPager.setCurrentItem(1, false);
break;
case R.id.three:
viewPager.setCurrentItem(2, false);
break;
case R.id.four:
viewPager.setCurrentItem(3, false);
break;
case R.id.five:
viewPager.setCurrentItem(4, false);
break;
}
return true;
}
}
我不想使用 viewPager.setOffscreenPageLimit(size)
因为它会在启动时同时加载所有 5 个片段中的数据(我不想在启动时调用所有 5 个 API)。
这可能是一个比您希望的更复杂的解决方案,但是将数据与 UI 分离是可行的方法。意思是使用 MVVM 之类的东西,然后只保留 ViewModel 数据(而不是人为地使片段保持活动状态)
另一种 easier/faster 解决方案是只使用存储库并将加载的数据保存在其中 class,然后片段可以只检查存储库是否已经加载数据,然后相应地显示内容.
我不知道这是否可行,因为无论何时使用导航组件,它都会弹出片段堆栈。
但是为了保存数据,我认为有一种方法是使用 ViewModel,即使片段被销毁也能保持活动状态。
- 要开始使用 ViewModel,请将此添加到 build.grade(模块:应用程序)中的依赖项部分:
dependencies {
...
implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.1"
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
...
}
- 您现在应该能够创建一个扩展 ViewModel 的 class,例如我将其称为 myViewModel,在 ViewModel 构造函数中您将调用为您加载数据的方法:
public class MyViewModel extends ViewModel {
DataClass myData ;
public MyViewModel () {
super();
getData();
}
void getData(){
...
assign myData here
...
}
}
- 然后在第一个片段的 onCreate 中,您将使用以下代码创建 ViewModel:
MyViewModel myViewMode= new ViewModelProvider(requireActivity()).get(MyViewModel .class);
现在您会期望每次从零创建片段时也会从头创建 ViewModel,但这里有一个转折点,只要您提供的对象引用,ViewModel 就会保持活动状态通过 ViewModelProvider 是活的,在我们的例子中是主要的 activity.
这样,ViewModel 将在应用程序的整个生命周期内仅调用一次构造函数,只要您的 activity 没有被销毁,之后每次您请求 ViewModel在您的 onCreate 片段中,它只会为您提供对先前创建的片段的引用,而不是创建一个新片段(如果您之前遇到过设计模式,则类似于单例设计模式)。
您稍后可以将 getter 添加到您的 ViewModel 以在您的片段中随时获取数据。
N.B :您在 ViewModel 中带来和存储的数据会从您的 RAM 中消耗,因此请避免拥有大量数据并仅存储必要的数据,以便一个示例,而不是存储位图,存储它的 uri/ 而不是存储具有属于数据库的 key/id 的对象,只存储 key/id 并且只要你需要,只需将它从数据库中带到内存中.
之前的通知对于避免在您的应用程序使用期间出现 OutOfMemoryError 异常非常重要。
如果你对 ViewModels 有好奇心,你可以通过这个 link
开始阅读它们