【从 0 开始开发一款直播 APP】5.1 MVP 完全解析 -- 实现直播登录

本文为菜鸟窝作者蒋志碧的连载。“从 0 开始开发一款直播 APP ”系列来聊聊时下最火的直播 APP,如何完整的实现一个类"腾讯直播"的商业化项目
视频地址:http://www.cniao5.com/course/10121


【从 0 开始开发一款直播 APP】5.1 MVP 完全解析 -- 实现直播登录
【从 0 开始开发一款直播 APP】5.2 MVP 之 Fragment 交互实现滑动导航
【从 0 开始开发一款直播 APP】5.3 MVC 完全解析 -- 实现直播登录


MVP 概述

在无任何架构模式下的开发时,Activity 和 Model 之间的关系太紧密,做了所有的操作,不易维护,扩展性差。如果所有逻辑都在 Activity 中实现,代码显得臃肿不易维护和修改。

MVP(Model-View-Presenter,模型-视图-表示器)模式则是由 IBM 开发出来的一个针对 C++ 和 Java 的编程模型,大概出现于 2000 年,是 MVC 模式的一个变种,主要用来隔离UI、UI 逻辑和业务逻辑、数据。MVP 模式中不容许 View 直接访问 Model,这是 MVP 和 MVC 之间最大的不同。View 中应该只有 UI 逻辑,捕捉用户输入以及视图的渲染。这样将其它复杂的逻辑抽离出来放到 Presenter 中去,这样就出现了MVP。简单的说,就是将 View 中的复杂工作抽取到 Presenter 中,降低了耦合度,便于维护和测试,也增强了复用性。

Presenter 是 Model 和 View 之间的桥梁,为了让结构变得更加简单,View 并不能直接对 Model 进行操作,这也是 MVP 与 MVC 最大的不同之处。

Model — 业务逻辑和数据模型。

Model 层主要负责

1、从网络,数据库,文件,传感器,第三方等数据源读写数据。

2、对外部的数据类型进行解析转换为 APP 内部数据交由上层处理。

3、对数据的临时存储,管理,协调上层数据请求。

View — View 的绘制和用户交互

View 层主要负责

1、提供 UI 交互

2、在 Presenter 的控制下修改 UI

3、将业务事件交由 Presenter 处理

注意:View 层不存储数据,不与 Model 层交互

Presenter — View 和 Model 间的交互

Presenter 层主要负责

1、作为 View 和 Model 之间的纽带,处理与用户交互的逻辑实现。

2、根据用户在视图中的行为更新模型的逻辑

3、负责从 View 视图中取得数据发送给模型

MVP 优点

1、降低耦合度,实现了Model和View真正的完全分离,可以修改 View 而不影响 Model

2、模块职责划分明显,层次清晰

3、隐藏数据

4、 Presenter 可以复用,一个 Presenter 可以用于多个 View,而不需要更改 Presenter的逻辑(当然是在 View 的改动不影响业务逻辑的前提下)

5、利于测试驱动开发。在使用 MVP 的项目中 Presenter 对 View 是通过接口进行,在对 Presenter 进行不依赖 UI 环境的单元测试的时候。可以通过 Mock 一个 View 对象,这个对象只需要实现了 View 的接口即可。然后依赖注入到 Presenter 中,单元测试的时候就可以完整的测试 Presenter 应用逻辑的正确性。

6、View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做到高度可复用的View组件。

7、提高代码灵活性

MVP 缺点

1、Presenter中除了应用逻辑以外,还有大量的 View -> Model,Model -> View 的手动同步逻辑,造成 Presenter 比较笨重,维护起来会比较困难。

2、由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁。

3、如果 Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么 Presenter 也需要变更了。

4、额外的代码复杂度及学习成本。

MVP 使用

MVP 的逻辑实现类图,根据 MVP 模型,定义 P 层和 V 层接口以及基本方法以及 M 层相关方法。

使用 MVP 大致要做以下步骤

1、创建 IPresenter 接口,把所有业务逻辑接口都定义在内,并创建它的实现类 PresenterImpl。Ipresenter 持有 IView 的引用,调用 IView 中的方法。

2、创建 IView接口,把所有视图逻辑的接口都定义在内,创建其实现类 Activity / Fragment。

3、IPresenter 间接持有 Model 的引用,但 Model 并不是必须有的,但是一定会有 Presenter 和 View。

