练习Demo要求:
UI:
1、在EditText输入用户名,点击保存,数据存储到SharedPreferences;
2、点击查看,从SharedPreferences中取出数据,并显示在TextView中。
效果:
分析:
一、该练习的核心功能是“保存”和“查看”,这两个功能都有涉及到数据操作,遂该部分属于Model层,所以定义接口类UserDataModel:
public interface UserDataModel {
void writeUserDate(Context context, String userName, OnUserDataListener userDataListener);//保存数据操作 OnUserDataListener 起到回调作用
void readUserDate(Context context,OnUserDataListener userDataListener);//查看数据操作
}
再定义接口实现类UserDataModelImpl,来实现保存和查看用户名功能:
public class UserDataModelImpl implements UserDataModel {
private boolean isSuccess;//保存用户名是否成功
/**
* 保存用户名
* @param context
* @param userName
* @param userDataListener
*/
@Override
public void writeUserDate(Context context, String userName, OnUserDataListener userDataListener) {
//若操作大量数据,会很耗时间,所以在此可以在子线程中完成数据操作
SharedPreferences sp = context.getSharedPreferences("sp_user_data", Context.MODE_PRIVATE);
isSuccess = sp.edit().putString("name", userName).commit();//数据保存操作
if(isSuccess){
userDataListener.onSuccess("添加用户 "+userName+" 成功!","save");//回调存储结果状态
}else {
userDataListener.onFail("添加用户 "+userName+" 失败!","save");
}
}
/**
* 查看数据
* @param context
* @param userDataListener
*/
@Override
public void readUserDate(Context context, OnUserDataListener userDataListener) {
SharedPreferences sp = context.getSharedPreferences("sp_user_data", Context.MODE_PRIVATE);
String userName = sp.getString("name", null);
if(userName!=null && userName.length()>0){
userDataListener.onSuccess("用户名: "+userName,"read");
}else {
userDataListener.onFail("用户名为空!","read");
}
}
}
二、Model层完成后,下面来看Presenter层,它是连接View和Model的中间人,所以它里面既要包含View的接口类,也要包含Presenter的接口类,在此基础上,还需要另外一个接口类OnUserDataListener,它起到将回调结果传给Presenter的作用。OnUserDataListener接口类,包含成功接口和失败接口,对应数据操作成功时调用和数据操作失败时调用。
public interface OnUserDataListener {//起到回调作用
void onSuccess(String str,String flag);//flag表示是保存操作还是查看操作
void onFail(String str,String flag);
}
再看下UserDatePresenter接口类,Presenter层通过实现UserDatePresenter接口,来向Model层发出传递数据信号,根据该练习的功能要求分别定义两个接口setUserDara和getUserDara,分别对应保存数据和查看数据:
public interface UserDatePresenter {
void setUserDara(String userName);//传递用户名数据给model层
void getUserDara();
}
最后来实现所有的接口,定义UserDatePresenterImpl类:
public class UserDatePresenterImpl implements UserDatePresenter, OnUserDataListener {
//1、包含View层和Model层这两部分的接口类
private UserDataModel userDataModel;//Model层接口类
private UserDataView userDataView;//View层接口类
private Context context;
public UserDatePresenterImpl(Context context,UserDataView userDataView){//2、实例化UserDatePresenterImpl类
this.context = context;
this.userDataView = userDataView;//a、接过View层传来的接口实体类,此时将View和Presenter连接
userDataModel = new UserDataModelImpl();//b、创建Model层接口实体类,此时将Presenter与Model连接,这样View——》Presenter——》Model便连接在了一起
}
/*
3、实现UserDatePresenter接口,用于将数据或操作信号传递给Model层
*/
@Override
public void setUserDara(String userName) {//保存用户名数据
userDataModel.writeUserDate(context,userName,this);
}
@Override
public void getUserDara() {//查看用户名数据
userDataModel.readUserDate(context,this);
}
/*
4、实现OnUserDataListener回调接口类,用于Model层回调结果的处理,根据回调结果刷新UI
(对于大量数据刷新UI,应将其在UI线程中执行)
*/
@Override
public void onSuccess(String str,String flag) {//数据操作成功回调
if(flag.equals("save")){//当flag是save时,表示是保存数据操作,当保存成功后弹出Toast,提示保存成功
userDataView.showResultDataToast(str);
}else {//当flag是read时,表示是查看数据操作,当成功查出用户名后,在TextView中显示出来
userDataView.showResultDataTextView(str);
}
}
@Override
public void onFail(String str,String flag) {
if(flag.equals("save")){
userDataView.showResultDataToast(str);
}else {
userDataView.showResultDataTextView(str);
}
}
}
三、最后来看View层,它只涉及与用户进行数据交互(输入)以及数据的展示,所以定义UserDataView接口类,提供Presenter层对View的操作:
public interface UserDataView {
void showResultDataTextView(String resultData);//TextView方式展示数据
void showResultDataToast(String resultData);//Toast方式展示数据
}
View层通常是Activity或Fragment,所以在此来实现接口方法,以便于Presenter层调用:
public class MainActivity extends Activity implements UserDataView, View.OnClickListener {
private EditText userNameET;
private Button saveBT,readBT;
private TextView userNameTV;
private UserDatePresenter userDatePresenter;//1、在此引用UserDatePresenter接口类,使View和Presenter连接在一起
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//view初始化
}
private void initView(){
userNameET = (EditText) findViewById(R.id.userNameET);
saveBT = (Button) findViewById(R.id.saveBT);
readBT = (Button) findViewById(R.id.readBT);
userNameTV = (TextView) findViewById(R.id.userNameTV);
saveBT.setOnClickListener(this);
readBT.setOnClickListener(this);
context = getApplicationContext();
userDatePresenter = new UserDatePresenterImpl(context,this);//2、实例化接口类
}
/*
3、向Presenter层传递数据或操作信号
*/
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.saveBT:
if((userNameET.getText().toString())!=null && (userNameET.getText().toString()).length()>0){
userDatePresenter.setUserDara(userNameET.getText().toString());//传递用户名数据
}else {
Toast.makeText(context,"用户名不能为空!",Toast.LENGTH_SHORT).show();
}
break;
case R.id.readBT:
userDatePresenter.getUserDara();//传递查看用户名数据信号
break;
}
}
/*
4、实现UserDataView接口方法,用于Presenter层操作View
*/
@Override
public void showResultDataTextView(String resultData) {
userNameTV.setText(resultData);
}
@Override
public void showResultDataToast(String resultData) {
Toast.makeText(context,resultData,Toast.LENGTH_SHORT).show();
userNameTV.setText("");
userNameET.setText("");
}
}
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="wzz.a2017wzzmvp2.view.MainActivity">
<EditText
android:id="@+id/userNameET"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名"/>
<Button
android:id="@+id/saveBT"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="保存"/>
<Button
android:id="@+id/readBT"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查看"/>
<TextView
android:id="@+id/userNameTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
时序图如下: