如何一步一步实现Android的MVP框架,MVP在Android中简

作者:计算机知识

最进想做了三个新的小品种,总想来点对友好来讲特别的事物。前边见到Google老大推荐使用MVP布局,即刻认为不尝试看都不佳正是艳羡它的小弟了。良心表弟也特地在Github推出了三个项目Android Architecture Blueprints,用来展现Android用各样的MVP框架,也能算了官方网站教程了。在网络征集素材看了一下大神们的解析后,本人入手试了试。那么就立刻上手来看一看MVP毕竟怎么。(本文都是环绕项目中todo-mvp部分来介绍)

近些年在受我们合营社的大神影象下,也搭建一个MVP开垦框架,希望能够给对文化做七个总结。
超神的凤梨简书地址:
此间运用一个轻易易行的应用对MVP做多个上课。

前言:MVP是什么样作者就不讲了,要是急需的能够去百度查实资料。

先上一张图,然后依照实际的代码大家来说讲谷歌是怎么看待MVP构造的

说到里海虎机,玩过的人应有记得那体系型的图(那是主分界面),下边就从最基本的知识解析整个应用程式的制程,也还要把Android中的一些功底知识增强三次

一、MVP的形式介绍

信赖大家对MVC都以比较熟知了:M-Model-模型、V-View-视图、C-Controller-调节器,MVP作为MVC的嬗变版本,那么看似的MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。 从MVC和MVP两个结合来看,Controlller/Presenter在MVC/MVP中都起着逻辑调整管理的剧中人物,起着决定各业务流程的法力。而 MVP与MVC最差别的有些是M与V是不直接关乎的也是就Model与View不真实直接涉及,这两个之间间距着的是Presenter层,其担任调节View与Model之间的直接交互作用。在 Android中很首要的一些正是对UI的操作基本上供给异步举行也正是在MainThread中才具操作UI,所以对View与Model的隔开分离是 合理的。别的Presenter与View、Model的相互使用接口定义交互作用操作可以更进一层实现松耦合也能够由此接口特别实惠地举办单元测验。所以也就有了那张图片(MVP和MVC的相持统一)

图片 1

1833901-5c4e92e23b072d88.png

WranglerxJava是阅览者方式的一种达成,观望者为Consumer或然Subscriber 被观看者为Flowable

图片 2

图片 3

二、项目布局图

图片 4

咱俩差不离理一理,达成七个Present要求如何内容:

第一丁一七个Base接口,分别是用作Presenter和View的基类

第一说一下这么些应用软件的基本操作:

如何一步一步实现Android的MVP框架,MVP在Android中简易易懂的实现案例。三、MVP情势的应用

  • 1.着力的,Present要拿走Activity的实例对象,它们是一对一的涉及。

  • 2.首先,Present料定是被阅览者,他要管理完事件后归来结果给阅览它的人。所以她要实现Flowable中切实的诀窍。

  • 3.她要有接收事物管理的目的,约等于函数的参数,然后依据参数来进展拍卖和重回结果

public interface BaseView<T> { // 为View设置Presenter void setPresenter(T presenter); // 初始化界面控件 void initView(View view);}public interface BasePresenter { // 获取数据并改变界面显示,在todo-mvp的项目中的调用时机为Fragment的OnResume()方法中 void start();}

1.点击下注开关后,会跻身投注分界面

3.1model层描述和现实代码

法定事例中加如公约类来统一处理View和Presenter。那样任何功能能够在左券类如数家珍。老大便是不行,那或多或少照旧异常的棒的。事举例下:

图片 5

提供我们想要展示在view层的数额和实际登录业务逻辑管理的兑现,
package taiyuaneltyl.com.my_mvp.model;

import taiyuaneltyl.com.my_mvp.presenter.LoginOnListener;

/**
 * Created by Administrator on 2018/3/31.
 */

public interface LoginNet {

    //真实登陆的操作的接口,实现类为LoginNetIml.相当于MVP模式中的Model层
    void Login(String name, String pwd, String resid,LoginOnListener loginOnListener);
}
  • 4.她要有再次来到结果的力量,所以要求经受观看者的监听容器(Consumer,Subscriber),这也是急需写在函数之中的。