4、在上图中可以看到,Activity 中包含了一个 IPresenter,而 PresenterImpl 里包含了一个 IView并依赖于 Model。Activity 只保留了对 IPresenter 的调用,其它工作全部由 PresenterImpl 实现。

MVP 实现登录

Presenter — LoginPresenter

1、定义 BasePresenter 接口,主要方法是 start() — presenter 开始处理数据,绑定 Presenter 。 finish() — 处理销毁工作,界面结束时调用,取消绑定 Presenter 的方法。

2、定义 ILoginPresenter 抽象类实现 BasePresenter 接口,定义登录所需逻辑处理方法,与 ILoginView 关联。

3、定义 LoginPresenter 继承 ILoginPresenter 抽象类,实现抽象方法以及处理逻辑。

View — LoginActivity

1、定义 BaseView 接口,将通用方法封装到里面。

2、定义 ILoginView 接口,定义登录需要的通用方法。

3、创建 LoginActivity 实现 ILoginView 接口,并与 LoginPresenter 关联。

Model — UserInfo

根据登录请求数据定义 Model 所需字段以及 set() 和 get() 方法,注意:Model 要实现序列化接口。


根据相关类图创建包和类。

对登录不了解的请查看 【从 0 开始开发一款直播 APP】4.4 网络封装之 OkHttp -- 网络请求实现直播登录

在后面的代码中会涉及到网络的状态判断,倒计时器的加载,弱引用,ACache 缓存等,有兴趣的可以看看。
【从 0 开始开发一款直播 APP】6 缓存 ACache 源码解析
【从 0 开始开发一款直播 APP】7 倒计时器 CountDownTimer 源码解析
【从 0 开始开发一款直播 APP】8 弱引用 WeakReference
【从 0 开始开发一款直播 APP】9 网络连接状态详解

Presenter 所有类实现

1、BasePresenter

public interface BasePresenter{
    /**
     * presenter 开始处理方法
     */
    void start();
    /**
     * 处理一些销毁工作,在界面结束时候调用
     */
    void finish();
}

2、ILoginPresenter

public abstract class ILoginPresenter implements BasePresenter {

    protected BaseView mBaseView;
    public ILoginPresenter(BaseView baseView) {
        mBaseView = baseView;
    }

    /**
     * 检查手机号验证码是否合法
     * @param phone
     * @param verifyCode
     * @return
     */
    public abstract boolean checkPhoneLogin(String phone, String verifyCode);


    /**
     * 检查用户名密码是否合法
     * @param userName
     * @param password
     * @return
     */
    public abstract boolean checkUserNameLogin(String userName, String password);

    /**
     * 手机号登录
     * @param phone
     * @param verifyCode
     */
    public abstract void phoneLogin(String phone, String verifyCode);

    /**
     * 用户名登录
     * @param userName
     * @param password
     */
    public abstract void userNameLogin(String userName, String password);

    /**
     * 发送验证码
     * @param phoneNum
     */
    public abstract void sendVerifyCode(String phoneNum);
}

3、LoginPresenter

实现 ILoginPresenter 接口及其方法的逻辑

public class LoginPresenter extends ILoginPresenter {

    private ILoginView mLoginView;

    public LoginPresenter(ILoginView loginView) {
        super(loginView);
        mLoginView = loginView;
    }

    @Override
    public void start() {

    }

    @Override
    public void finish() {
        //与 View 解绑
        if (mLoginView!=null){
            mLoginView = null;
        }
    }

    @Override
    public boolean checkPhoneLogin(String phone, String verifyCode) {
        //判断手机号是否合法
        if (OtherUtils.isPhoneNumValid(phone)) {
            //判断验证码是否正确
            if (OtherUtils.isVerifyCodeValid(verifyCode)) {
              //监测网络状态,包括网络类型(Wi-Fi,2G,3G,4G)以及网络是否连接正常,设置网络等
                if (OtherUtils.checkNetWorkState(mLoginView.getContext())) {
                    return true;
                } else {
                    mLoginView.showMsg("当前无网络连接!");
                }
            } else {
                mLoginView.verifyCodeError("验证码错误!");
            }
        } else {
            mLoginView.phoneError("手机格式错误!");
        }
        mLoginView.dismissLoading();
        return false;
    }

