我想让我的片段不会重新加载数据时,配置与视图模型的变化。
所以,我试着做一个关于gitHub用户的应用程序。我的主要活动包含搜索视图搜索用户,并显示结果与搜索视图。我的详细活动是显示详细的用户时,在列表中的一个用户点击,并在我的详细活动,我使用标签布局和查看分页显示用户的追随者和以下。
我的ViewModel for activity工作得很好,并且可以在方向改变时保持我的数据。但是当我对我的片段做同样的事情时,当方向改变时,我的片段会不断地重新加载新的数据。
在这里,我使用View Model来请求数据
public class FollowingFragment extends Fragment {
public static final String KEY_FOLLOWING = "key_following";
private RecyclerView recyclerView;
private FollowingViewModel followingViewModel;
private FollowingAdapter followingAdapter;
ShimmerFrameLayout shimmerFrameLayout;
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
ArrayList<FollowingResponse> followingResponse = new ArrayList<>();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_following, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.rv_following);
shimmerFrameLayout = view.findViewById(R.id.shimmer_frame_layout2);
followingViewModel = ViewModelProviders.of(this).get(FollowingViewModel.class);
followingAdapter = new FollowingAdapter();
followingAdapter.setOnItemClickCallback(new FollowingAdapter.OnItemClickCallback() {
@Override
public void onItemClicked(FollowingResponse followingResponse) {
showSelectedItem(followingResponse);
}
});
//this is what i've tried and worked, but my fragment result with double or triple the data.
if (savedInstanceState == null){
}
else {
followingResponse = savedInstanceState.getParcelableArrayList(KEY_FOLLOWING);
}
showRecyclerView();
getData();
}
private void getData() {
followingViewModel.setDataFollowing(DetailUserActivity.clickedUser);
followingViewModel.getDataFollowing().observe(getViewLifecycleOwner(), new Observer<ArrayList<FollowingResponse>>() {
@Override
public void onChanged(ArrayList<FollowingResponse> followingResponses) {
shimmerFrameLayout.setVisibility(View.GONE);
shimmerFrameLayout.stopShimmer();
followingAdapter.setData(followingResponse);
followingResponse.addAll(followingResponses);
recyclerView.setAdapter(followingAdapter);
followingAdapter.notifyDataSetChanged();
}
});
}
private void showRecyclerView() {
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
}
@Override
public void onResume() {
super.onResume();
followingViewModel.setDataFollowing(DetailUserActivity.clickedUser);
}
private void showSelectedItem(FollowingResponse item) {
Intent intent = new Intent(getContext(), DetailUserActivity.class);
intent.putExtra("EXTRA_DATA", item.getLogin());
startActivity(intent);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putParcelableArrayList(KEY_FOLLOWING, followingResponse);
super.onSaveInstanceState(outState);
}
}
详尽活动
public class DetailUserActivity extends AppCompatActivity {
private TextView tvName, tvNickname, tvLocation, tvCompany, tvEmail, tvWebsite;
private TextView tvCountFollowers, tvCountRepository, tvCountFollowing;
private ImageView imgProfile;
ProgressBar progressBar;
public static String clickedUser;
UserViewModel userViewModel;
private ViewPager viewPager;
TabLayout tabLayout;
private final String EXTRA_DATA = "EXTRA_DATA";
private static final String EXTRA_FOLLOW = "extra_follow";
// Fragment followingFragment;
// FragmentTransaction transaction;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detail_user_activity);
// i've tried this, but when the orientation change, my detail activity force close and throw me to my main activity.
// if (savedInstanceState != null){
// followingFragment = getSupportFragmentManager().getFragment(savedInstanceState, KEY_FOLLOWING);
// } else {
// followingFragment = new FollowingFragment();
//
// getSupportFragmentManager().beginTransaction().replace(R.id.tv_view_pager, followingFragment).commit();
// }
tvName = findViewById(R.id.tv_item_name);
tvNickname = findViewById(R.id.tv_item_nickname);
tvLocation = findViewById(R.id.tv_item_location);
tvCompany = findViewById(R.id.tv_item_company);
tvEmail = findViewById(R.id.tv_item_email);
tvWebsite = findViewById(R.id.tv_item_website);
imgProfile = findViewById(R.id.img_item_photo);
tvCountFollowers = findViewById(R.id.tv_count_follower);
tvCountRepository = findViewById(R.id.tv_count_repo);
tvCountFollowing = findViewById(R.id.tv_count_following);
progressBar = findViewById(R.id.progressbar2);
setForUserData();
setForTabLayout();
}
private void setForUserData(){
Intent detailIntent = getIntent();
clickedUser = detailIntent.getStringExtra("EXTRA_DATA");
userViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(UserViewModel.class);
userViewModel.setUserUVM(clickedUser);
userViewModel.getUserUVM().observe(this, new Observer<UserResponse>() {
@Override
public void onChanged(UserResponse userResponse) {
progressBar.setVisibility(View.GONE);
Glide.with(getApplicationContext())
.load(userResponse.getAvatarUrl())
.into(imgProfile);
tvName.setText(userResponse.getLogin());
tvLocation.setText(userResponse.getLocation());
tvNickname.setText(userResponse.getName());
tvCompany.setText(userResponse.getCompany());
tvEmail.setText(userResponse.getEmail());
tvWebsite.setText(userResponse.getBlog());
tvCountRepository.setText(String.valueOf(userResponse.getPublicRepos()));
tvCountFollowers.setText(String.valueOf(userResponse.getFollowers()));
tvCountFollowing.setText(String.valueOf(userResponse.getFollowing()));
}
});
}
private void setForTabLayout(){
tabLayout = findViewById(R.id.tv_tab_layout);
viewPager = findViewById(R.id.tv_view_pager);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount()));
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setTabMode(TabLayout.MODE_FIXED);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
int totalTab;
@SuppressWarnings("deprecation")
ViewPagerAdapter(FragmentManager fragmentManager, int totalTabs) {
super(fragmentManager);
this.totalTab = totalTabs;
}
@SuppressWarnings("ConstantConditions")
@NonNull
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new FollowersFragment();
case 1:
return new FollowingFragment();
default:
return null;
}
}
@Override
public int getCount() {
return totalTab;
}
}
// @Override
// protected void onSaveInstanceState(@NonNull Bundle outState) {
// getSupportFragmentManager().putFragment(outState, KEY_FOLLOWING, followingFragment );
// super.onSaveInstanceState(outState);
// }
}
我试图解决我的FollowingFragment第一,然后我会做同样的对我的FollowerFragment。我真的是编程新手,没有人可以问。有人可以帮助我解决我的问题与保持数据在片段时,方向改变?
3条答案
按热度按时间lymnna711#
在Fragment中,而不是在onViewCreated()中编写此代码,将其写入OnCreate()中
onViewCreated()将在每次方向改变时被调用,因此它将在每次方向改变时创建视图模型的新示例,从而使视图模型重新加载数据
ttisahbt2#
如果您只需要为
FollowingViewModel
加载一次数据,那么最好在视图模型的构造函数中进行加载,这样您就不必担心片段的方向更改。dgiusagp3#
当您在片段中创建ViewModel的示例时,如下所示
followingViewModel = ViewModelProviders.of(this).get(FollowingViewModel.class);
您将
this
作为所有者传递,其中这是片段本身。要获取View Model的同一示例,需要传递所有者的同一示例。每当方向发生变化时,碎片就会被破坏并重新创建。在重新创建时,
this
是一个不同的示例,因此提供程序返回的ViewModel也不同。你可以做的是,使用片段的父Activity作为所有者。
followingViewModel = ViewModelProviders.of(activity).get(FollowingViewModel.class);
由于大多数情况下Activity不会被销毁,因此您将收到相同的
FollowingViewModel
示例。在Activity被销毁的情况下,新Activity能够使用
NonConfigurationInstances
检索相同的旧ViewModelStore
。因此,在重建时获取相同的视图模型。这就是为什么UserViewModel
逻辑在Activity中正常工作的原因。点击此链接了解更多详情proandroiddev