浅谈Android设计模式

浅谈Android设计模式
https://blog.csdn.net/xiaoming100001/article/details/80302143

干货|安卓APP崩溃捕获方案——xCrash

http://blog.itpub.net/69945252/viewspace-2674668/

instance 


//双重检查模式DCL,在某些情况下会失效

if instance == null 

synchronized
  instance == null
  
  /静态内部类单例模式,


SingleDemoHolder 
  instance = SingleDemo
  
  
enum  
INSTANCE ,println 

补充下JVM对内部类的加载顺序

 private static class SingleDemoHolder{
        static {
            System.out.println("调用匿名内部类:Inner Static");
        }
        private static final SingleDemo instance = new SingleDemo(3);

    }


SingleDemo SingleDemoHolder.instance

建造者模式:用来创建复杂对象的模式,将其部件解耦。通常Android中的Dialog或者EventBus使用的时候会碰到。


abstract Builder
abstract void buildCpu
abstract create

extends Builder

computer.setmCpu

buildCpu.buildCpu

buildCpu.create

public abstract class Builder {
    public abstract void buildCpu(String cpu);
    public abstract void buildMainboard(String main_board);
    public abstract void buildGraphicsCard(String graphics_card);
    public abstract void buildRam(String ram);

    public abstract Computer create();
}


/**
 * 真正的建造者,实现build的方法,然后返回组建好的对象
 * Created by XQM on 2018/5/13.
 */
public class BuildComputer extends Builder {
    private Computer computer = new Computer();

    @Override
    public void buildCpu(String cpu) {
        computer.setmCpu(cpu);
    }
OOM  内存泄漏 

AAR 应用程序无响应

、享元模式:是池技术的重要实现方式,可以减少应用程序创建对象,降低产生OOM风险,提高程序的性能。


 享元工厂用来创建具体的享元角色,通过map来缓存对象
 * 如果系统存在大量的相似对象或者缓存池的场景可以使用

GoodsFactory 享元工厂
map 
    private static Map<String,Goods> goodsMap = new HashMap<>();

策略模式:定义一系列的算法,把算法封装起来,并且是它们可以相互替换,使得算法可以独立于使用它的客户而独立变化。比如代码有很多if…else或者case,会变得比较臃肿,维护成本也比较高,违背开放封闭原则,通过策略模式就可以简化。


/**
 * 开发
 * Created by XQM on 2018/5/13.
 */
public class APPStrategy implements IDevelopStrategy {
    @Override
    public void develop() {
        System.out.println("产品发话了,需要开发APP");
    }
}

/**
 * 具体的策略
 * Created by XQM on 2018/5/13.
 */
public class WebSiteStrategy implements IDevelopStrategy {
    @Override
    public void develop() {
        System.out.println("产品发话了,需要开发网站");

    }
}

IDevelopStrategy

观察者模式:定义对象间一对多的依赖关系,每当一个对象改变状态时,则所有依赖于它的对象都会得到通知并且被自动更新。常见运用在发布-订阅事件总线。

/**
 * 把所有的观察者对象保存在一个集合中,其中每一个主题可以有任意数量的观察者,可以想象为公众号
 * Created by XQM on 2018/5/13.
 */
public interface ObservedSubject {
    /**
     * 增加观察者
     * @param observer
     */
    void add(Observer observer);

    /**
     * 删除观察者
     * @param observer
     */
    void delete(Observer observer);

    /**
     * 通知更新
     * @param message
     */
    void notify(String message);
}

/**
 * 抽象被观察者的实现类,实现添加、删除和通知观察者的方法
 * Created by XQM on 2018/5/13.
 */
public class SubcriptionSubject implements ObservedSubject {
    private List<Observer> subscriberUsers = new ArrayList<Observer>();
    @Override
    public void add(Observer oberver) {
        subscriberUsers.add(oberver);
    }

    @Override
    public void delete(Observer observer) {
        subscriberUsers.remove(observer);
    }

    @Override
    public void notify(String message) {
        for (Observer observer:subscriberUsers){
            observer.update(message);
        }
    }
}

/**
 * 抽象观察者
 * Created by XQM on 2018/5/13.
 */
public interface Observer {
    void update(String message);
}
/**
 * 具体观察者
 * Created by XQM on 2018/5/13.
 */
public class SubscriberUser implements Observer {
    private String name;