    @Override
    public boolean checkUserNameLogin(String userName, String password) {
      //判断用户名是否合法
        if (OtherUtils.isUsernameVaild(userName)) {
          //判断密码是否合法
            if (OtherUtils.isPasswordValid(password)) {
                //监测网络状态,包括网络类型(Wi-Fi,2G,3G,4G)以及网络是否连接正常,设置网络等
                if (OtherUtils.checkNetWorkState(mLoginView.getContext())) {
                    return true;
                } else {
                    mLoginView.showMsg("当前无网络连接!");
                }
            } else {
                mLoginView.passwordError("密码过短!");
            }
        } else {
            mLoginView.usernameError("用户名不符合规范!");
        }
        //取消loading进度显示
        mLoginView.dismissLoading();
        return false;
    }

    @Override
    public void phoneLogin(final String phone, final String verifyCode) {
        //判断手机号和验证码是否正确
        if (checkPhoneLogin(phone, verifyCode)) {
            final PhoneLoginRequest request = new                               PhoneLoginRequest(RequestComm.loginPhone, phone, verifyCode);
            AsyncHttp.instance().postJson(request, new AsyncHttp.IHttpListener() {
                @Override
                public void onStart(int requestId) {
                  //显示loading进度
                    mLoginView.showLoading();
                }

                @Override
                public void onSuccess(int requestId, Response response) {
                    if (response.getStatus() == RequestComm.SUCCESS) {
              ACache.get(mLoginView.getContext()).put(CacheConstants.LOGIN_PHONE, phone);
                        mLoginView.loginSuccess();
                    } else {
                        mLoginView.loginFailed(response.getStatus(), response.getMsg());
                    }
                    mLoginView.dismissLoading();
                }

                @Override
                public void onFailure(int requestId, int httpStatus, Throwable error) {
                    mLoginView.verifyCodeFailed("网络异常");
                    mLoginView.dismissLoading();
                }
            });
        }
    }

    @Override
    public void userNameLogin(final String userName, final String password) {
        //判断用户名是否合法
        if (checkUserNameLogin(userName, password)) {
            LoginRequest request = new LoginRequest(RequestComm.loginUsername, userName, password);
            AsyncHttp.instance().postJson(request, new AsyncHttp.IHttpListener() {
                @Override
                public void onStart(int requestId) {
                    mLoginView.showLoading();
                }

                @Override
                public void onSuccess(int requestId, Response response) {
                    if (response.getStatus() == RequestComm.SUCCESS) {
                        //请求数据成功
                        UserInfo info = (UserInfo) response.getData();
                        //将登陆数据存入缓存,这个在后面的文章会介绍
                        UserInfoCache.saveCache(mLoginView.getContext(), info);
         ACache.get(mLoginView.getContext()).put(CacheConstants.LOGIN_USERNAME, userName);
         ACache.get(mLoginView.getContext()).put(CacheConstants.LOGIN_PASSWORD, password);
                        mLoginView.loginSuccess();
                    } else {
                        mLoginView.loginFailed(response.getStatus(), response.getMsg());
                        mLoginView.dismissLoading();
                    }
                }

                @Override
                public void onFailure(int requestId, int httpStatus, Throwable error) {
                    mLoginView.loginFailed(httpStatus, error.getMessage());
                    mLoginView.dismissLoading();
                }
            });
        }
    }

    @Override
    public void sendVerifyCode(String phoneNum) {
        //判断手机号是否合法
        if (OtherUtils.isPhoneNumValid(phoneNum)) {
          //监测网络状态,包括网络类型(Wi-Fi,2G,3G,4G)以及网络是否连接正常,设置网络等
            if (OtherUtils.checkNetWorkState(mLoginView.getContext())) {
                VerifyCodeRequest request = new VerifyCodeRequest(RequestComm.verifyCodeRequestId, phoneNum);
                AsyncHttp.instance().postJson(request, new AsyncHttp.IHttpListener() {
                    @Override
                    public void onStart(int requestId) {
                        mLoginView.showLoading();
                    }

                    @Override
                    public void onSuccess(int requestId, Response response) {
                        if (response.getStatus() == RequestComm.SUCCESS) {
                            UserInfo info = (UserInfo) response.getData();
                            if (null != mLoginView){
                                //倒计时器 60 秒发送验证码
                                mLoginView.verifyCodeSuccess(60,60);
                            }
                        }else {
                            mLoginView.verifyCodeFailed("获取后台验证码失败!");
                        }
                        mLoginView.dismissLoading();
                    }

                    @Override
                    public void onFailure(int requestId, int httpStatus, Throwable error) {

                        if (null != mLoginView){
                            mLoginView.verifyCodeFailed("获取后台验证码失败!");
                        }
                        mLoginView.dismissLoading();
                    }
                });
            } else {
                mLoginView.showMsg("当前无网络连接!");
            }
        } else {
            mLoginView.phoneError("手机号码不符合规范!");
        }
    }
}

