高效的使用MVP

来源:互联网 发布:为什么安装不了知乎 编辑:程序博客网 时间:2024/05/16 03:20

(1)说明

写mvp的时候,presenter会持有view,如果presenter有后台异步的长时间的动作,比如网络请求,这时如果返回退出了Activity,后台异步的动作不会立即停止,这里就会有内存泄漏的隐患,所以会在presenter中加入一个销毁view的方法。但是当后台的延时操作返回时,这个时候view被销毁了,如果接着去调用view的方法就 会抛出空指针异常。所以在后台的延时操作中需要考虑到这种可能产生空指针的情况,尤其是网络请求。

(2)创建基类和使用

①   Presenter

如果每一个Activity都需要做绑定和解绑操作就太麻烦,现在可以用一个通用的presenter来为我们添加view的绑定与销毁。

public abstract class BasePresenter<T> {

    public mView;

    public void attach(mView) {
        this.mView = mView;
    }

    public void dettach() {
        mView null;
    }
}

因为不能限定死传入的View,所以使用泛型来代替传入的对象。通过这个通用的presenter可以把原来的LoginPresenter简化成下面的样子。

public class LoginPresenter extends BasePresenter<LoginView>{

    private final LoginData loginData;
    private Handler mHandler;

    public LoginPresenter() {
        loginData new LoginData();
        mHandler new Handler();
    }

    public void login() {
        //点击登录时
        
if (TextUtils.isEmpty(mView.getUserName())){
            mView.showFailedError("请输入用户名");
        }else if (TextUtils.isEmpty(mView.getPassword())){
            mView.showFailedError("请输入密码");
        }else {

            mView.showLoading();
            loginData.login(mView.getUserName(), mView.getPassword(), new GetNetListener() {
                @Override
                
public void loginSuccess(Stringrequest) {
                    //需要在UI线程执行
                    
mHandler.post(new Runnable() {
                        @Override
                        
public void run() {
                            mView.hideLoading();
                            mView.toMainActivity();
                        }
                    });
                }

                @Override
                
public void loginFailed(final String err) {
                    mHandler.post(new Runnable() {
                        @Override
                        
public void run() {
                            mView.hideLoading();
                            mView.showFailedError(err);
                        }
                    });
                }
            });
        }

    }

    public void toPassWroad() {
        //修改密码界面
        
mView.toPassWroad();
    }

②  View

界面需要提供的UI方法中会有很多类似的UI方法,可以把它们提取到一个公共的父类接口中。比如提取显示loading界面和隐藏loading界面的方法,其他的view层接口就可以直接继承BaseView接口,不必重复的写显示和隐藏loading界面方法。

public interface BaseView {
    void showLoading();
    void hideLoading();
}

具体实现类

public interface LoginView extends BaseView {
    String getUserName();
    String getPassword();
    void clearUserName();
    void clearPassword();
    void toMainActivity();
   void showFailedError(String message);
    void toPassWroad();
}

presenter绑定到activity和View的绑定和解绑操作是每个Activity都会去做的,同样这里我也希望能有一个父类来完成这个统一的操作。

public class LoginActivity extends BaseActivity<LoginView,LoginPresenter> implements LoginView {

    private EditText etUsername;
    private EditText etPassword;
    private LinearLayout llForgetpass;
    private Button btLogin;
    private LinearLayout llLoginQuan;

    @Override
    
public void initView() {
        setContentView(R.layout.activity_login);
        etUsername = (EditText)findViewById(R.id.et_username);
        etPassword = (EditText)findViewById(R.id.et_password);
        llForgetpass = (LinearLayout)findViewById(R.id.ll_forgetpass);
        btLogin = (Button)findViewById(R.id.bt_login);
        llLoginQuan = (LinearLayout)findViewById(R.id.ll_login_quan);

    }

    @Override
    
public void initData() {

        btLogin.setOnClickListener(new View.OnClickListener(){
            @Override
            
public void onClick(View v) {
                presenter.login();
            }
        });
        llForgetpass.setOnClickListener(new View.OnClickListener(){
            @Override
            
public void onClick(View v) {
                presenter.toPassWroad();
            }
        });

    }

    @Override
    
public LoginPresenterinitPresenter() {
        return new LoginPresenter();
    }

    @Override
    
public StringgetUserName() {
        return etUsername.getText().toString().trim();
    }

    @Override
    
public String getPassword(){
        return etPassword.getText().toString().trim();
    }

    @Override
    
public void clearUserName() {
        etUsername.setText("");

    }

    @Override
    
public void clearPassword() {
        etPassword.setText("");
    }

    @Override
    
public void toMainActivity() {
        startActivity(new Intent(this, MainActivity.class));
    }

