我正在使用3个片段的底部导航。在Home-fragment上,我请求API提取数据并在回收器视图中显示,我的问题是每当我切换片段并再次进入Home-fragment时,它都会重新创建布局,并且再次从API提取数据,我只想加载一次应用启动时
这是我在片段中调用API的地方
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.home_fragment, container, false);
// return inflater.inflate(R.layout.home_fragment, container, false);
sharedPrefManager = new SharedPrefManager(getActivity());
locationTrack = new LocationTrack(getActivity());
buildGoogleApiClient();
fusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
getUserLatLng();
setUp(view);
netWorkCall();
return view;
}
HomeActivity默认加载家庭片段
if (savedInstanceState == null) {
Fragment fragment = null;
fragment = new HomeFragment();
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.content_frame, fragment, "home").addToBackStack("Home");
ft.commit();
}
}
底部导航点击侦听器
private void displaySelectedScreen(int itemId) {
Fragment fragment = null;
switch (itemId) {
case R.id.action_home:
fragment = new HomeFragment();
break;
case R.id.action_profile:
if (sharedPrefManager.getAuthority()) {
fragment = new ProfileFragment();
} else {
SDConstant.switchActivity(this, LoginScreen.class);
}
break;
case R.id.action_calculator:
if (sharedPrefManager.getAuthority()) {
fragment = new CalculatorFragment();
} else {
SDConstant.switchActivity(this, LoginScreen.class);
}
break;
}
//replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment, "home").addToBackStack("Home");
ft.commitAllowingStateLoss();
//ft.commitNow();
}
}
}
请指导我解决方案如何解决此重新创建API调用
答案 0 :(得分:1)
首先,请在onViewCreated
而不是onCreateView
内执行以下调用:
sharedPrefManager = new SharedPrefManager(getActivity());
locationTrack = new LocationTrack(getActivity());
buildGoogleApiClient();
fusedLocationClient = LocationServices.getFusedLocationProviderClient(getActivity());
getUserLatLng();
setUp(view);
netWorkCall(); //this call has to be removed as explained later
为什么?因为onCreateView应该只返回片段UI。之后会直接调用OnViewCreated,这是做一些事情的地方。
不可以解决您的问题。解决此问题的最佳方法是将架构组件中的ViewModel与LiveData结合使用。
您可以阅读有关此主题here的更多信息。
您的实现看起来像这样(通过链接修改了示例):
public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<List<User>>();
loadUsers();
}
return users;
}
private void loadUsers() {
// Do an asynchronous operation to fetch users.
}
}
在您的onViewCreated中,您可以执行以下操作:
MyViewModel model = new ViewModelProvider(getViewLifecycleOwner()).get(MyViewModel.class);
model.getUsers().observe(getViewLifecycleOwner(), users -> {
// update UI
});
不要为此感到不知所措。实际上,它所做的是相对简单的。 ViewModel可以保留配置更改。这意味着,如果您旋转手机,则不会再次调用loadUsers请求-与在底部导航选项卡之间切换相同。当然,如果片段被销毁,ViewModel也会被销毁(然后调用onCleared函数)。
LiveData用户只是一个简单观察者的名字。可变意味着您可以设置一个值,getUsers()返回一个不可更改的LiveData,这意味着您只能读取其值。当为LiveData对象设置值时,将通知其订阅者。您可以想象它像LiveData是使用ViewModel的Fragment实现的接口。一旦获取数据,就会调用此接口函数。有关处理LiveData is explained here的更多信息,您绝对应该检查一下。
因此,如果尚未加载用户,则ViewModel将在您开始观察getUsers时调用loadUsers。如果已加载它们,则返回当前值。
哦,要添加LiveData和ViewModel-> it's explained here :)
希望这很有帮助。我知道很多,但请相信我,值得花时间!