  • 5.她要有管理四十六线程并能重回到主线程的力量,因为自身调用了网络乞求后不容许将子线程回到主线程的操作交由View管理。

  • 6.他要防止内部存款和储蓄器泄漏,因为Present超级多意况下必要用到多线程,借使持有Activity的实例,那么就能够招致Activity释放的不立时。

public interface YourContract { interface View extends BaseView<Presenter>{ //这里加View功能方法 void showError(); void showLoading(); void Stoploading(); } interface Presenter extends BasePresenter{ // 同上 void loatPosts(int PagerNum,boolean cleaing); void reflush(); void loadMore(int PagerNum); }}

2.上下拖动选拔下注比,并精选稳固金额或和睦输入金额,点击分明再次来到主分界面

3.2 LoginNetImI 具体得以实现详明

import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.StringCallback;

import okhttp3.Call;

import taiyuaneltyl.com.my_mvp.presenter.LoginOnListener;

/**
 * Created by Administrator on 2018/3/31.
 * <p>
 * 网络请求的实现
 */

public class LoginNetIml implements LoginNet {
  /**
 * 请求成功在onResponse方法判断response不等于null 调用loginOnListener.onpSuccess(response);
 * 等于null 调用 loginOnListener.onError();
 * 请求失败onError 调用 loginOnListener.onError();
 */
    @Override
    public void Login(String name, String pwd, String rid, final LoginOnListener loginOnListener) {

        OkHttpUtils
                .get()
                .url("http://api.eltyl.com/index.php/Home/App/dologin")
                .addParams("mobile", name)
                .addParams("password", pwd)
                .addParams("regid", rid)
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e, int id) {
                           loginOnListener.onError();
                    }

                    @Override
                    public void onResponse(String response, int id) {
                        Log.v("111111",response);
                        if (response != null) {
                            loginOnListener.onpSuccess(response);
                        } else {
                            loginOnListener.onError();
                        }

                    }
                });
    }
}

那正是自己收拾出来的对Present的4点必要,上面大家一一完成。

对了,个中BaseView中含方法setPresenter,该方法效果是在将presenter实例传入view中,其调用机缘是presenter实现类的布局函数中。如下

3.然后初阶游戏,现身如图效果,转动的岗位的图片背景会成为浅紫

3.3 presenter层描述和求实代码

以下器重涉嫌多少个类,MainActivity(视图类),BasePresent(Present的基类),MainActivityPresent(MainActivity对应的Present实现类)

public YourPresenter(Context context, YourContract.View view) { this.context=context; this.view=view; this.view.setPresenter; }

图片 6

Presenter扮演着view和model的中间层的剧中人物。获取model层的数据现在塑造view层;也得以接到view层UI上的报告命令后分发管理逻辑,交给model层做作业操作。它也能够调控View层的种种操作。

package taiyuaneltyl.com.my_mvp.presenter;

/**
 * Created by Administrator on 2018/3/31.
 */

public interface LoginOnListener {
    /**
     * 请求成功
     * @param mbean
     */
    void onpSuccess(String mbean);

    /**
     * 请求失败
     */
    void onError();


}

** 公共属性 **

在讲那个后边,不知底大家有没有理会到上没图中,Fragment是用作View层而Activity是充作Presenter的,有未有想过谷歌为何要推荐那样做吗?

关键功能描述正是那样,由于不会发动态图,所以实际效果不可能呈现,风乐趣的能够下载试试哈

3.4 OnLoginListenerImpl 具体落实详整

package taiyuaneltyl.com.my_mvp.presenter;

import android.os.Handler;

import taiyuaneltyl.com.my_mvp.View.LoginView;
import taiyuaneltyl.com.my_mvp.model.LoginNet;
import taiyuaneltyl.com.my_mvp.model.LoginNetIml;

/**
 *    M层和V交互
 */

public class OnLoginListenerImpl {
    private LoginNet baseNet;
    private LoginView loginView;

    public OnLoginListenerImpl(LoginView loginView) {
        this.loginView = loginView;
        baseNet = new LoginNetIml();
    }