View 所有类实现

1、BaseView

public interface BaseView {
    /**
     * 数据加载或耗时加载时界面显示
     */
    void showLoading();

    /**
     * 数据加载或耗时加载完成时界面显示
     */
    void dismissLoading();

    /**
     * 消息提示,如 Toast,Dialog等
     */
    void showMsg(String msg);
    void showMsg(int msgId);

    /**
     * 获取Context
     * @return
     */
    Context getContext();
}

2、ILoginView

在 LoginPresenter 中绑定了 ILoginView,在 LoginPresenter 实现逻辑时调用的时 ILoginView 中的方法。

public interface ILoginView extends BaseView {

    /**
     * 登录成功
     */
    void loginSuccess();

    /**
     * 登录失败
     * @param status
     * @param msg
     */
    void loginFailed(int status, String msg);

    /**
     * 用户名错误
     * @param errorMsg
     */
    void usernameError(String errorMsg);

    /**
     *手机号错误
     * @param errorMsg
     */
    void phoneError(String errorMsg);

    /**
     * 密码错误
     * @param errorMsg
     */
    void passwordError(String errorMsg);

    /**
     * 验证码错误
     * @param errorMsg
     */
    void verifyCodeError(String errorMsg);

    /**
     * 验证失败
     * @param errorMsg
     */
    void verifyCodeFailed(String errorMsg);

    /**
     * 验证成功
     * @param reaskDuration
     * @param expireDuration
     */
    void verifyCodeSuccess(int reaskDuration, int expireDuration);

}

3、LoginActivity

之前的文章中有讲过用户登录实现,那时是硬实现,没有逻辑分层,可以结合前面的文章一起学习。

public class LoginActivity extends BaseActivity implements View.OnClickListener, ILoginView {
    //共用控件
    private ProgressBar progressBar;
    private EditText etPassword;
    private EditText etLogin;
    private Button btnLogin;
    private Button btnPhoneLogin;
    private TextInputLayout tilLogin, tilPassword;
    private Button btnRegister;
    //手机验证登陆控件
    private TextView tvVerifyCode;
    private boolean isPhoneLogin = false;

    private LoginPresenter mLoginPresenter;

    @Override
    protected void setActionBar() {
    }

    @Override
    protected void setListener() {

    }

    @Override
    protected void initData() {
        etLogin.setText(ACache.get(this).getAsString(CacheConstants.LOGIN_USERNAME));
        etPassword.setText(ACache.get(this).getAsString(CacheConstants.LOGIN_PASSWORD));
    }

    @Override
    protected void initView() {
        mLoginPresenter = new LoginPresenter(this);
        etLogin = obtainView(R.id.et_username);
        etPassword = obtainView(R.id.et_password);
        btnRegister = obtainView(R.id.btn_register);
        btnPhoneLogin = obtainView(R.id.btn_phone_login);
        btnLogin = obtainView(R.id.btn_login);
        progressBar = obtainView(R.id.progressbar);
        tilLogin = obtainView(til_login);
        tilPassword = obtainView(R.id.til_password);
        tvVerifyCode = obtainView(R.id.btn_verify_code);

        userNameLoginViewInit();
    }

    @Override
    protected int getLayoutId() {
        return R.layout.activity_login;
    }

