Android - есть 2 фрагмента, которые были разработаны как MVVM. ViewPager не работает правильно - PullRequest
0 голосов
/ 10 января 2019

У меня есть ошибка в моем приложении, и я не могу найти, где неправильная функциональность, поэтому я упростила свое приложение, чтобы показать вам. Я исключил, что у приложения есть viewPager и 2 фрагмента с recyclerView, и когда пользователь проведет пальцем влево - viewPager показывает второй фрагмент, но он не предоставляет возможности пользователю смахивать - viewPager показывает только второй фрагмент. Этот проект был загружен на github: https://github.com/reflectorGit/Repository1

Это макет MainActivity - activity_main .xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical">

<Button
    android:id="@+id/button_bind_fake_model_with_fragments"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="bind"/>

<android.support.v4.view.ViewPager
    android:id="@+id/view_pager"
    android:layout_height="match_parent"
    android:layout_width="match_parent"/>

И есть MainActivity - в методе OnCreate фрагменты будут созданы конструктором по умолчанию, затем будут инициализированы их поля данных, но данные не будут связаны с фрагментами в методе OnCreate, поскольку Activity не будет создана, поэтому если мы вызываем метод getActivity () из Fragment.BindDataWithFragment (), программа выдаст исключение NullReferenceException. Таким образом, данные фрагментов будут связаны, когда пользователь нажимает кнопку. MainActivity.java

package com.example.user.myapplication;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
static List<MyBaseFragment> fragments;
static FragmentManager fm;
static ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fm = getSupportFragmentManager();


    fragments = new ArrayList<MyBaseFragment>();
    fragments.add(new FirstFragment());
    fragments.add(new SecondFragment());

    fragments.get(0).setData(initFakeModelForFirstFragment());
    fragments.get(1).setData(initFakeModelForSecondFragment());

    Button btnBindFakeModelWithFragments = (Button) findViewById(R.id.button_bind_fake_model_with_fragments);
    btnBindFakeModelWithFragments.setOnClickListener(this);

    viewPager = (ViewPager) findViewById(R.id.view_pager);
}



private List<MyModel> initFakeModelForFirstFragment() {
    ArrayList<MyModel> firstFragmentFakeModel = new ArrayList<MyModel>();
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_1"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_2"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_3"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_4"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_5"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_6"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_7"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_8"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_9"));
    firstFragmentFakeModel.add(new MyModel("FirstFragmentModel_10"));
    return firstFragmentFakeModel;
}

private List<MyModel> initFakeModelForSecondFragment() {
    ArrayList<MyModel> secondtFragmentFakeModel = new ArrayList<MyModel>();
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_1"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_2"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_3"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_4"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_5"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_6"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_7"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_8"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_9"));
    secondtFragmentFakeModel.add(new MyModel("SecondFragmentModel_10"));
    return secondtFragmentFakeModel;
}

@Override
public void onClick(View view) {
    viewPager.setAdapter(new FragmentPagerAdapter(fm, fragments));

    for(MyBaseFragment fragment : fragments) {
        fragment.BindDataWithFragment();
    }


    viewPager.getAdapter().notifyDataSetChanged();
}
}

Есть два фрагмента, полученных из MyBaseFragment First и Second. Вкратце - MyBaseFragment предоставляет шаблонный метод BindDataWithFragment, а также абстрактные методы initBinding (), onSuccess (список данных). initBinding () - инициализировать представление для конкретного фрагмента (для FirstFragment.java - frag_one.xml, для SecondFragment - frag_two.xml). onSuccess (список данных) - связать данные для адаптера recyclerView в конкретном фрагменте

import java.util.List;

public abstract class MyBaseFragment extends Fragment {
private List<MyModel> data = null;

public List<MyModel> getData() {
    return data;
}

public void setData(List<MyModel> data) {
    this.data = data;
}

protected final void BindDataWithFragment() {
    initBinding();
    if(this.data != null && this.data.size() > 0) {
        onSuccess(this.data);
    }
    else {
        throw new IllegalArgumentException();
    }
}

protected abstract void initBinding();
protected abstract void onSuccess(List<MyModel> data);


protected abstract class BaseMyModelAdapter<T extends BaseMyModelHolder> extends RecyclerView.Adapter<T>{
    protected List<MyModel> data = null;
    public List<MyModel> getData(){
        return data;
    }

    public void setData(List<MyModel> data){
        this.data = data;
    }

    public BaseMyModelAdapter(List<MyModel> data) {
        this.data = data;
    }
}

protected abstract class BaseMyModelHolder extends RecyclerView.ViewHolder {
    public BaseMyModelHolder(MyModelItemBinding binding) {
        super(binding.myViewModelItem);
        this.binding = binding;
    }
    protected MyModelItemBinding binding = null;
}
}

Это макет первого фрагмента --gment_one.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.CategoryPagerActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/fragment_one_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        android:scrollbars="vertical" />
</RelativeLayout>

Это код первого фрагмента:

package com.example.user.myapplication;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.user.myapplication.databinding.FragmentOneBinding;
import com.example.user.myapplication.databinding.MyModelItemBinding;
import java.util.List;