    public SubscriberUser(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name+"更新了:"+message);
    }
}

/**
 * 优点:观察者和被观察者之间是抽象耦合,容易扩展
 * 缺点:在Java中消息的通知一般是按照顺序的,如果每个观察者造成卡顿,会影响整体的效率,采用异步解决
 * Created by XQM on 2018/5/13.
 */
public class ObserverClient {
    public static void main(String[] args){
        SubcriptionSubject subcriptionSubject = new SubcriptionSubject();

        SubscriberUser user1 = new SubscriberUser("下雨了");
        SubscriberUser user2 = new SubscriberUser("下雪了");
        SubscriberUser user3 = new SubscriberUser("落花了");

        //注册订阅
        subcriptionSubject.add(user1);
        subcriptionSubject.add(user2);
        subcriptionSubject.add(user3);

        //发送更新给订阅者
        subcriptionSubject.notify("不一样的博客更新了");

    }


ObservedSubject add  delete Observer notify

public class SubcriptionSubject implements ObservedSubject {
    private List<Observer> subscriberUsers = new ArrayList<Observer>();

 @Override
    public void notify(String message) {
        for (Observer observer:subscriberUsers){
            observer.update(message);
        }
    }


    
    继承Observable类(被观察者发送消息),notifyObservers发送通知
Observable notifyObservers 

Android中MVC、MVP、MVVM的区别与使用
https://www.jianshu.com/p/78e0a508b1c6


Model  View Controller 

Activity/Fragment在View与Controller的定义中有点模糊。

MVP(Model-View-Presenter)是MVC的改良模式。


Model View Presenter做逻辑处理,修改Model

Android 架构设计实现——MVP模式

http://www.voidcn.com/article/p-ztnemdmt-mn.html


基于 MVC(Model View Controller) 模式的 MVP(Model-View-Presenter) 模式应运而生

只要保证我们是通过 Presenter 将 View 和 Model 解耦合、降低类型复杂度、各个模块可以独立测试、独立变化,这就是正确的方向。

IModel IPresenter IView


LoginContract 
 LoginView         LoginPresenter
 