    @Override
    
public void showFailedError(Stringmessage) {
        Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    
public void toPassWroad() {
        startActivity(new Intent(LoginActivity.this,ForgetPassActivity.class));
    }

    @Override
    
public void showLoading() {
        llLoginQuan.setVisibility(View.VISIBLE);
    }

    @Override
    
public void hideLoading() {
        llLoginQuan.setVisibility(View.GONE);
    }

}

③model

监听网络请求

public interface GetNetListener {
    //请求成功的监听
    
void loginSuccess(Stringrequest);
    //请求失败的监听
    
void loginFailed(Stringerr);
}

/**
 * Created by ylzx on 2016/12/21.
 * 
请求网络的方法
 
*/
public abstract class GetNet {
    //登录接口
    
public void login(Stringusername, String password, GetNetListener loginListener){};

}

/**
 * Created by ylzx on 2016/12/21.
 * 
请求网络
 
*/
public class LoginData extends GetNet {
    public  String TAG="LoginData";
    private GetNetListener mLoginListener;

    @Override
    
public void login(Stringusername, String password, GetNetListener loginListener) {

        this.mLoginListener = loginListener;
        //网络请求
        
try {

            HashMap<String, String>sortedParams = new HashMap<String, String>();
            
sortedParams.put("accountID", username);
     
            OkHttpUtils
                    .post()
                    .url(url)
                    .params(params)
                    .build()
                    .execute(new MyStringCallback());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class MyStringCallback extends StringCallback {
        @Override
        
public void onError(Call call,Exception e, int id) {
            mLoginListener.loginFailed(e.toString());
        }

        @Override
        
public void onResponse(Stringresponse, int id) {

            BaseModel baseModel =GsonUtil.jsonToBean(response, BaseModel.class);

            if (baseModel.isFlag()){
//成功
                
mLoginListener.loginSuccess(response);

            } else {
                //错误时
                
mLoginListener.loginFailed(baseModel.getErrorMsg());
            }

        }
    }


}

 

4.高效的使用MVP

(1)说明

写mvp的时候,presenter会持有view,如果presenter有后台异步的长时间的动作,比如网络请求,这时如果返回退出了Activity,后台异步的动作不会立即停止,这里就会有内存泄漏的隐患,所以会在presenter中加入一个销毁view的方法。但是当后台的延时操作返回时,这个时候view被销毁了,如果接着去调用view的方法就 会抛出空指针异常。所以在后台的延时操作中需要考虑到这种可能产生空指针的情况,尤其是网络请求。

(2)创建基类和使用

 

①   Presenter

如果每一个Activity都需要做绑定和解绑操作就太麻烦,现在可以用一个通用的presenter来为我们添加view的绑定与销毁。

public abstract class BasePresenter<T> {

    public mView;

    public void attach(mView) {
        this.mView = mView;
    }

    public void dettach() {
        mView null;
    }
}

因为不能限定死传入的View,所以使用泛型来代替传入的对象。通过这个通用的presenter可以把原来的LoginPresenter简化成下面的样子。

public class LoginPresenter extends BasePresenter<LoginView>{

    private final LoginData loginData;
    private Handler mHandler;

    public LoginPresenter() {
        loginData new LoginData();
        mHandler new Handler();
    }

    public void login() {
        //点击登录时
        
if (TextUtils.isEmpty(mView.getUserName())){
            mView.showFailedError("请输入用户名");
        }else if (TextUtils.isEmpty(mView.getPassword())){
            mView.showFailedError("请输入密码");
        }else {

            mView.showLoading();
            loginData.login(mView.getUserName(), mView.getPassword(), new GetNetListener() {
                @Override
                
public void loginSuccess(Stringrequest) {
                    //需要在UI线程执行
                    
mHandler.post(new Runnable() {
                        @Override
                        
public void run() {
                            mView.hideLoading();
                            mView.toMainActivity();
                        }
                    });
                }

                @Override
                
public void loginFailed(final String err) {
                    mHandler.post(new Runnable() {
                        @Override
                        
public void run() {
                            mView.hideLoading();
                            mView.showFailedError(err);
                        }
                    });
                }
            });
        }

    }

    public void toPassWroad() {
        //修改密码界面
        
mView.toPassWroad();
    }

②  View

界面需要提供的UI方法中会有很多类似的UI方法,可以把它们提取到一个公共的父类接口中。比如提取显示loading界面和隐藏loading界面的方法,其他的view层接口就可以直接继承BaseView接口,不必重复的写显示和隐藏loading界面方法。

public interface BaseView {
    void showLoading();
    void hideLoading();
}

具体实现类

public interface LoginView extends BaseView {
    String getUserName();
    String getPassword();
    void clearUserName();
    void clearPassword();
    void toMainActivity();
   void showFailedError(String message);
    void toPassWroad();
}

presenter绑定到activity和View的绑定和解绑操作是每个Activity都会去做的,同样这里我也希望能有一个父类来完成这个统一的操作。

public class LoginActivity extends BaseActivity<LoginView,LoginPresenter> implements LoginView {

    private EditText etUsername;
    private EditText etPassword;
    private LinearLayout llForgetpass;
    private Button btLogin;
    private LinearLayout llLoginQuan;

    @Override
    
public void initView() {
        setContentView(R.layout.activity_login);
        etUsername = (EditText)findViewById(R.id.et_username);
        etPassword = (EditText)findViewById(R.id.et_password);
        llForgetpass = (LinearLayout)findViewById(R.id.ll_forgetpass);
        btLogin = (Button)findViewById(R.id.bt_login);
        llLoginQuan = (LinearLayout)findViewById(R.id.ll_login_quan);

    }

    @Override
    
public void initData() {

        btLogin.setOnClickListener(new View.OnClickListener(){
            @Override
            
public void onClick(View v) {
                presenter.login();
            }
        });
        llForgetpass.setOnClickListener(new View.OnClickListener(){
            @Override
            
public void onClick(View v) {
                presenter.toPassWroad();
            }
        });

    }

    @Override
    
public LoginPresenterinitPresenter() {
        return new LoginPresenter();
    }

    @Override
    
public StringgetUserName() {
        return etUsername.getText().toString().trim();
    }

    @Override
    
public String getPassword(){
        return etPassword.getText().toString().trim();
    }

    @Override
    
public void clearUserName() {
        etUsername.setText("");

    }

    @Override
    
public void clearPassword() {
        etPassword.setText("");
    }

    @Override
    
public void toMainActivity() {
        startActivity(new Intent(this, MainActivity.class));
    }

    @Override
    
public void showFailedError(Stringmessage) {
        Toast.makeText(LoginActivity.this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    
public void toPassWroad() {
        startActivity(new Intent(LoginActivity.this,ForgetPassActivity.class));
    }

    @Override
    
public void showLoading() {
        llLoginQuan.setVisibility(View.VISIBLE);
    }

    @Override
    
public void hideLoading() {
        llLoginQuan.setVisibility(View.GONE);
    }

}

③model

监听网络请求

public interface GetNetListener {
    //请求成功的监听
    
void loginSuccess(Stringrequest);
    //请求失败的监听
    
void loginFailed(Stringerr);
}

/**
 * Created by ylzx on 2016/12/21.
 * 
请求网络的方法
 
*/
public abstract class GetNet {
    //登录接口
    
public void login(Stringusername, String password, GetNetListener loginListener){};

}

/**
 * Created by ylzx on 2016/12/21.
 * 
请求网络
 
*/
public class LoginData extends GetNet {
    public  String TAG="LoginData";
    private GetNetListener mLoginListener;

    @Override
    
public void login(Stringusername, String password, GetNetListener loginListener) {

        this.mLoginListener = loginListener;
        //网络请求
        
try {

            HashMap<String, String>sortedParams = new HashMap<String, String>();
            // sysNo   3des加密
            
sortedParams.put("accountID", username);
            sortedParams.put("pwd", MD5Util.md5(password));
            final String url =BaseInfo.URL "enterpriseEmployee/employeeLogin.do";
            sortedParams.put("access_token", BaseInfo.ACCESS_TOKEN);//固定传参
            
String sign =SignUtils.sign(BaseInfo.SERVICEKEY, sortedParams);
            Map<String, String>params = new HashMap<String, String>();
            params.put("appid""600000");
            params.put("sign_type""APP");
            params.put("sign", sign);

            for (Map.Entry<String,String> entry : sortedParams.entrySet()) {
               params.put(entry.getKey(), URLEncoder.encode(DES3Util.encode(entry.getValue(),BaseInfo.SERVICEKEY)));
            }

            OkHttpUtils
                    .post()
                    .url(url)
                    .params(params)
                    .build()
                    .execute(new MyStringCallback());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class MyStringCallback extends StringCallback {
        @Override
        
public void onError(Call call,Exception e, int id) {
            mLoginListener.loginFailed(e.toString());
        }

        @Override
        
public void onResponse(Stringresponse, int id) {

            BaseModel baseModel =GsonUtil.jsonToBean(response, BaseModel.class);

            if (baseModel.isFlag()){
//成功
                
mLoginListener.loginSuccess(response);

            } else {
                //错误时
                
mLoginListener.loginFailed(baseModel.getErrorMsg());
            }

        }
    }


}

 

0 0
原创粉丝点击