android学习笔记-MVP实例
最近在疯狂学习mvp架构,看了一堆博文也没整明白,最后还是谷歌的官方案例给整明白了,遂整理记录,有错误的地方,还请大神们指教。
mvp基本结构如图,view持有presenter,presenter持有view和model,presenter通过持有的model存取数据,通过持有的view获取view中的数据,或改变view的ui显示。可以看到view中有个set方法,主要是方便外部注入presenter实例,这里是通过presenter中持有的view来调用setpresenter()将presenter自己的实例注入到view中去,至于原因请看这里。最后实现了view和model的解耦,所有的业务逻辑都放在presenter内操作,和view解耦,view只负责ui的展示。
这里以简单的login界面距离介绍。为了简介起见,所有的layout和jdbc相关的操作都不作具体展示。首先是java文件,如下:
首先定义三个接口,代表mvp三个模块,然后用一个contract接口来管理,之后是三个实现类,这里fragment对应的是view,而activity只用来做一些初始化操作。最后需要一个user的pojo,便于从数据库存取数据。具体代码如下:
1、User
public class User {
private Integer id;
private String name;
private String password;
public User(Integer id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public User(){}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
没啥好说,属性对应的数据库列属性,其他方法都自动生成
2、Base
public interface BaseModel<T> {
T loadModel(Context context, String name);
void saveModel(T model);
}
public interface BasePresenter {
void start() throws ExecutionException, InterruptedException;
}
public interface BaseView<T> {
void setPresenter(T presenter);
}
最*抽象
3、contract
public interface LoginContract {
interface View extends BaseView<Presenter> {
void setProgressIndicator(boolean active);
String getName();
String getPassword();
void setName(String name);
void setPassword(String psw);
void showToast(String text);
}
interface Presenter extends BasePresenter{
}
}
扩展了一些方法,用contract管理
4、activity
public class LoginActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
LoginFragment loginFragment = new LoginFragment();
ActivityUtil.addFragmentToActivity(getSupportFragmentManager(),loginFragment,R.id.loginfrm);
//初始化整个mvp架构
new LoginPresenter(loginFragment,new LoginModel(),this);
}
}
只做初始化,绑定fragmnet
5、view
public class LoginFragment extends Fragment implements LoginContract.View{
// 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 LoginContract.Presenter mPresenter;
private EditText nameEdit;
private EditText pswEdit;
private Button loginButton;
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public LoginFragment() {
// 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 LoginFragment.
*/
// TODO: Rename and change types and number of parameters
public static LoginFragment newInstance(String param1, String param2) {
LoginFragment fragment = new LoginFragment();
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 View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View root = inflater.inflate(R.layout.fragment_login, container, false);
nameEdit = root.findViewById(R.id.name);
pswEdit = root.findViewById(R.id.psw);
loginButton = root.findViewById(R.id.bt_login);
loginButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
try {
mPresenter.start();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
return root;
}
@Override
public void setProgressIndicator(boolean active) {
}
@Override
public String getName() {
return nameEdit.getText().toString();
}
@Override
public String getPassword() {
return pswEdit.getText().toString();
}
@Override
public void setName(String name) {
}
@Override
public void setPassword(String psw) {
}
@Override
public void setPresenter(LoginContract.Presenter presenter) {
this.mPresenter = presenter;
}
public void showToast(String text){
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
}
}
没用到的方法先不管,两个edittext,一个button,两个get方法方便presenter取数据,一个showToast方法显示状态,按下button启动presenter
6、model
public class LoginModel implements BaseModel {
private User mUser;
private SharedPreferences mPrefs;
private Query mQuery;
LoginModel(){
mUser = new User();
mQuery = QueryFactory.createMysqlQuery();
}
@Override
public User loadModel(Context context, String name) {
//根据用户名返回user对象
List list = mQuery.queryRows(context,"select * from user where name=?",User.class,new Object[]{name});
if(list.size()==0){
return new User();
}
return (User)list .get(0);
}
@Override
public void saveModel(Object model) {
mQuery.insert(model);
}
}
同样没用到的属性和方法先不管,关键是一个query对象,主要是管理jdbc操作数据库的,然后根据username查找并返回给presenter
7、presenter
public class LoginPresenter implements LoginContract.Presenter{
private LoginContract.View mView;
private LoginModel mModel;
private Context mContext;
public LoginPresenter(LoginContract.View loginView,LoginModel loginModel,Context context){
mView = loginView;
mModel = loginModel;
mContext = context;
loginView.setPresenter(this);
}
@Override
public void start() throws ExecutionException, InterruptedException {
User remoteUser = new User();
Thread loadThread = new Thread(new Runnable(){
@Override
public void run() {
User user = mModel.loadModel(mContext,mView.getName());
remoteUser.setId(user.getId());
remoteUser.setName(user.getName());
remoteUser.setPassword(user.getPassword());
}
});
loadThread.start();
loadThread.join();
User typeUser = new User();
typeUser.setName(mView.getName());
typeUser.setPassword(mView.getPassword());
int state = checkValid(typeUser,remoteUser);
switch (state){
case 0:
mView.showToast("登录成功!");
break;
case 1:
mView.showToast("用户名不存在!");
break;
case 2:
mView.showToast("密码错误!");
break;
case 3:
mView.showToast("请输入用户名!");
break;
case 4:
mView.showToast("请输入密码!");
break;
}
}
private int checkValid(User typeUser,User remoteUser){
String typeName = typeUser.getName();
String typePSW = typeUser.getPassword();
String remoteName = remoteUser.getName();
String remotePsw = remoteUser.getPassword();
if(typeName.equals("")){
return 3;
}
if(typePSW.equals("")){
return 4;
}
if(remoteName==null){
return 1;
}
if(remotePsw!=null&&!typePSW.equals(remotePsw)){
return 2;
}
return 0;
}
}
presenter分别从view和model两边接收两个user对象,并作比较,从而显示登录状态提示
上一篇: 白盒测试案例分析(在十个球中找一个假球),并在Junit下进行测试
下一篇: C++——类与对象