Android MVP简单例子

MVP
M:数据请求
V:视图
P:M和V交互的桥梁

MVP模式的好处:
1.View与Model完全隔离。
2.利于维护。
3.利于写单元测试

弊:
代码多。

简单的登录例子


image.png

首先回调接口:

public interface CallBack {
    //成功返回
    void onSuccess();
    //失败返回
    void onFilure(String msg);
}

M层:
接口

public interface IUserModel {
    void login(String user, String pwd, CallBack callBack);
}

实现IUserModel接口,延迟发送来模范访问网络

public class UserModel implements IUserModel {
    private Handler handler=new Handler(Looper.getMainLooper());
    @Override
    public void login(final String user, final String pwd, final CallBack callBack) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (user.equals("123456") && pwd.equals("123456")){
                    callBack.onSuccess();
                }else {
                    callBack.onFilure("账号或密码错误");
                }
            }
        },2000 );
    }
}

V层
接口LoginView继承BaseMvpView接口,LoginView接口可以根据自己的需要去定义。

public interface BaseMvpView {
    //显示等待框
    void showLoding(String msg);
    //隐藏等待框
    void hideLoding();
    //错误信息
    void showerr(String err);
}
public interface LoginView extends BaseMvpView{
    //成功返回信息
    void showResult(String msg);
    //Toast信息
    void showToast(String msg);
}

P层

public class BaseMvpPresenter<V extends BaseMvpView> implements Presenter<V> {
    private V mvpView;
    @Override
    public void attachView(V mvpView) {
        this.mvpView = mvpView;
    }

    @Override
    public void deachView() {
        mvpView = null;
    }

    /**
     * 判断 view是否为空
     * @return
     */
    public  boolean isAttachView(){
        return mvpView != null;
    }
    /**
     * 返回目标view
     * @return
     */
    public  V getMvpView(){
        return mvpView;
    }
    /**
     * 检查view和presenter是否连接
     */
    public void checkViewAttach(){
        if(! isAttachView()){
            throw  new MvpViewNotAttachedException();
        }
    }
    /**
     * 自定义异常
     */
    public static   class  MvpViewNotAttachedException extends RuntimeException {
        public MvpViewNotAttachedException() {
            super("请求数据前请先调用 attachView(MvpView) 方法与View建立连接");
        }
    }
}

BaseMvpPresenter类主要是处理P层的一些错误,例如view销毁了,但是p层还在调用v层的方法,就会导致空指针。

ILoginPresenter 定义一个接口

public interface ILoginPresenter {
    void login(String user,String pwd);
}

LoginPresenter 类实现ILoginPresenter 接口,在login里面接受MainActivity传过来的值,做校验处理,通过 userModel.login传数据过去M层做网络处理,然后通过CallBack回调,调用 loginView.showResult("登录成功");把结果返回给Activity.

public class LoginPresenter extends BaseMvpPresenter<LoginView> implements ILoginPresenter {
    private UserModel userModel;

    public LoginPresenter(UserModel userModel) {
        this.userModel = userModel;
    }

    @Override
    public void login(String user, String pwd) {
        checkViewAttach();//检查是否绑定
        //获取View实例
        final LoginView loginView = getMvpView();
        if (user.length() == 0 && pwd.length() == 0) {
            loginView.showToast("账号密码不能为空");
        } else {
            loginView.showLoding("正在登录");
            userModel.login(user, pwd, new CallBack() {
                @Override
                public void onSuccess() {
                    loginView.hideLoding();
                    loginView.showResult("登录成功");
                }

                @Override
                public void onFilure(String msg) {
                    loginView.hideLoding();
                    loginView.showerr(msg);
                }
            });
        }
    }
}

Activity实现LoginView接口

public class MainActivity extends AppCompatActivity implements LoginView {
    private LoginPresenter loginPresenter;
    private ProgressDialog progressDialog;
    private EditText et1, et2;
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        loginPresenter = initPresenter();
        loginPresenter.attachView(this);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                loginPresenter.login(et1.getText().toString().trim(), et2.getText().toString().trim());
            }
        });
    }

    public LoginPresenter initPresenter() {
        return new LoginPresenter(new UserModel());
    }

    private void initView() {
        et1 = findViewById(R.id.et1);
        et2 = findViewById(R.id.et2);
        btn = findViewById(R.id.btn);
        progressDialog = new ProgressDialog(this);
    }

    @Override
    public void showResult(String msg) {
        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
    }

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

    @Override
    public void showLoding(String msg) {
        progressDialog.setMessage(msg);
        if (!progressDialog.isShowing())
            progressDialog.show();
    }

    @Override
    public void hideLoding() {
        if (progressDialog.isShowing())
            progressDialog.dismiss();
    }

    @Override
    public void showerr(String err) {
        Toast.makeText(getApplicationContext(), err, Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        loginPresenter.deachView();
    }
}
123.gif