    /**
     * 用户名密码登录界面init
     */
    public void userNameLoginViewInit() {
        //用户名登录切换
        userLoginTrans();
        tvVerifyCode.setOnClickListener(this);
        //注册
        btnRegister.setOnClickListener(this);
        //手机号登录
        btnPhoneLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //手机号登录
                phoneLoginViewinit();
            }
        });
        //用户名登录
        btnLogin.setOnClickListener(this);
    }

    public void phoneLoginViewinit() {
        phoneLoginTrans();
        btnPhoneLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //转换为用户名登录界面
                userNameLoginViewInit();
            }
        });

        btnLogin.setOnClickListener(this);
        btnRegister.setOnClickListener(this);
        tvVerifyCode.setOnClickListener(this);
    }

    private void phoneLoginTrans() {
        isPhoneLogin = true;
        tvVerifyCode.setVisibility(View.VISIBLE);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
        alphaAnimation.setDuration(250);
        tvVerifyCode.setAnimation(alphaAnimation);
        //设定点击优先级于最前(避免被EditText遮挡的情况)
        tvVerifyCode.bringToFront();
        //设置输入框输入类型为 手机号
        etLogin.setInputType(EditorInfo.TYPE_CLASS_PHONE);
        etLogin.setText("");
        etPassword.setText("");
        //手机号登录按钮文字改为 用户名登录
        btnPhoneLogin.setText("用户名登录");
        tilLogin.setHint("手机号");
        tilPassword.setHint("密码");
    }

    private void userLoginTrans() {
        isPhoneLogin = false;
        tvVerifyCode.setVisibility(View.GONE);
        AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
        alphaAnimation.setDuration(250);
        tvVerifyCode.setAnimation(alphaAnimation);
        etLogin.setInputType(EditorInfo.TYPE_CLASS_TEXT);
        etLogin.setText("");
        etPassword.setText("");
        btnPhoneLogin.setText("手机号登录");
        tilLogin.setHint("用户名");
        tilPassword.setHint("密码");
    }

    /**
     * 手机登录和用户名登录界面显示或隐藏
     * @param active
     */
    public void showOnLoading(boolean active) {
        if (active) {
            progressBar.setVisibility(View.VISIBLE);
            btnLogin.setVisibility(View.INVISIBLE);
            etLogin.setEnabled(false);
            etPassword.setEnabled(false);
            btnPhoneLogin.setClickable(false);
        btnRegister.setTextColor(getResources().getColor(R.color.colorTransparentGray));
       btnPhoneLogin.setTextColor(getResources().getColor(R.color.colorTransparentGray));
            btnRegister.setClickable(false);
        } else {
            progressBar.setVisibility(View.GONE);
            btnLogin.setVisibility(View.VISIBLE);
            etLogin.setEnabled(true);
            etPassword.setEnabled(true);
            btnPhoneLogin.setClickable(true);
            btnRegister.setClickable(true);
            btnRegister.setTextColor(getResources().getColor(R.color.white));
            btnPhoneLogin.setTextColor(getResources().getColor(R.color.white));
        }
    }

    public boolean checkPhoneLogin(String phone, String verifyCode) {
        if (OtherUtils.isPhoneNumValid(phone)) {
            if (OtherUtils.isVerifyCodeValid(verifyCode)) {
                if (OtherUtils.checkNetWorkState(this)) {
                    return true;
                } else {
                    ToastUtils.showShort(this, "当前无网络连接");
                }
            } else {
                ToastUtils.showShort(this, "验证码错误");
            }
        } else {
            ToastUtils.showShort(this, "手机格式错误");
        }
        return false;
    }

    public boolean checkUserNameLogin(String userName, String password) {
        if (OtherUtils.isUsernameVaild(userName)) {
            if (OtherUtils.isPasswordValid(password)) {
                if (OtherUtils.checkNetWorkState(this)) {
                    return true;
                } else {
                    ToastUtils.showShort(this, "当前无网络连接");
                }
            } else {
                ToastUtils.showShort(this, "密码过短");
            }
        } else {
            ToastUtils.showShort(this, "用户名不符合规范");
        }
        return false;
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_login:
                if (isPhoneLogin) {
                    mLoginPresenter.phoneLogin(etLogin.getText().toString(), etPassword.getText().toString());
                } else {
                    mLoginPresenter.userNameLogin(etLogin.getText().toString(), etPassword.getText().toString());
                }
                break;
            case R.id.btn_verify_code:
                mLoginPresenter.sendVerifyCode(etLogin.getText().toString());
                break;
            case R.id.btn_register:
                break;
        }
    }

    @Override
    public void loginSuccess() {
        dismissLoading();
        invoke(this, MainActivity.class);
        finish();
    }

    @Override
    public void loginFailed(int status, String msg) {
        dismissLoading();
        showMsg("登录失败:" + msg);
    }

    @Override
    public void usernameError(String errorMsg) {
        etLogin.setError(errorMsg);
    }

    @Override
    public void phoneError(String errorMsg) {
        etLogin.setError(errorMsg);
    }

    @Override
    public void passwordError(String errorMsg) {
        etPassword.setError(errorMsg);
    }

    @Override
    public void verifyCodeError(String errorMsg) {
        showMsg(errorMsg);
    }

    @Override
    public void verifyCodeFailed(String errorMsg) {
        showMsg(errorMsg);
    }

    @Override
    public void verifyCodeSuccess(int reaskDuration, int expireDuration) {
        showMsg("注册短信下发,验证码 " + expireDuration / 60 + " 分钟内有效!");
        OtherUtils.startTimer(new WeakReference<TextView>(tvVerifyCode), "验证码", reaskDuration, 1);
    }

    @Override
    public void showLoading() {
        showOnLoading(true);
    }

    @Override
    public void dismissLoading() {
        showOnLoading(false);
    }

    @Override
    public void showMsg(String msg) {
        showToast(msg);
    }

    @Override
    public void showMsg(int msgId) {
        showMsg(msgId);
    }

    @Override
    public Context getContext() {
        return this;
    }
}

