我在TabLayout中重复的片段中有一个RecyclerView
。我在RecyclerView中遇到了视图不变的问题。我在每个标签上都有一个微调器。我想在选择微调器项目时更改数据。
我的案例:
- 在标签之间切换时,项目已更改
在第一个标签中的微调器中选择其他值时 - 项目未更改。 (但是数据在适配器类中发生了变化。首先,它在选择期间不为null然后为null。但是第一个没有空的数据没有出现,它被替换为null。使用断点找到它。)
注意:在这种情况下,切换选项卡时,项目会更改为 微调器在上一个选项卡中选择了项目。然后它消失了 并在选项卡中显示当前项目。
- 醇>
在最后一个标签的微调器中选择其他值时 - 项目已更改。
我的查看寻呼机适配器类
public class StudentViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<StudentList> mFragmentList = new ArrayList<>();
private final List<Clazz> mFragmentTitleList = new ArrayList<>();
public StudentViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public void addFragment(StudentList fragment,Clazz clazz){
mFragmentList.add(fragment);
mFragmentTitleList.add(clazz);
}
@Override
public Fragment getItem(int position) {
return StudentList.newInstance(mFragmentTitleList.get(position));
}
@Override
public int getCount() {
return mFragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position).getName();
}
}
我的RecyclerView
适配器类
public class PeopleAdapter extends RecyclerView.Adapter<PeopleAdapter.MyViewHolder> implements View.OnClickListener {
private List<Student> dataList;
private Context context;
private Clicker clicker;
public PeopleAdapter(List<Student> data, Context context, Clicker clicker) {
this.dataList = data;
this.context = context;
this.clicker = clicker;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.people_list_item, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Student data=dataList.get(position);
holder.email.setText(data.getEmail());
holder.name.setText(data.getName());
holder.phone.setText(data.getPhone());
Glide.with(context).load(Method.getImageUrl(MyConfiguration.STUDENT_IMAGE_URL,
data.getStudentId())).asBitmap().into(holder.profilePic);
holder.edit.setOnClickListener(this);
holder.edit.setTag(position);
}
@Override
public int getItemCount() {
return dataList.size();
}
@Override
public void onClick(View v) {
clicker.OnItemClicked((int) v.getTag(),null);
}
static class MyViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.name)
TextView name;
@BindView(R.id.email)
TextView email;
@BindView(R.id.phone)
TextView phone;
@BindView(R.id.image)
ImageView profilePic;
@BindView(R.id.imageedit)
ImageView edit;
MyViewHolder(View view) {
super(view);
ButterKnife.bind(this,view);
}
}
}
标签片段
public class StudentList extends Fragment implements SectionChanger {
@BindView(R.id.studentlist)
RecyclerView mRecyclerview;
CompositeDisposable disposable;
private Unbinder unbinder;
private Clazz clazz;
private Requester requester;
public StudentList() {
StudentInformation.bindSectionChangeListener(this);
}
public static StudentList newInstance(Clazz clazz) {
StudentList fragment=new StudentList();
Bundle args = new Bundle();
args.putSerializable(MyConfiguration.SECTIONS, clazz);
fragment.setArguments(args);
return fragment;
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
disposable.clear();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_student_list, container, false);
unbinder = ButterKnife.bind(this, view);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerview.setLayoutManager(mLayoutManager);
initializeRetrofit();
if (getArguments() != null) {
clazz = (Clazz) getArguments().getSerializable(MyConfiguration.SECTIONS);
loadStudentJson(clazz != null ? clazz.getClassId() : null,
clazz != null ? clazz.getSections().get(0).getSectionId() : null);
}
return view;
}
/**
* Load students list
*/
public void loadStudentJson(String class_id,String section_id) {
disposable = new CompositeDisposable(requester.getStudentsInSection(class_id,section_id)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(
this::handleResponse,
this::handleError
)
);
}
private void handleResponse(List<Student> list) {
PeopleAdapter adapter=new PeopleAdapter(list, getActivity(),
(position, name) -> Toast.makeText(getActivity(), position, Toast.LENGTH_LONG).show());
mRecyclerview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void handleError(Throwable error) {
Toast.makeText(getActivity(), "Error " + error.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
@Override
public void ChangeData(Section section) {
loadStudentJson(section.getClassId(),section.getSectionId());
}
public void initializeRetrofit(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
CookieHandler handler=new Cookies(getActivity());
//ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(getActivity()));
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cookieJar(new JavaNetCookieJar(handler))
.build();
requester = new Retrofit.Builder()
.baseUrl(MyConfiguration.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build().create(Requester.class);
}
}
Viewpager设置片段
public class StudentInformation extends Fragment implements TabLayout.OnTabSelectedListener, AdapterView.OnItemSelectedListener {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private Unbinder unbinder;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
CompositeDisposable disposable;
List<Section> sectionsList=new ArrayList<>();
private OnConnectingFragments mListener;
@BindView(R.id.tabs)
TabLayout mTabLayout;
@BindView(R.id.viewpager)
ViewPager viewPager;
@BindView(R.id.secSelector)
Spinner spinner;
@BindView(R.id.className)
TextView className;
private static SectionChanger sectionChanger;
public StudentInformation() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment StudentInformation.
*/
// TODO: Rename and change types and number of parameters
public static StudentInformation newInstance(String param1, String param2) {
StudentInformation fragment = new StudentInformation();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
disposable.clear();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fragment_student_information, container, false);
unbinder = ButterKnife.bind(this, view);
LoadDataAndSetupViewPager();
//setupViewPager(viewPager);
mTabLayout.setupWithViewPager(viewPager);
mTabLayout.addOnTabSelectedListener(this);
spinner.setOnItemSelectedListener(this);
// ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, MyConfiguration.CLASS_SECTIONS);
// spinner.setAdapter(arrayAdapter);
return view;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Fragment fragment,String tag) {
if (mListener != null) {
mListener.onClickedMenu(fragment,tag);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnConnectingFragments) {
mListener = (OnConnectingFragments) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
/*private void setupViewPager(ViewPager viewPager) {
StudentViewPagerAdapter adapter = new StudentViewPagerAdapter(getFragmentManager());
//adapter.addFragment(new StudentList(),"exam");
for (String claz: MyConfiguration.CLASS)
adapter.addFragment(new StudentList(), claz);
viewPager.setAdapter(adapter);
}*/
@OnClick(R.id.add)
public void OnClicked(LinearLayout view){
onButtonPressed(new AddStudent(),"addStudent");
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
className.setText(String.format(getString(R.string.class_name), tab.getPosition()+1));
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
public void LoadDataAndSetupViewPager() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
ClearableCookieJar cookieJar =
new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(getActivity()));
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Requester requester=new Retrofit.Builder()
.baseUrl(MyConfiguration.BASE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(JacksonConverterFactory.create())
.client(client)
.build().create(Requester.class);
disposable=new CompositeDisposable(requester.getClasses() ////GETTING CLASSES////
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.flatMapIterable(clazzs -> clazzs)
.flatMap(clazz -> requester.getDivision(clazz.getClassId()) ////GETTING SECTIONS////
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.flatMapIterable(sections -> sections)
.doOnNext(section -> {sectionsList.add(section);
Log.v("section_id",section.getSectionId());})
.takeLast(1)
.map(section -> clazz)
)
.doOnNext(clazz -> {clazz.setSections(sectionsList);
Log.v("List Size",sectionsList.size()+"");
sectionsList=new ArrayList<>();
})
.toList()
.subscribe(this::SetupViewPager, throwable -> Log.e("retroerror",throwable.toString())));
}
public void SetupViewPager(List<Clazz> classList){
StudentViewPagerAdapter adapter = new StudentViewPagerAdapter(getFragmentManager());
//adapter.addFragment(new StudentList(),"exam");
for (Clazz claz: classList){
adapter.addFragment(new StudentList(), claz);
}
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(3);
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
List<Section>sections=classList.get(position).getSections();
ArrayAdapter<Section> arrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, sections);
spinner.setAdapter(arrayAdapter);
}
});
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
Section section= (Section) parent.getItemAtPosition(position);
sectionChanger.ChangeData(section);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
public static void bindSectionChangeListener(SectionChanger changer){
sectionChanger=changer;
}
}
问题是:为什么有时候在微调器中选择选项时数据会保持不变?(看我的情况)
答案 0 :(得分:6)
尝试使用getChildFragmentManager()而不是getFragmentManager()将解决您的问题
答案 1 :(得分:3)
我认为你应该实现onNothingSelected(),如下所示
Section mCurrentSection;
@Override
public void onNothingSelected(AdapterView<?> parent) {
int position = parent.getSelectedItemPosition();
Section section= (Section) parent.getItemAtPosition(position);
if (mCurrentSection == null || !mCurrentSection.equals(section)) {
mCurrentSection = section;
sectionChanger.ChangeData(section);
}
}
因为,当您重新选择一个微调器项时,会调用onNothingSelected而不是onItemSelected。
答案 2 :(得分:1)
问题主要在于:
public StudentList() {
StudentInformation.bindSectionChangeListener(this);
}
这并不能保证用户可见的片段是最后一个绑定的片段。您设置viewPager.setOffscreenPageLimit(3);
意味着每次可以实例化三个片段,因此当您在片段上时,也会创建右侧和左侧片段。
这解释了为什么最后一个很好用,因为没有一个正确的片段,可能是最后一个被实例化和绑定的片段。
我个人会更改处理页面片段内微调器的实现,因为它只对页面片段起作用。
使用setUserVisibleHint的解决方案
当片段变得对用户不可见时,将页面片段绑定到主片段。注意内存泄漏并释放静态引用
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
StudentInformation.bindSectionChangeListener(this);
}
}
使用总线的解决方案
另一个快速解决方案可能是使用这样的总线:http://square.github.io/otto/
通过这种方式,每个片段都会订阅一个事件SelectedItemChanged
并刷新它们自己。每次更改微调器时,主片段都会发布更新。
然而这个例子非常大,所以我不确定没有其他问题。尝试共享一个完整的项目以获得更具体的帮助。
答案 3 :(得分:1)
当您使用recycleview时,仅依赖于您的模型类字段值。对模型类进行所有更改并基于此模型类字段创建行视图。
即,您必须根据模型类字段的值创建或更改值或查看状态。
例如:如果你想让一行(位置30)不可见,那么我将在模型类中设置一个名为可见性的标志,并将其设置为 false 。
在这种情况下,只要在UI中重新查看视图,我们就必须检查标志并根据该模型类字段值设置可见性。
像这样你可以在模型类中创建API等标志,内容值,序列化参数。此方法将通过用户交互和API更改使您的reclycleview更加一致。
答案 4 :(得分:1)
检查StudentViewPagerAdapter
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position).newInstance(mFragmentTitleList.get(position));
}
为什么再次致电newInstance
?
将其替换为以下内容,
return mFragmentList.get(position);
答案 5 :(得分:-1)
首先,检查是否在
之后添加了这一行setadapter :
adapter.notifyDataSetChanged();
另一种方法是使MyViewHolder
持有者和国际职位
例如
public void onBindViewHolder(final MyViewHolder holder, final int position) {