MVP RecyclerView 简单实例


image.png

回调 CallBack2,跟上面不同,加了泛型,因为要返回实体类。

public interface CallBack2<T> {
    //成功返回
    void onSuccess(T t);
    //失败返回
    void onFilure(String msg);
}

M层
接口没什么好说的,就一个获取数据的接口,回调参数

public interface IMain2Model {
    void getData( CallBack2<mybean> callBack);
}

模仿网络操作

public class Main2Model implements IMain2Model {
    private Handler handler = new Handler(Looper.getMainLooper());
    @Override
    public void getData(final CallBack2<mybean> callBack) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                String string = "{\n" +
                        "  \"students\": [\n" +
                        "    {\n" +
                        "      \"name\": \"jadyli\",\n" +
                        "      \"gender\": \"male\",\n" +
                        "      \"age\": 18\n" +
                        "    },\n" +
                        "    {\n" +
                        "      \"name\": \"Juliet\",\n" +
                        "      \"gender\": \"female\",\n" +
                        "      \"age\": 20\n" +
                        "    }\n" +
                        "  ]\n" +
                        "}";
                final mybean mybean = new Gson().fromJson(string, mybean.class);
                for (int i=0;i<mybean.getStudents().size();i++){
                    callBack.onSuccess(mybean);
                }
            }
        }, 1000);
    }
}

V层
接口

public interface Main2View<T> extends BaseMvpView {
    //成功返回信息
    void showResult(T t);
    //Toast信息
    void showToast(String msg);
}

P层
接口

public interface IMain2Presenter {
    void getData();
}

基本跟登录的一样

public class Main2Presenter extends BaseMvpPresenter<Main2View> implements IMain2Presenter {
    private Main2Model main2Model;

    public Main2Presenter(Main2Model main2Model) {
        this.main2Model = main2Model;
    }

    public void getData() {
        checkViewAttach();//检查是否绑定
        final Main2View main2View = getMvpView();
        main2View.showLoding("正在加载数据");
        main2Model.getData(new CallBack2<mybean>() {
            @Override
            public void onSuccess(mybean mybean) {
                main2View.showResult(mybean);
            }

            @Override
            public void onFilure(String msg) {

            }
        });
    }
}

Main2Activity代码

public class Main2Activity extends AppCompatActivity implements Main2View {
    private static final String TAG = "Main2Activity";
    private RecyclerView rv;
    private ProgressDialog progressDialog;
    private List<mybean> list;
    private MyAdapter adapter;
    private LinearLayoutManager manager;
    private Main2Presenter presenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        list = new ArrayList<>();
        initView();
        presenter = initPresenter();
        presenter.attachView(this);
        presenter.getData();
    }

    private void initView() {
        rv = findViewById(R.id.rv);
        progressDialog = new ProgressDialog(this);
    }


    @Override
    public void showResult(Object o) {
        mybean mybean = (com.gzfyit.mvp3.mybean.mybean) o;
        list.add(mybean);
        Log.e(TAG, "showResult: " + list);
        adapter = new MyAdapter(getApplicationContext(), list);
        manager = new LinearLayoutManager(getApplicationContext());
        rv.setLayoutManager(manager);
        rv.setAdapter(adapter);
    }

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

    }

    @Override
    public void showLoding(String msg) {
        progressDialog.setMessage(msg);
        if (!progressDialog.isShowing())
            progressDialog.show();
    }

    @Override
    public void hideLoding() {
        if (progressDialog.isShowing())
            progressDialog.dismiss();
    }

    @Override
    public void showerr(String err) {
        Toast.makeText(getApplicationContext(), err, Toast.LENGTH_SHORT).show();
    }

    public Main2Presenter initPresenter() {
        return new Main2Presenter(new Main2Model());
    }
}

MyAdapter

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private static final String TAG = "MyAdapter";
    private Context context;
    private List<mybean> list;

    public MyAdapter(Context context, List<mybean> list) {
        this.context = context;
        this.list = list;
    }

    @NonNull
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
        Log.e(TAG, "onBindViewHolder: " + list.size());
        mybean mybean = list.get(position);
        holder.tv_num.setText(mybean.getStudents().get(position).getName());
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv_num;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tv_num = itemView.findViewById(R.id.tv_num);
        }
    }
}
123.gif
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容