 public class BaseModel implements IModel {
    // 做一些数据处理, 网路请求的初始化操作
}


然后定义交互中间人 LoginPresenter,处理 View 的业务逻辑,它是沟通 View 和 Model 的桥梁,Presenter 持有的 View、Model 引用都是抽象,且经常会执行耗时操作:


Presenter 持有View,Model 引用都是抽象,且经常会执行耗时操作:

LoginPresenter extends BasePresenter<LoginActivity>

getiModelMap().get("login")).login(name, pwd, new LoginModel

getIView().loginSuccess(result); // 成功


vvvvvvvvv决这个问题需要通过弱引用来解决,LoginPresenter 的父类 BasePresenter 如下:

WeakReference IView iview


public class LoginActivity extends AppCompatActivity implements IView, LoginContract.LoginView {

LoginContract.LoginView,IView

MVP的特点
View接受事件,传递给Presenter
Presenter做逻辑处理,修改Model
Model通知Presenter数据变化,Presenter更新View
MVP的优点
将Model与View完全分隔,提高了可扩展性。
便于测试。在测试Presenter时,只要实现View的接口并注入到Presenter就可以测试Presenter的业务逻辑。
MVP的缺点
与MVC一样,P层起到的控制功能伴随着业务的增多,也会变得臃肿。
Presneter需要持有View的引用,同时View也需要持有Presenter的引用,控制上存在一定复杂度。

Presenter

MVP
View -Presenter-Model
Model-Presenter-View

Android DataBinding 从入门到进阶

https://juejin.im/post/6844903609079971854


ViewModel-Presenter        DataBinding

android {
    dataBinding {
        enabled = true
    }
}


dataBinding enabled

layout data 

MVVM

Model  View  data


getRoot

alias = "TempUser"

variable
name type

DataBindingUtil.setContentView

notifyPropertyChangedPro

activityMain2Binding.setUserInfo 


@{userInfo.name}

13

fragmentBlankBinding

ViewDataBinding

实现数据变化自动驱动 UI 刷新的方式有三种:BaseObservable、ObservableField、ObservableCollection


notifyChange        


    android:onClick="@{()->goodsHandler.changeGoodsName()}"

@{()->{}

BaseObservable ObservableField ObservableCollection


DataBindingUtil.setContentView


OnPropertyChangedCallback


onPropertyChanged


 if (propertyId == com.leavesc.databinding_demo.BR.name) {

ObservableParcelable 

ObservableDouble

ObservableField


可通过 ObservableField 泛型来申明其他类型

@{list[index],default =xx}

ObservableArrayList    list 


ObservableMap
DataBindingUtil.setContentView

ObservableArrayMap

setMap  setList

三、双向数据绑定

双向绑定的意思即为当数据改变时同时使视图刷新,而视图改变时也可以同时改变数据

@={}


activityMain10Binding.setGoods 


data -view , view-data

onClick = android:onClick="@{()->userPresenter.onUserNameClick(userInfo)}"
@ {() ->}

include viewStub

include layout

name 
type

在主布局文件中将相应的变量传递给 include 布局,从而使两个布局文件之间共享同一个变量

include
bind

  
        <include
            layout="@layout/view_include"
            bind:userInfo="@{userInfo}" />


bind:userInfo

layout  data import 

variable name  = " "
type = ""

activityMain6Binding.viewStub.getViewStub.inflate

ViewStub 标签懒加载
https://www.jianshu.com/p/9f2e7cf9a0b4


要被加载的布局通过 android:layout 属性来设置. 然后在程序中调用 inflate() 方法来加载. 还可以设定 Visibility 为 VISIBLE 或 INVISIBLE, 也会触发 inflate(). 但只有直接使用 inflate() 方法能返回布局文件的根 View. 但是这里只会在首次使用 setVisibility() 会加载要渲染的布局文件. 再次使用只是单纯的设置可见性.

对 inflate() 操作也只能进行一次, 因为 inflate() 的时候是其指向的布局文件替换掉当前 <ViewStub> 标签. 之后, 原来的布局文件中就没有 <ViewStub> 标签了. 因此, 如果多次 inflate() 操作, 会报错: ViewStub must have a non-null ViewGroup viewParent

inflate

<ViewStub> 标签实质上是一个宽高都为 0 的不可见 View. 通过延迟加载布局的方式优化布局提升渲染性能.


Android性能优化之一:ViewStub
https://www.cnblogs.com/lwbqqyumidi/p/4047108.html

.布局文件inflate时,ViewStub主要是作为一个“占位符”的性质,放置于view tree中,且ViewStub本身是不可见的。ViewStub中有一个layout属性,指向ViewStub本身可能被替换掉的布局文件,在一定时机时,通过viewStub.inflate()完成此过程;


viewStub.inflate

layout ViewStub


viewStub.infalte()或viewStub.setVisibility(View.VISIBLE)来完成;
 if (noDataView == null) {
 4         ViewStub noDataViewStub = (ViewStub) view.findViewById(R.id.no_data_viewstub);
 5         noDataView = noDataViewStub.inflate();
 6     } else {
 7         noDataView.setVisibility(View.VISIBLE);
 8     }


结合ViewStub“占位符”可以比较好的完成此类需求


ViewStub layout bind:userInfo = "@{userInfo}"


     activityMain6Binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
            @Override
            public void onInflate(ViewStub stub, View inflated) {
   //如果在 xml 中没有使用 bind:userInfo="@{userInf}" 对 viewStub 进行数据绑定
                //那么可以在此处进行手动绑定
                ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);
                viewStubBinding.setUserInfo(user);
                Log.e(TAG, "onInflate");


    ActivityMain6Binding activityMain6Binding = DataBindingUtil.setContentView(this, R.layout.activity_main6);
    View view = activityMain6Binding.viewStub.getViewStub().inflate();


   ViewStubBinding viewStubBinding = DataBindingUtil.bind(inflated);

   
   
   DataBindingUtil.bind inflated


例如,对于一个 ImageView ,我们希望在某个变量值发生变化时,可以动态改变显示的图片,此时就可以通过 BindingAdapter 来实现


BindingAdapter("url")

loadImage   

<data   <variable     name = "image"

<ConstraintLayout

 bind:url="@{image.url}" />


BindingConversion

@{String}    -conversionString

BindingConversion background textColor    

background->Drawable    textColor->Color

Array List Set Map&lt

dataBinding     list[index]


SparseArray

variable array String[]

list    map

  android:text='@{@string/format("leavesC", "Ye")}'
  
  @{@string/format("","")}

三.MVVM
MVVM实现了数据与UI的双重绑定,其中DataBinding是实现MVVM的关键工具。

Model
与MVC和MVP一样,Model层保存了业务数据与处理方法
View
对应Activity以及XML,但是比起MVC与MVP框架中的View层,更加简洁
ViewModel
负责实现View与Model的交互,将两者分离

MVVM  Model View  ViewModel  DataBinding


View     -  ViewModel  - Model


  MVVM的特点
View接受事件,转交给ViewModel
ViewModel操作Model更新数据
Model更新后通知ViewModel,ViewModel更新View数据
MVVM的优点
低耦合。由于ViewModel的存在,View可以独立于Model变化与修改;同理,Model也可以独立于View变化与修改。
可重用性。一个ViewModel可被多个View重复绑定,实现同一组业务。
ViewModel中解决了MVP中V-P互相持有引用的问题,使得结构更清晰,简洁
MVVM的缺点
ViewModel持有Model的依赖。
数据绑定方式使得bug难以确定是在View中还是在Model中。


MVVM  ViewModel   MVP V-P ->View,Presenter
  

Android之生产者/消费者设计模式解释
https://blog.csdn.net/haigand/article/details/90551070

这种设计模式需要满足以下三点要求:

(1)生产者生产数据到缓冲区中,消费者从缓冲区中取数据。
(2)如果缓冲区已经满了,则生产者线程阻塞;
(3)如果缓冲区为空,那么消费者线程阻塞。


PublicQueue


synchronized add

LinkedHashMap<Integer,T>
wait       notifyAll


     Iterator it = linkedHashMap.entrySet().iterator();
        T t = null;
        if(it.hasNext()){
            Map.Entry<Integer, T> entry = (Map.Entry<Integer, T>) it.next();
            t = entry.getValue();
            int index = entry.getKey();
            linkedHashMap.remove(index);
            System.out.println("消费一个产品,当前商品角标为:"+index+"===文本为:"+ t +"===缓存长度为:"+linkedHashMap.size());
        }
        return t;
    }

iterator it.next


/**
 * 生产者线程
 */
public class ProducerThread extends Thread {
 
    private PublicQueue publicQueue;
 
    public ProducerThread(PublicQueue publicQueue){
        this.publicQueue = publicQueue;
    }
 
    @Override
    public void run() {
        for(int i=0;i<60;i++){
            publicQueue.add(String.valueOf(i));
        }
    }
}


/**
 * 消费者线程
 */
public class ConsumerThread extends Thread {
 
    private PublicQueue publicQueue;
 
    public ConsumerThread(PublicQueue publicQueue){
        this.publicQueue = publicQueue;
    }
 
    @Override
    public void run() {
        for(;;){
            publicQueue.remove();
        }
    }
}

lock condition       wait signalAll

lock addCondition removeCondition


Map.Entry<Integer,T> entry

BlockingDeque

blockingDeque.put msg


blockingDeque.take


总结:

有关缓存队列的处理有三种方法:
(1)双向链表LinkedHashMap和synchronized结合;
(2)双向链表LinkedHashMap和lock结合;
(3)直接使用阻塞队列BlockingQueue。

LinkedHashMap synchronized


lock     newCondition

unlock await notifyAll

BlockingDeque

Android的设计模式-观察者模式


https://www.jianshu.com/p/8f32da74cd8b

1.定义
定义对象间的一种一个对多的依赖关系,当一个对象的状态发送改变时,所以依赖于它的对象都得到通知并被自动更新。


notifies

    public interface Observer {//抽象观察者
        public void update(String message);//更新方法
    }


Observer(抽象观察者)这两个类,我们也可以直接拿来用,其代码如下:


Observable

    public interface  Observable {//抽象被观察者
         void add(Observer observer);//添加观察者
 
         void remove(Observer observer);//删除观察者
    
         void notify(String message);//通知观察者
    }

Observable observer

实际上,JDK内部也内置了Observable(抽象被观察者),Observer(抽象观察者)这两个类

bu

Observable ArrayList<>observers            


. 应用场景
当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
当一个对象必须通知其它对象,而它又不能假定其它对象是谁
跨系统的消息交换场景,如消息队列、事件总线的处理机制。

        Button button = (Button) findViewById(R.id.button);
        //注册观察者
        button.setOnClickListener(new View.OnClickListener() {
            //观察者实现
            @Override
            public void onClick(View arg0) {
                Log.d("test", "Click button ");
            }
        });

        .setOnClickListener        onClick


//数据集被观察者
public class DataSetObservable extends Observable<DataSetObserver> {
   
    public void notifyChanged() {
        synchronized(mObservers) {
            //遍历所有观察者,并调用他们的onChanged()方法
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }

    //其他代码略
}


AdapterDataSetObserver

ListView notifyDataSetChanged AdapterDataSetObserver
onChanged requestLayout

BroadcastReceiver sendBro

IntentFilter onReceive

角色说明:
Subject(抽象主题):又叫抽象被观察者,把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject(具体主题):又叫具体被观察者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
Observer (抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,当得到主题更改通知时更新自身的状态。

Subject(抽象主题):又叫抽象被观察者,把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。 
Observer
ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,当得到主题更改通知时更新自身的状态。
ConcreteSubject(具体主题):又叫具体被观察者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。


适配器模式,装饰者模式,外观模式的异同?

https://blog.csdn.net/github_37130188/article/details/89762810


小结:装饰者模式——动态地将责任附加到对象上。想要扩展功能,装饰者提供了有别于继承的另外一种选择。是一个很好的符合了开闭原则的设计模式。

Android的设计模式-适配器模式
https://www.jianshu.com/p/31686bf8f9a2

PhoneAdapter

     public void test() {
        Electric electric = new Electric();
        System.out.println("默认电压:" + electric.output_220v());

        Adapter phoneAdapter = new PhoneAdapter(electric);//传递一个对象给适配器
        System.out.println("适配转换后的电压:" + phoneAdapter.convert_5v());

    }


A23


 mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        mAdapter = new MyAdapter(getData());

LinearLayoutManager        MyAdapter

   // 设置布局管理器
        mRecyclerView.setLayoutManager(mLayoutManager);
        // 设置adapter
        mRecyclerView.setAdapter(mAdapter);


onCreateViewHolder


ViewHolder

onBindViewHolder    ViewHolder holder


Android的设计模式-装饰者模式


https://www.jianshu.com/p/df1a96c5c046


Decorator(抽象装饰角色):一般是抽象类,抽象组件的子类,同时持有一个被装饰者的引用,用来调用被装饰者的方法

ConcreteDecorator(具体装饰类):抽象装饰角色的具体实现。

abstract Room
fitment

NewRoom except 

     public abstract class RoomDecorator extends Room {//继承Room,拥有父类相同的方法
        private Room mRoom;//持有被装饰者的引用,这里是需要装修的房间

        public RoomDecorator(Room room) {
            this.mRoom = room;
        }

        @Override
        public void fitment() {
            mRoom.fitment();//调用被装饰者的方法
        }
    }


public abstract RoomDecorator    

  public abstract class RoomDecorator extends Room {//继承Room,拥有父类相同的方法

  @Override
        public void fitment() {
            mRoom.fitment();//调用被装饰者的方法
        }

 public class Bedroom extends RoomDecorator {//卧室类,继承自RoomDecorator

   @Override
        public void fitment() {
            super.fitment();
            }


abstract class Context 


abstract void startActivity        @RequiresPermission Intent intent

ContextImpl        


    mMainThread.getInstrumentation().execStartActivity(
                    getOuterContext(), mMainThread.getApplicationThread(), null,
                    (Activity) null, intent, -1, options);
                    
    mMainThread.getInstrumentation.execStartActivity

getOuterContext,    
                    
ContextWrapper        ContextThe

        public class ContextWrapper extends Context {//Context包装类
        Context mBase;//持有Context引用

        public ContextWrapper(Context base) {//这里的base实际上就是ContextImpl
            mBase = base;
        }

        @Override
        public void startActivity(Intent intent) {
            mBase.startActivity(intent);//调用ContextImpl的startActivity()方法
        }

        //其他代码略
    }

Context类在这里就充当了抽象组件的角色,ContextImpl类则是具体的组件,
而ContextWrapper就是具体的装饰角色,通过扩展ContextWrapper增加不同的功能,
就形成了Activity、Service等子类。
最后,放一张总的UML类图帮助理解:

ContextImpl ContextWrapper ContextImpl


Context 抽象组件  ContextImpl 具体的组件
ContextWrapper装饰


Context ContextImpl

ContextWrapper    
 

理解RxJava:(一)基础知识
https://www.cnblogs.com/JohnTsai/p/5695560.html


响应式代码的基本构成部分是Observables和Subscribers(译者注:技术名词很难找到合适的中文翻译,所以维持原文不被翻译)。Observable发出items,Subscriber消费这些items。

Observables Subscribers


Observable->Subscriber


  new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> sub) {

OnSubscribe Subscriber

myObservable.subscribe(mySubscriber);

Subscribers被认定是做出反应(reacts)的事物,而不是做出转变(mutates)的事物。

Operators介绍


.map
map(new Func1<String, Integer>() {
.map (new Func1<>)


Observable.just("Hello, world!")
   .map(s -> s + " -Dan")
   .map(s -> s.hashCode())
   .map(i -> Integer.toString(i))
   .subscribe(s -> System.out.println(s));


Observable(被观察者) Subscriber(观察者)

Observale可以是数据库查询,Subscriber得到结果并将它们显示在屏幕上。Observable可以是屏幕上的点击,Subscriber对它做出反应。Observable可以是从网络读取的字节流,Subscriber把它写入磁盘。

RxJava是个能够处理任何问题的通用框架。

理解RxJava:(二)Operator,Operator

https://www.cnblogs.com/JohnTsai/archive/2004/01/13/5700120.html


operators


//返回一个基于文本查询网站链接的列表
Observable<List<String>> query(String text); 

.subscribe  
Observable.from urls
.subscribe url
屏住你的呼吸,因为你见到了你的救世主:flatMap()。

Observable.flatMap()获取一个Observable的返回值,将值发给另一个取代它的Observable。如下:


flatMap new Func1  String ,Observable

call   List <String>  urls


Observable.from       urls           

flatMap()(看起来)很怪,对吗?为什么返回另一个Observable?核心概念是新的Observable返回的正是Subscriber所观察的。

它不接收List<String>——它接收Observable.from()返回的一系列的单独的Strings。

 .flatMap(new Func1<List<String>, Observable<String>>() {
        @Override
        public Observable<String> call(List<String> urls) {
            return Observable.from(urls);
        34
    })
    
    .flatMap(urls -> Observable.from(urls))


     .flatMap(urls -> Observable.from(urls))
    .flatMap(new Func1<String, Observable<String>>() {
        @Override
        public Observable<String> call(String url) {
            return getTitle(url);
        }
    })
    
    
    
     .flatMap(new Func1<List<String>, Observable<String>>() {
        @Override
        public Observable<String> call(List<String> urls) {
            return Observable.from(urls);
        }
    })
    在把一系列的URL分开为单独的items后
    
     .doOnNext(title -> saveTitle(title))
    query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .subscribe(title -> System.out.println(title));
    
    .filter .take ()
    
    
    理解RxJava:(三)RxJava的优点
    https://www.cnblogs.com/JohnTsai/archive/2004/01/13/5704191.html
    
    
    
    调度者(Schedulers)
    
    
    subscribeOn Observer
    
    observeOn  Subscriber
    
    
    Subscriptions).unsubscribe
    
    理解RxJava:(四)Reactive Android
    
    
    https://www.cnblogs.com/JohnTsai/archive/2004/01/13/5708704.html
    
    
    subscribeOn  Schedulers.io
    
    
    ViewObservable.clicks .subscribe 
    
    Observable.zip
    Observable<Photo>
    .subscribe
    
    
    Observable.defer(()->Observable.just);
    
    
    现在, 直到你订阅Observable才会去调用slowBlockMethod()方法。
    
    request.subscribe
    
    
    
    
    
    
    

 

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付 39.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值