public class FirstFragment extends MyBaseFragment {
private FragmentOneBinding fragmentOneBinding = null;
public FragmentOneBinding getFragmentOneBinding() {
    return fragmentOneBinding;
}
public void setFragmentOneBinding(FragmentOneBinding fragmentOneBinding) {
    this.fragmentOneBinding = fragmentOneBinding;
}

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_one, container, false);
    return view;
}

@Override
protected void initBinding() {
    fragmentOneBinding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_one);
}

@Override
protected void onSuccess(List<MyModel> data) {
    getFragmentOneBinding().fragmentOneRv.setLayoutManager(new LinearLayoutManager(getContext()));
    FirsFragmentAdapter firstDataAdapter = new FirsFragmentAdapter(data);
    getFragmentOneBinding().fragmentOneRv.setAdapter(firstDataAdapter);
}

private class FirstModelHolder extends BaseMyModelHolder {
    public FirstModelHolder(MyModelItemBinding view) {
        super(view);
        this.binding = view;
    }
}

private class FirsFragmentAdapter extends BaseMyModelAdapter<FirstModelHolder> {

    public FirsFragmentAdapter(List<MyModel> data) {
        super(data);
    }
    @NonNull
    @Override
    public FirstModelHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        MyModelItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.my_model_item, parent,false);
        return new FirstModelHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull FirstModelHolder holder, int position) {
        holder.binding.setMyViewModel( new MyViewModel(getData().get(position)));
    }
    @Override
    public int getItemCount() {
        return getData().size();
    }
}
}

Это макет второго фрагмента - frag_two.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".view.CategoryPagerActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/fragment_two_rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp"
        android:scrollbars="vertical" />
</RelativeLayout>

Это код второго фрагмента:

package com.example.user.myapplication;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.user.myapplication.databinding.FragmentTwoBinding;
import com.example.user.myapplication.databinding.MyModelItemBinding;
import java.util.List;

public class SecondFragment extends MyBaseFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_two, container, false);
    return view;
}
@Override
protected void initBinding() {
    fragmentTwoBinding = DataBindingUtil.setContentView(getActivity(), R.layout.fragment_two);
}

@Override
protected void onSuccess(List<MyModel> data) {
    getFragmentTwoBinding().fragmentTwoRv.setLayoutManager(new LinearLayoutManager(getContext()));
    SecondFragment.SecondFragmentAdapter secondFragmentAdapter = new SecondFragment.SecondFragmentAdapter(data);
    getFragmentTwoBinding().fragmentTwoRv.setAdapter(secondFragmentAdapter);
}

public FragmentTwoBinding getFragmentTwoBinding() {
    return fragmentTwoBinding;
}

public void setFragmentTwoBinding(FragmentTwoBinding fragmentTwoBinding) {
    this.fragmentTwoBinding = fragmentTwoBinding;
}

private FragmentTwoBinding fragmentTwoBinding = null;


private class SecondModelHolder extends BaseMyModelHolder {
    public SecondModelHolder(MyModelItemBinding view) {
        super(view);
        this.binding = view;
    }
}

private class SecondFragmentAdapter extends BaseMyModelAdapter<SecondFragment.SecondModelHolder> {

    public SecondFragmentAdapter(List<MyModel> data) {
        super(data);
    }
    @NonNull
    @Override
    public SecondFragment.SecondModelHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        MyModelItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.my_model_item, parent,false);
        return new SecondFragment.SecondModelHolder(binding);
    }

    @Override
    public void onBindViewHolder(@NonNull SecondFragment.SecondModelHolder holder, int position) {
        holder.binding.setMyViewModel( new MyViewModel(getData().get(position)));
    }
    @Override
    public int getItemCount() {
        return getData().size();
    }
}
}

И это макет каждого элемента переработчикаПросмотреть my_model_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
    <variable
        name="myViewModel"
        type="com.example.user.myapplication.MyViewModel"/>
</data>
<RelativeLayout
    android:id="@+id/my_view_model_item"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@{myViewModel.name}"
        />
</RelativeLayout>

This MyModel.java:

package com.example.user.myapplication;

public class MyModel {

private String mName;

public String getmName() {
    return mName;
}

public void setmName(String mName) {
    this.mName = mName;
}

public MyModel(String mName) {
    this.mName = mName;
}
}

Это MyViewModel.java:

package com.example.user.myapplication;

import android.databinding.BaseObservable;

public class MyViewModel extends BaseObservable {
public String name;

public MyViewModel(MyModel myModel) {
    if(myModel == null) {
        throw new IllegalArgumentException();
    }
    this.name = myModel.getmName();
}

}

И последний - FragmentPagerAdapter.java

package com.example.user.myapplication;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import java.util.List;

public class FragmentPagerAdapter extends android.support.v4.app.FragmentPagerAdapter {
List<? extends MyBaseFragment> fragments = null;
public FragmentPagerAdapter(FragmentManager fm, List<? extends MyBaseFragment> fragments) {
    super(fm);
    this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
    return fragments.get(position);
}

@Override
public int getCount() {
    return fragments.size();
}
}
...