    /**
     * login在登陆的监听调用
     * 
     *  
     */
    public void login() {
//        Handler handler=new Handler();
//        handler.postDelayed(new Runnable() {
//            @Override
//            public void run() {
        loginView.Onloading();

        /**
         * baseNet的Login需要三个参数  在LoginView中定义三个string类型的   不想定义也可以这样写  
         *   public void login (String name,String pwd,String Rid){
         *       下面的Login就可以拿到请求参数 自己喜欢哪种 随便写
         *   }
         *
         */
        baseNet.Login(loginView.getUserName(), loginView.getPassword(), loginView.getRid(), new LoginOnListener() {

            @Override
            public void onpSuccess(String mbean) {   //mbean就是请求的结果
                loginView.OnSuccess(mbean);
                loginView.Ondismiss();
            }

            @Override
            public void onError() {
                loginView.Onfail("");
                loginView.Ondismiss();
            }
        });
//            }
//        },300);

    }



}

本人以为把部分能力所能达到联手落到实处的放在基类里面,然后根据各部分特色开展继续,那样优化了代码的可读性和代码量
此处的共用属性笔者觉着有四个,一是重回主线程的技术,二是管理内部存款和储蓄器泄漏,十分的少说,先帖代码

MVC中Activity的作用

据守大家事情发生早先的习于旧贯也许说在MVC格局中,Activity是作为View层和客户打交道,选拔客户数量的输入和输出的。非常是咱们会在Activity的宣示周期中写入一些逻辑来落到实处大家想要的效率。那样很有益于,可是后果是大家的Activity非常的重叠,用脑筋想只要我们有的通用的功力每一个Activity里都要写三回不是一件很难熬的事务。当时,Activity 不止承受了 View 的角色,还担任了一局地的 Controller 剧中人物,那样一来 V 和 C 就耦合在联合签名了,尽管如此写方便,不过假设专业调治的话,要保障起来就难了,而且在一个交汇的 Activity 类查找职业逻辑的代码也会这多少个蛋疼,所以看起来有必不可缺在 Activity 中,把 View 和 Controller 分离开来,而那正是 MVP 格局的干活了。

上边最初一步步深入分析任何应用程式塑造进度:

3.5 view层描述和求实代码

public class BasePresent {

    private WeakReference<Context> mContext ;

    protected BasePresent(Context context){
        mContext = new WeakReference<Context>(context);
    }


    protected Context getContext(){
        return mContext.get();
    }

    protected void runOnUIThread(Runnable runnable){
        //判断Context的合理
        if(runnable==null || mContext.get() == null || !(mContext.get() instanceof Activity)){
            return ;
        }
        ((Activity)mContext.get()).runOnUiThread(runnable);

    }
}
MVP中View层的兑现

有关何以要选拔Fragment作为View层的落到实处类。小编看出网络有这三种说法,第一个原因是大家把activity作为三个大局调控类来创造对象,把fragment作为view,那样双方就能够融入。第叁个原因是因为fragment比较灵敏,能够有助于的管理分界面适配的标题

MVP 把 Activity 中的 UI 逻辑抽象成 View 接口,把作业逻辑抽象成 Presenter 接口,Model 类依旧原来的 Model。

来看一段代码就能够精晓Activity的功效了(究竟代码能够看清):

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); if (savedInstanceState!=null){ mainFragment= (MainFragment) getSupportFragmentManager().getFragment(savedInstanceState,"MainFragment"); bookmarksfragment=(BookmarksFragment) getSupportFragmentManager().getFragment(savedInstanceState,"BookmarksFragment"); }else { mainFragment=MainFragment.newInstance(); bookmarksfragment=BookmarksFragment.newInstance(); } new BookmarksPresenter(MainActivity.this,bookmarksfragment);}

