美文网首页从0到1开发一款APP直播APP程序员
【从 0 开始开发一款直播 APP】5.1 MVP 完全解析 -

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

作者: 菜鸟窝 | 来源:发表于2017-04-19 09:20 被阅读254次

    本文为菜鸟窝作者蒋志碧的连载。“从 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

    相关文章

      网友评论

        本文标题:【从 0 开始开发一款直播 APP】5.1 MVP 完全解析 -

        本文链接:https://www.haomeiwen.com/subject/mxsczttx.html