Android项目mvvm的尝试


五一期间没事,继续研究最近也使用得比较多的Android,很多Activity代码上百成千行,这次使用MVVM的方式,将部分代码分到别地方,也就是ViewModel。

1、首先导Jetpack包,这个包基本用kotlin语言更好点,毕竟可以用协程。

//jetpack
    def lifecycle_version = "2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

2、新建一个容器类,这个是官方推荐的,我觉得有点像逻辑层,不管了,先建吧 SystRepository.class,把逻辑全写在里面

实现功能比较简单,从网络获取用户信息。

public class SysRepository {
    private Context context;
    private IUserService userService;

    public SysRepository(Context context) {
        this.context = context;
        userService = RetrofitClient.getInstance().getService(IUserService.class);
    }

    public void userBinder(MutableLiveData userId,MutableLiveData userName){
        String spuserId = "";
        UserLoginInfo userLoginInfo =  SpHelper.GetUserLoginSetting(context);
        if(userLoginInfo!=null){
            spuserId = userLoginInfo.getUserId();
        }

        Call> call =  userService.getUserInfo(spuserId);
        call.enqueue(new Callback>() {
            @Override
            public void onResponse(Call> call, Response> response) {
                if(response.isSuccessful()) {
                    ResultBean resultBean = response.body();
                    if (resultBean.getSuccess()) {
                        UserInfoBean userInfoBean = resultBean.getResult();
                        if (userInfoBean != null) {
                            userId.postValue(userInfoBean.getUserId());
                            userName.postValue(userInfoBean.getUserName());
                        }
                    } else {
                        Toast.makeText(context, resultBean.getMsg(), Toast.LENGTH_SHORT).show();
                    }
                }
                else
                {
                    Toast.makeText(context,response.message() , Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onFailure(Call> call, Throwable t) {
                Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3、新建viewModel文件,这地方要注意的是,如果用到Context需要继承AndroidViewModel,官方推荐是不要传这个,正常是继承ViewModel 

public class SysViewModel extends AndroidViewModel {

    private MutableLiveData userId;

    private MutableLiveData userName;

    private static final String TAG = SysViewModel.class.getSimpleName();

    private SysRepository sysRepository;

    private Context context;

    public SysViewModel(@NonNull Application application) {
        super(application);
        this.context = application;
        sysRepository = new SysRepository(this.context);
    }

    public MutableLiveData getUserId() {
        if(userId==null){
            userId = new MutableLiveData<>();
            userId.setValue("");
        }
        return userId;
    }


    public MutableLiveData getUserName() {
        if(userName==null){
            userName = new MutableLiveData<>();
            userName.setValue("");
        }
        return userName;
    }

    public void userInfoBinder(){
        sysRepository.userBinder(userId,userName);
    }
}

下面就是在主界面中修改了,一种是在Fragment的写法,一种是Activity中的写法。

 //Fragment写法
        binding = DataBindingUtil.inflate(inflater,R.layout.fragment_sys,container,false);
        //Activity
        //binding = DataBindingUtil.setContentView(this,R.layout.fragment_sys);
        sysViewModel = new ViewModelProvider(getActivity(),new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(SysViewModel.class);
        binding.setSysViewModel(sysViewModel);
        binding.setLifecycleOwner(getActivity());
        View view = binding.getRoot();
        return view;

下面的文字是以前的写法,包括非bind的写法,不一定对,可以,留着参考

一、非bind方式

1、Fragment文件添加代码

 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_sys, container, false);

        userViewModel = new UserViewModel(getActivity());
        sys_fra_tv_username = view.findViewById(R.id.sys_fra_tv_username);
        sys_fra_tv_userid = view.findViewById(R.id.sys_fra_tv_userid);
        userViewModel.getUserId().observe(getActivity(), new Observer() {
            @Override
            public void onChanged(String s) {
                sys_fra_tv_userid.setText(s);
            }
        });
        userViewModel.getUserName().observe(getActivity(), new Observer() {
            @Override
            public void onChanged(String s) {
                sys_fra_tv_username.setText(s);
            }
        });
        return view;
    }

2、使用了观察者模式来监听数据的变化,在合适的地方加上

public class SysViewModel extends AndroidViewModel {

    private MutableLiveData userId;

    private MutableLiveData userName;

    private static final String TAG = SysViewModel.class.getSimpleName();

    private SysRepository sysRepository;

    private Context context;

    public SysViewModel(@NonNull Application application) {
        super(application);
        this.context = application.getBaseContext();
        sysRepository = new SysRepository(this.context);
    }

    public MutableLiveData getUserId() {
        if(userId==null){
            userId = new MutableLiveData<>();
            userId.setValue("");
        }
        return userId;
    }


    public MutableLiveData getUserName() {
        if(userName==null){
            userName = new MutableLiveData<>();
            userName.setValue("");
        }
        return userName;
    }

    public void userInfoBinder(){
        sysRepository.userBinder(userId,userName);
    }
}

3、布局文件如下

<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/gray_f0f0f0"
        android:orientation="vertical"
        tools:context="com.yysoft.syjz.Fragments.SysFragment">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="10dp"
            android:background="@color/white"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="用户Id:"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />

            <TextView
                android:id="@+id/sys_fra_tv_userid"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />
        LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="10dp"
            android:background="@color/white"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="用户名:"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />

            <TextView
                android:id="@+id/sys_fra_tv_username"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />
        LinearLayout>

        <Button
            android:id="@+id/btn_out"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="退出"
            android:textColor="@color/white">Button>


    LinearLayout>

二、bind方式,和上面相比,写的代码更少

1、首先打开bind方式,在build.gradle文件中andriod节点添加

dataBinding{
        enabled = true
    }

2、添加bind类,在布局文件最高点右击添加,里面也进行了些修改,是不是有点VUE的感觉,呵呵。

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
    <variable
        name="data"
        type="com.yysoft.syjz.vm.UserViewModel" />
    data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/gray_f0f0f0"
        android:orientation="vertical"
        tools:context="com.yysoft.syjz.Fragments.SysFragment">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="10dp"
            android:background="@color/white"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="用户Id:"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />

            <TextView
                android:id="@+id/sys_fra_tv_userid"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="@{data.userId}"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />
        LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="80dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="10dp"
            android:background="@color/white"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="用户名:"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />

            <TextView
                android:id="@+id/sys_fra_tv_username"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="10dp"
                android:gravity="center"
                android:text="@{data.userName}"
                android:textColor="@color/text_9f9f9f"
                android:textSize="24sp" />
        LinearLayout>

        <Button
            android:id="@+id/btn_out"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="退出"
            android:textColor="@color/white">Button>


    LinearLayout>
layout>

3、Fragment文件中添加代码

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment   
        userViewModel = new UserViewModel(getActivity());
        binding = FragmentSysBinding.inflate(inflater,container,false);
        binding.setData(userViewModel);
        binding.setLifecycleOwner(getActivity());
       View view = binding.getRoot();
        return view;
    }

4、在合适的地方添加更新方法,和上面一样,这里不说了。

总结,确实将原来页面上的代码提出来扔往viewmodel里面,也有了mvvm的感觉,像vue,其实也有点像mvc。是不是双向绑定还没继续试。等下一P吧。