看了上面的代码差不离就能够清楚Activity的功力是哪些了。首倘使用作全局的垄断,担当创设View甚至Presenter实例,并将四头关系起来。

 public class YourFragment extends Fragment implements YourContract.View { private YourContract.Presenter presenter; @Override public void onResume() { super.onResume(); presenter.start(); } @Override public void setPresenter(YourContract.Presenter presenter) { if (presenter!=null){ this.presenter=presenter; } } @Override public void showError() { Snackbar.make(fab, R.string.loaded_failed,Snackbar.LENGTH_INDEFINITE) .setAction(R.string.retry, new View.OnClickListener() { @Override public void onClick { presenter.reflush .show(); } @Override public void showLoading() { refresh.post(new Runnable() { @Override public void run() { refresh.setRefreshing; } }); } @Override public void Stoploading() { refresh.post(new Runnable() { @Override public void run() { refresh.setRefreshing; } }); }}

能够见到通过setPresenter方法获取到Presenter的实例。然后在Fragment的生命周期中调用presenter.start(卡塔尔国方法。这样View层只负担数据给顾客显示他们见到的事物,而不去管具体是怎么贯彻的(ps:作者感觉在onResume(卡塔尔国方法此前调用应该都行呢,不知底是还是不是对的。假设有错,还请指教)

public class YourPresenter implements YourContract.Presenter {public YourPresenter(Context context, YourContract.View view) { this.context=context; this.view=view; this.view.setPresenter; }@Override public void loatPosts(int PagerNum, final boolean cleaing) { //具体实现就不贴了,有点长}@Override public void start() { loatPosts(CurrentPagerNum,true); }@Override public void reflush() { loatPosts(CurrentPagerNum,true); }@Override public void loadMore(int PagerNum) { loatPosts(CurrentPagerNum PagerNum,false); }}

在构造方法中,Presenter将作者的事例传递给了View,那样View就能够调用Presenter层的方法来拍卖业务逻辑了。在start(卡塔尔方法中,管理了数码加载。

花色中model层最大的特点是被赋予了数额取得的天职,与大家平日model层只定义实体对象天壤之别,实例中,数据的获取、存款和储蓄、数据状态变化都以model层的天职,Presenter会根据要求调用该层的多寡管理逻辑并在急需时将回调传入。那样model、presenter、view都只管理各自的任务,此种实现真即是十足职分最棒的笺注。

  • 拜别了视图逻辑和事情逻辑,收缩耦合度,达成了Model和View真正的通通分开,能够校正View而不影响Modle
  • Activity 只管理生命周期的职分,代码变得更为简洁
  • 视图逻辑和事务逻辑分别抽象到了 View 和 Presenter 的接口中去,进步代码的可阅读性
  • View能够扩充组件化。在MVP当中,View不重视Model。那样就能够让View从一定的作业场景中抽离出来,能够说View能够成功对业务完全无知。它只要求提供一种类接口提必要上层操作。那样就足以达成中度可复用的View组件。
  • 福利测量试验驱动开荒。Presenter 被架空成接口,能够有各个绘声绘色的落成,所以方便开展单元测量检验。在行使MVP的项目中Presenter对View是透过接口举行,在对Presenter实行批驳赖UI遭遇的单元测量检验的时候。能够因此Mock五个View对象,这一个目的只要求达成了View的接口就能够。然后注重注入到Presenter中,单元测量试验的时候就能够完全的测量检验Presenter应用逻辑的没有错。

以上正是本身前段时间来对MVP的通晓了。假如有荒谬的地点,接待指教哦。

首先说一下那些界面包车型地铁编写:

担任呈现数据、提供温馨分界面跟客户交互作用就行。MVP下Activity和Fragment以致View的子类体现在了这一 层,Activity日常也就做加载UI视图、设置监听再交由Presenter管理的一部分办事,所以也就供给具备相应Presenter的引用。本层所急需做的操作正是在每三遍有对应人机联作的时候,调用presenter的相干方法就能够。(比方说,button点击)

package taiyuaneltyl.com.my_mvp.View;

/**
 * Created by Administrator on 2018/3/31.
 */

public interface LoginView {
    /**
     * 请求成功
     */
    void OnSuccess(String bean);
    /**
     * 请求失败
     */
    void Onfail(String msg);

    /**
     * 请求参数
     */

    String getUserName();

    String getPassword();

    String getRid();



    /**
     * 显示加载dialog
     */
    void Onloading();

    /**
     * 隐藏加载dialog
     */
    void Ondismiss();
}

能够看看,大家因此WeakRefrence达成了对Activity的弱应用,并且经过给子类揭破的getContext方法,一是缓和了内存泄漏的难题,二是对子类心得不到拍卖内存泄漏进程的留存。大家用布局方法来注脚,小编的Present必得具备Activity对象。

主界面:

3.6 MVP情势中View层对应七个activity,这里是登录的activity

package taiyuaneltyl.com.my_mvp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.gson.Gson;
import com.jcodecraeer.xrecyclerview.XRecyclerView;

import java.util.List;

import taiyuaneltyl.com.my_mvp.Bean.Bean;
import taiyuaneltyl.com.my_mvp.Bean.LoginBean;
import taiyuaneltyl.com.my_mvp.Utils.DialogUtil;
import taiyuaneltyl.com.my_mvp.Utils.LoadingDialog;
import taiyuaneltyl.com.my_mvp.View.LoginView;
import taiyuaneltyl.com.my_mvp.presenter.LoginOnListener;
import taiyuaneltyl.com.my_mvp.presenter.OnLoginListenerImpl;

public class MainActivity extends AppCompatActivity implements LoginView {
    private EditText ed_name, ed_pwd; //用户账号 密码
    private Button bt_login;         //登陆
    OnLoginListenerImpl monLoginListener = new OnLoginListenerImpl(this);  //p层的monLoginListener

    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ed_name = findViewById(R.id.ed_name);
        ed_pwd = findViewById(R.id.ed_pwd);
        bt_login = findViewById(R.id.bt_login);
        bt_login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                monLoginListener.login();  //监听里面调用p层的login登陆
            }
        });

    }

    //请求成功 bean是结果  以下为LoginView 实现 
    @Override
    public void OnSuccess(String bean) {
        Log.v("---------", bean);
        LoginBean loginBean = new Gson().fromJson(bean, LoginBean.class);
        String s = loginBean.getData().getName();
        Log.v("---------", s);

    }
   //请求失败 msg是返回错误码
    @Override
    public void Onfail(String msg) {
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_LONG).show();
    }
     //获取用户名
    @Override
    public String getUserName() {
        return ed_name.getText().toString();
    }
   //获取密码
    @Override
    public String getPassword() {
        return ed_pwd.getText().toString();
    }
  //  获取Rid 
    @Override
    public String getRid() {
        return "2131332";
    }

    //加载中显示loading
    @Override
    public void Onloading() {
        Toast.makeText(MainActivity.this, "2222", Toast.LENGTH_LONG).show();
        DialogUtil.LoadingDialog(this, "登录中...");


    }
    //加载完毕关闭loading
    @Override
    public void Ondismiss() {
        Toast.makeText(MainActivity.this, "6666666", Toast.LENGTH_LONG).show();
        DialogUtil.LoadingDialogClose();
    }


}

** View **

1.全体接纳线性结构,在那之中的每一行又是八个线性构造,采纳权重的办法给各个子线性布局分配中度

后记

对此View来讲,小编只供给出示分界面和调用Present,所以在View中必需贯彻对Present的开端化

2.水果和金币是ImageView控件,金币数量和原野绿的唤醒文字应用TextView,并且浅米灰文字达成跑马灯果,最后一行是多个藏匿背景的开关

以上就是自个儿对MVP的某个打探

public class MainActivity extends BaseActivity {

    MainActivityPresent present ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        present = new MainActivityPresent(this);
    }
}

投注分界面:

Demo地址:https://gitee.com/oubajunping/MVP_Demo

** 业务 **

1.完好无损依旧选用线性布局

自己后天有三个要求:

2.最上面包车型地铁鲜果比是ListView控件,该控件下方有4个开关(投注金额),最终一行是叁个输入框和三个规定开关

  • 1.MainActivity急需举办登入操作
  • 2.MainActivity须求下载图片并监听整个下载过程

下一场是依照分界面分析怎么写代码(主旨部分):

这两点有何样分裂?

1.对此主分界面,重要正是转动的进度不佳做,须要四个机械漏刻,贰个担负转动的总时间(总时间利用私自数的措施,确定保障每一回转动的小运尽量地不相同),八个负责获取转动进度米玉米黄背景所在的图形的id,当客商选好投注比及投注金额后,点击伊始时,则还要运转那七个反应计时器,运维后,第八个沙漏会处在sleep状态(时间是在一定范围私行变化的),而第三个电磁打点计时器则会间接总结选中图片的序号(当然那几个序号是0~11的循环,因为一齐有12张图纸啊),当第一个电磁打点计时器的sleep状态甘休后,则会即时通报第3个计时器甘休总结序号,此时的序号即为中奖的序号,然后与客商筛选的图形的id实行相比,最后得出结果

真的有两样,第多个需求表示笔者传入四个值,重回给作者二个结果就能够了,但是第一个须要,须要自家发送央求下载,然后下载的快慢要实时的回到给自己。

2.对于下注分界面,首假诺利用SimpleAdapter达成能够压宝的图样的ListView,指明图片的称号及投注比,由于投注是在投注分界面达成,而娱乐开端则是在主分界面,所以就须求向主分界面传递投注的有关音信(投注比、投注金额),那是使用onActivityReslt由下注分界面进行值的回传到完成

** RxJava2 实现 **

先第一个须要,首先大家不写MainActivity,大家写Present

率先大家要求有叁个措施,

MainActivityPresent.java:
public void login(final Login login , final Consumer<String> consumer){
  ...
}

我们得以见见,我们登录,必要经受View传给自家的登入音信,这里用Login,进而进行对数码的拍卖,管理完了后,须求再次回到结果给View,所以那边供给Consumer类,大家写多少个完整的。 tip:使用final因为有用到线程读取数据

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void login(final Login login , final Consumer<String> consumer){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //登陆代码.....
                LogUtils.d("login");
                //runOnUIThread
                String result = "登陆成功";
                final Flowable flowable = Flowable.just(result);
                runOnUIThread(new Runnable() {
                    @Override
                    public void run() {
                        flowable.subscribe(consumer);
                    }
                });

            }
        }).start();
}
}

