美文网首页
Android-MVP使用beta

Android-MVP使用beta

作者: 码农老谭 | 来源:发表于2019-09-30 17:09 被阅读0次

MVP与MVC之间的区别

MVC
  • View:对应于布局文件
  • Model:业务逻辑和实体模型
  • Controllor:对应于Activity
MVP
  • View 对应于Activity,负责View的绘制以及与用户交互
  • Model 依然是业务逻辑和实体模型
  • Presenter 负责完成View于Model间的交互
MVP模式的作用

MVP的好处

  • 分离了视图逻辑和业务逻辑,降低了耦合

  • Activity只处理生命周期的任务,代码变得更加简洁

  • 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性

  • Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试

  • 把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM

其中最重要的有三点:

Activity 代码变得更加简洁

相信很多人阅读代码的时候,都是从Activity开始的,对着一个1000+行代码的Activity,看了都觉得难受。

使用MVP之后,Activity就能瘦身许多了,基本上只有FindView、SetListener以及Init的代码。其他的就是对Presenter的调用,还有对View接口的实现。这种情形下阅读代码就容易多了,而且你只要看Presenter的接口,就能明白这个模块都有哪些业务,很快就能定位到具体代码。Activity变得容易看懂,容易维护,以后要调整业务、删减功能也就变得简单许多。

方便进行单元测试

一般单元测试都是用来测试某些新加的业务逻辑有没有问题,如果采用传统的代码风格(习惯性上叫做MV模式,少了P),我们可能要先在Activity里写一段测试代码,测试完了再把测试代码删掉换成正式代码,这时如果发现业务有问题又得换回测试代码,测试代码已经删掉了!双需要重新再写了……

MVP中,由于业务逻辑都在Presenter里,我们完全可以写一个PresenterTest的实现类继承Presenter的接口,现在只要在Activity里把Presenter的创建换成PresenterTest,就能进行单元测试了,测试完再换回来即可。万一发现还得进行测试,那就再换成PresenterTest。

避免 Activity 的内存泄露

Android APP 发生OOM的最大原因就是出现内存泄露造成APP的内存不够用,而造成内存泄露的两大原因之一就是Activity泄露(Activity Leak)(另一个原因是Bitmap泄露(Bitmap Leak))。

Java一个强大的功能就是其虚拟机的内存回收机制,这个功能使得Java用户在设计代码的时候,不用像C++用户那样考虑对象的回收问题。然而,Java用户总是喜欢随便写一大堆对象,然后幻想着虚拟机能帮他们处理好内存的回收工作。可是虚拟机在回收内存的时候,只会回收那些没有被引用的对象,被引用着的对象因为还可能会被调用,所以不能回收。

Activity是有生命周期的,用户随时可能切换Activity,当APP的内存不够用的时候,系统会回收处于后台的Activity的资源以避免OOM。

采用传统的MV模式,一大堆异步任务和对UI的操作都放在Activity里面,比如你可能从网络下载一张图片,在下载成功的回调里把图片加载到 Activity 的 ImageView 里面,所以异步任务保留着对Activity的引用。这样一来,即使Activity已经被切换到后台(onDestroy已经执行),这些异步任务仍然保留着对Activity实例的引用,所以系统就无法回收这个Activity实例了,结果就是Activity Leak。Android的组件中,Activity对象往往是在堆(Java Heap)里占最多内存的,所以系统会优先回收Activity对象,如果有Activity Leak,APP很容易因为内存不够而OOM。

采用MVP模式,只要在当前的Activity的onDestroy里,分离异步任务对Activity的引用,就能避免 Activity Leak。

MVC与MVP最明显的区别就是,MVC中是允许Model和View进行交互的,而MVP中很明显,Model与View之间的交互由Presenter完成。
还有一点就是Presenter与View之间的交互是通过接口的

实例代码说明
  • HomeActivity.class
public class HomeActivity extends AppCompatActivity {

    private HomePresenter mAddEditTaskPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addtask_act);

        // Set up the toolbar.
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        HomeFragment addEditTaskFragment = (HomeFragment) getSupportFragmentManager()
                .findFragmentById(R.id.contentFrame);

        if (addEditTaskFragment == null) {
            addEditTaskFragment = HomeFragment.newInstance();
            ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
                    addEditTaskFragment, R.id.contentFrame);
        }
//        // Create the presenter
        mAddEditTaskPresenter = new HomePresenter(addEditTaskFragment);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab_edit_task_done);
        fab.setImageResource(R.drawable.ic_logs);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Snackbar.make(v, "跳转到LOG页面", Snackbar.LENGTH_LONG).show();
                startActivity(new Intent(HomeActivity.this, LogActivity.class));
            }
        });

    }
}
  • HomeContract.class
public interface HomeContract {

    interface View {
        void showToast(String msg);
    }

    interface Presenter{
        void showToast(String msg);
    }
}
  • HomePresenter.class
public class HomePresenter implements HomeContract.Presenter {


    @NonNull
    private final HomeContract.View mAddTaskView;

    /**
     * Creates a presenter for the add/edit view.
     *
     * @param addTaskView the add/edit view
     */
    public HomePresenter(@NonNull HomeContract.View addTaskView) {
        mAddTaskView = checkNotNull(addTaskView);
        mAddTaskView.setPresenter(this);
    }

    @Override
    public void share(String msg) {
        mAddTaskView.showToast(msg);
    }
}
  • HomeFragment.class
public class HomeFragment extends Fragment implements HomeContract.View {

    private HomeContract.Presenter mPresenter;
    @BindView(R.id.button4)
    public Button button4;

    public static HomeFragment newInstance() {
        return new HomeFragment();
    }

    public HomeFragment() {

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.addtask_frag, container, false);
        unbinder = ButterKnife.bind(this, root);
        return root;
    }


    @Override
    public void setPresenter(@NonNull HomeContract.Presenter presenter) {
        mPresenter = checkNotNull(presenter);
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

    @Override
    public void showToast(@NonNull String msg) {
        Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT).show();
    }

    @OnClick({R.id.button4})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button4:
                mPresenter.showTost("MVP模式显示Tost");
                break;
        }
    }
}
  • addtask_act.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/colorPrimary"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/Toolbar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </android.support.design.widget.AppBarLayout>

        <android.support.design.widget.CoordinatorLayout
            android:id="@+id/coordinatorLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <FrameLayout
                android:id="@+id/contentFrame"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <android.support.design.widget.FloatingActionButton
                android:id="@+id/fab_edit_task_done"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_margin="@dimen/fab_margin"
                app:srcCompat="@android:drawable/ic_dialog_email"
                app:fabSize="normal"
                app:layout_anchor="@id/contentFrame"
                app:layout_anchorGravity="bottom|right|end" />
        </android.support.design.widget.CoordinatorLayout>

    </LinearLayout>

</android.support.v4.widget.DrawerLayout>
  • addtask_frag.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
        <Button
            android:id="@+id/button4"
            android:layout_width="0dp"
            android:layout_height="60dp"
            android:layout_weight="1"
            android:text="屏幕" />

</LinearLayout>

相关文章

网友评论

      本文标题:Android-MVP使用beta

      本文链接:https://www.haomeiwen.com/subject/bqlhpctx.html