Model 的定义

1、UserInfo 要实现序列化接口

public class UserInfo extends IDontObfuscate{

    private String nickname;
    private int sex;
    private String headPic;
    private String sigId;
    private String userId;
    private String sdkAppId;
    private String sdkAccountType;
    private String token;

    public UserInfo() {
    }

    public UserInfo(String nickname, int sex, String headPic, String userId) {
        this.nickname = nickname;
        this.sex = sex;
        this.headPic = headPic;
        this.userId = userId;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public String getHeadPic() {
        return headPic;
    }

    public void setHeadPic(String headPic) {
        this.headPic = headPic;
    }

    public String getSigId() {
        return sigId;
    }

    public void setSigId(String sigId) {
        this.sigId = sigId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getSdkAppId() {
        return sdkAppId;
    }

    public void setSdkAppId(String sdkAppId) {
        this.sdkAppId = sdkAppId;
    }

    public String getSdkAccountType() {
        return sdkAccountType;
    }

    public void setSdkAccountType(String sdkAccountType) {
        this.sdkAccountType = sdkAccountType;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

2、UserInfoCache 也要实现序列化接口

账号字段在后面的文章介绍,这里直接贴出来。

public class UserInfoCache extends IDontObfuscate{
    public static void saveCache(Context context, UserInfo info){
        ACache.get(context).put("user_id",info.getUserId());
        ACache.get(context).put("nickname",info.getNickname());
        ACache.get(context).put("head_pic",info.getHeadPic());
        ACache.get(context).put("sig_id",info.getSigId());
        ACache.get(context).put("token",info.getToken());
        ACache.get(context).put("sdk_app_id",info.getSdkAppId());
        ACache.get(context).put("adk_account_type",info.getSdkAccountType());
        ACache.get(context).put("sex",info.getSex());

        if (info.getSdkAppId() != null && TextUtils.isDigitsOnly(info.getSdkAccountType())){
            Constants.IMSDK_ACCOUNT_TYPE = Integer.parseInt(info.getSdkAccountType());
        }
    }

    public static String getUserId(Context context){
        return ACache.get(context).getAsString("user_id");
    }

    public static String getNickname(Context context){
        return ACache.get(context).getAsString("nickname");
    }

    public static String getHeadPic(Context context){
        return ACache.get(context).getAsString("head_pic");
    }

    public static String getSigId(Context context){
        return ACache.get(context).getAsString("sig_id");
    }

    public static String getToken(Context context){
        return ACache.get(context).getAsString("token");
    }

    public static String getSdkAccountType(Context context){
        return ACache.get(context).getAsString("adk_account_type");
    }

    public static String getSdkAppId(Context context){
        return ACache.get(context).getAsString("sex");
    }

    public static String getSex(Context context){
        return ACache.get(context).getAsString("sdk_app_id");
    }

    public static void clearCache(Context context){
        ACache.get(context).remove("user_id");
        ACache.get(context).remove("nickname");
        ACache.get(context).remove("head_pic");
        ACache.get(context).remove("sig_id");
        ACache.get(context).remove("token");
        ACache.get(context).remove("adk_account_type");
        ACache.get(context).remove("sdk_app_id");
        ACache.get(context).remove("sex");
    }
}

登录实现运行效果


参考:

http://www.jianshu.com/p/9a6845b26856

http://www.jianshu.com/p/f6252719b3af

140套Android优秀开源项目源码,领取地址:http://mp.weixin.qq.com/s/afPGHqfdiApALZqHsXbw-A

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容