重中之重有两句话

 final Flowable flowable = Flowable.just(result);
 flowable.subscribe(consumer);

此地大家成立了多个Flowable对象,传入结果将要在回到的结果result ,在登录完毕后我们通过第二句代码来报告给View。大家得以观察第二句话写在了runOnUIThread中,第二句话施行代表回馈View

接下去大家兑现MainActivity的调用

MainActivity.java:
//对于只需要结果的数据,可以使用简单的Consumer
present.login(new Login(), new Consumer<String>() {
    @Override
     public void accept(@NonNull String s) throws Exception {
        //登陆结果,s表示view需要present返回的类型
        LogUtils.d("accept");
         showTip(s);
     }
});

能够观望,我们调用时贯彻了Consumer类,相提并论载了accept方法,这几个艺术正是在登入管理到位后Present回调的措施。


下边我们落实第贰个要求,第二个供给重申进度性,大家只好使用Subscriber来管理那些供给。

也是,第一步,写Present

方法

MainActivityPresent.java:
public void downloadImage(final String url ,final Subscriber<Integer> subscriber){}

相通的,就非常的少说了,上边帖全部代码

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void downloadImage(final String url ,final Subscriber<Integer> subscriber){

        Flowable<Integer> flowable = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
                LogUtils.d("subscribe");
                //下载代码
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3000);
                            //传回更新数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onNext(47);
                                }
                            });
                            Thread.sleep(3000);
                            //传回下载完成数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onComplete();
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }, BackpressureStrategy.BUFFER);
        flowable.subscribe(subscriber);

    }


}

大家能够看出进度很复杂,大家兑现Flowable的方式也不及,这里最终也是有一句,flowable.subscribe(subscriber卡塔尔; 这里注意的是,那句话施行并不意味着回馈音信,而是规范的挂号监听,相当于关联起来。回馈新闻重载的subscribe里面。

咱俩能够观察在subscribe 笔者张开了子线程,过3秒后笔者回来主线程实行了e.onNext(47卡塔尔国; 又过3秒小编回去主线程实施了e.onComplete(State of Qatar; 这里您恐怕不驾驭含义,笔者先大约说一下,第一句话代表下载进程时的实时更新报告,第二句话代表完毕下载后的反馈。

好了 我们贴MainActivity的调用代码

MainActivity.java:
    //对于需要过程的数据,需要用Subscriber,我们需要一个进度,这里选用Integer为进度消息
    present.downloadImage("", new Subscriber<Integer>() {
        @Override
        public void onSubscribe(Subscription s) {
            LogUtils.d("onSubscribe");
            //开始请求
            showTip("start", Toast.LENGTH_SHORT);
            s.request(Long.MAX_VALUE);
        }

        @Override
        public void onNext(Integer integer) {
            LogUtils.d("onNext");
            //进度有更新
            showTip(integer "", Toast.LENGTH_SHORT);
        }

        @Override
        public void onError(Throwable t) {
            LogUtils.d("onError");
            //下载出错
        }

        @Override
        public void onComplete() {
            LogUtils.d("onComplete");
            //下载完成
            showTip("complete");
        }
    });

见状了何等?大家实现Subscriber类时,大家重载了onNext方法,onComplete方法,是还是不是和上边对应起来了? 是的,在MainActivityPresent中的 ”过3秒后作者回到主线程实行了e.onNext(47State of Qatar; 又过3秒小编重返主线程施行了e.onComplete(卡塔尔;” 和这里对应,这里反馈的音信在这里间被调用。

,很难懂,本人渐渐了解

贴个全部的代码

public class BasePresent {

    private WeakReference<Context> mContext ;

    protected BasePresent(Context context){
        mContext = new WeakReference<Context>(context);
    }


    protected Context getContext(){
        return mContext.get();
    }

    protected void runOnUIThread(Runnable runnable){
        //判断Context的合理
        if(runnable==null || mContext.get() == null || !(mContext.get() instanceof Activity)){
            return ;
        }
        ((Activity)mContext.get()).runOnUiThread(runnable);

    }
}

public class MainActivityPresent extends BasePresent {


    public MainActivityPresent(Context context) {
        super(context);
    }

    public void login(final Login login , final Consumer<String> consumer){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //登陆代码.....
                LogUtils.d("login");
                //runOnUIThread
                String result = "登陆成功";
                final Flowable flowable = Flowable.just(result);
                runOnUIThread(new Runnable() {
                    @Override
                    public void run() {
                        flowable.subscribe(consumer);
                    }
                });

            }
        }).start();


    }

    public void downloadImage(final String url ,final Subscriber<Integer> subscriber){

        Flowable<Integer> flowable = Flowable.create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(final FlowableEmitter<Integer> e) throws Exception {
                LogUtils.d("subscribe");
                //下载代码
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(3000);
                            //传回更新数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onNext(47);
                                }
                            });
                            Thread.sleep(3000);
                            //传回下载完成数据
                            runOnUIThread(new Runnable() {
                                @Override
                                public void run() {
                                    e.onComplete();
                                }
                            });
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }, BackpressureStrategy.BUFFER);
        flowable.subscribe(subscriber);

    }


}

public class MainActivity extends BaseActivity {

    MainActivityPresent present ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        present = new MainActivityPresent(this);

        //对于只需要结果的数据,可以使用简单的Consumer
        present.login(new Login(), new Consumer<String>() {
            @Override
            public void accept(@NonNull String s) throws Exception {
                //登陆结果,s表示view需要present返回的类型
                LogUtils.d("accept");
                //showTip(s);
            }
        });

        //对于需要过程的数据,需要用Subscriber,我们需要一个进度,这里选用Integer为进度消息
        present.downloadImage("", new Subscriber<Integer>() {
            @Override
            public void onSubscribe(Subscription s) {
                    LogUtils.d("onSubscribe");
                //开始请求
                showTip("start", Toast.LENGTH_SHORT);
                s.request(Long.MAX_VALUE);
            }

            @Override
            public void onNext(Integer integer) {
                LogUtils.d("onNext");
                //进度有更新
                showTip(integer "", Toast.LENGTH_SHORT);
            }

            @Override
            public void onError(Throwable t) {
                LogUtils.d("onError");
                //下载出错
            }

            @Override
            public void onComplete() {
                LogUtils.d("onComplete");
                //下载完成
                showTip("complete");
            }
        });
    }
}

4.结尾在Activity中重写onPause方法,在该办法中利用SharedPreferences保存数据,确定保障当使用被kill时,金币总量能够保留下来,当然,由于是应用SharedPreferences进行保存,所以当使用被卸载比量齐观装时,保存的数码自然会屏弃,应用则会初步化到先前时代的金币值

末尾就代码来张开详述:

主分界面的Acivity类如下:

[java]view plaincopy

packagecom.hkk.hi.tiger;

importandroid.app.Activity;

importandroid.content.Intent;

importandroid.content.SharedPreferences;

importandroid.graphics.Color;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.text.TextUtils;

importandroid.view.View;

importandroid.widget.Button;

importandroid.widget.ImageView;

importandroid.widget.TextView;

importandroid.widget.Toast;

importjava.util.Random;

public class MainActivity extends Activity {

private  ImageView mP1Iv, mP2Iv, mP3Iv, mP4Iv, mP5Iv, mP6Iv, mP7Iv, mP8Iv, mP9Iv, mP10Iv, mP11Iv, mP12Iv;

private ImageView[]  mImgArr =new ImageView[12];//使用数据存款和储蓄那12张图纸

private Button mBetBtn, mStartBtn;

private TextView moneyTv;

private String mBetName ="";

//投注的金币和剩下总金币

private int mBetMoney =0;

private int mBetTotalMoney =10000;

//当前入选图片的id

privateint currentId =0;

//使用数据存款和储蓄数据名

private String[] mNameArr = {"苹果1","香蕉1","梨子","西瓜","猕猴桃1","香蕉2","苹果2","芒果","猕猴桃2","草莓","猕猴桃3","橘子"};

private MyHandler mHandler =new MyHandler();

//创造定时器

private AnimThread animThread =new AnimThread();

private TimeThread timeThread =new TimeThread();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView(State of Qatar;//起初化控件

checkMoney(卡塔尔(قطر‎;//获取存款和储蓄的金币

mBetBtn.setOnClickListener(mClickListener);

mStartBtn.setOnClickListener(mClickListener);

//将图纸增加到ImageView[]中

mImgArr[0] = mP1Iv;

mImgArr[1] = mP2Iv;

mImgArr[2] = mP3Iv;

mImgArr[3] = mP4Iv;

mImgArr[4] = mP5Iv;

mImgArr[5] = mP6Iv;

mImgArr[6] = mP7Iv;

mImgArr[7] = mP8Iv;

mImgArr[8] = mP9Iv;

mImgArr[9] = mP10Iv;

mImgArr[10] = mP11Iv;

mImgArr[11] = mP12Iv;

}

/**

* 最初化控件

*/

private void initView() {

mP1Iv = (ImageView) findViewById(R.id.p1_iv);

mP2Iv = (ImageView) findViewById(R.id.p2_iv);

mP3Iv = (ImageView) findViewById(R.id.p3_iv);

mP4Iv = (ImageView) findViewById(R.id.p4_iv);

mP5Iv = (ImageView) findViewById(R.id.p5_iv);

mP6Iv = (ImageView) findViewById(R.id.p6_iv);

mP7Iv = (ImageView) findViewById(R.id.p7_iv);

mP8Iv = (ImageView) findViewById(R.id.p8_iv);

mP9Iv = (ImageView) findViewById(R.id.p9_iv);

mP10Iv = (ImageView) findViewById(R.id.p10_iv);

mP11Iv = (ImageView) findViewById(R.id.p11_iv);

mP12Iv = (ImageView) findViewById(R.id.p12_iv);

mBetBtn = (Button) findViewById(R.id.bet_btn);

mStartBtn = (Button) findViewById(R.id.start_btn);

moneyTv = (TextView) findViewById(R.id.money_tv);

}

/**

* 获取存款和储蓄的金币,假若获得到,则将得到的金币作为总金币数,否则弹出提醒第贰遍游戏、招待降临

*/

private void checkMoney() {

try{

SharedPreferences pref = getSharedPreferences("money", MODE_PRIVATE);

intmTotalMoney = pref.getInt("money",10000);

本文由bwin必赢发布,转载请注明来源

关键词: Android... 易懂 简易 案例 Android开发