初识Agera(二)——结合Demo介绍Agera的用法

前言

在上一篇我讲了Agera的基本概念和原理,但是有人估计会说你这讲的是什么呀,看的我好懵逼呀,talk is cheap,show me your code!我接下来就结合demo来讲一下Agera的用法。。

功能分析

接下来要写的demo是一个下拉刷新改变数据的demo。这个功能很常见吧,在很多的应用中都有这个功能吧,下拉之后向网络发送请求,然后改变数据。接下来利用这个demo来更好演示Agera的用法。

利用回调

我们很常见的思路就是回调吧,当数据加载成功或者失败后回调给页面。因此接下来就用这种思路完成demo。首先分析下流程:

  1. 下拉
  2. 获取数据
  3. 更新页面

因此需要监听下拉这个事件的触发,因此就需要一个observable同时实现OnRefreshListener,就命名为OnRefreshObservable,接着获取数据的对象需要监听这个下拉事件,又要通知界面更新,因此就需要实现observable和updatable的责任,同时又要提供数据,也就也需要实现Supplier的责任。那么为什么需要回调呢?因为往往获取数据是一个耗时的任务,我们会新开一个线程用于处理,那么当他失败或者成功的时候使用接口回调进行处理,就命名为UsernamesRepository。最后就是页面更新了,页面需要监听UsernamesRepository,也就需要实现updatable的责任。流程分析了,就下来就该写代码了
首先先描述一下界面:

#MainActivity
public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}
#activity_main
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="?attr/colorPrimary"        android:minHeight="?attr/actionBarSize"        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"        app:theme="@style/Toolbar" />    <fragment        android:id="@+id/fragment"        android:name="com.example.lizheng.myapplication.MainFragment"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>
#main_frag
<?xml version="1.0" encoding="utf-8"?><android.support.v4.widget.SwipeRefreshLayout    android:id="@+id/refresh_layout"    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"    android:layout_height="match_parent">    <ListView        android:id="@+id/list"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:paddingBottom="@dimen/activity_vertical_margin"        android:paddingLeft="@dimen/activity_horizontal_margin"        android:paddingRight="@dimen/activity_horizontal_margin"        android:paddingTop="@dimen/activity_vertical_margin"/></android.support.v4.widget.SwipeRefreshLayout>

布局很简单,fragment由一个下拉刷新控件内嵌套一个listview组成。mainActivity则是由一个toolbar和这个fragment组成。布局写好了,接下来就得按着流程来实现功能了。
首先就是需要让该OnRefreshListener实现Observable功能

public class OnRefreshObservable extends BaseObservable
        implements SwipeRefreshLayout.OnRefreshListener {
    //当下拉刷新触发时同时通知监听者更新,这样就让OnRefreshListener同时实现了observable的功能
    @Override
    public void onRefresh() {
        dispatchUpdate();
    }
}

接下来就应该实现获取数据的功能:

#UsernamesFetcher 
//具体获取姓名数据
public class UsernamesFetcher {
    //模拟数据数量为4
    public static int NUMBER_OF_USERS = 4;
    //模拟获取数据,采取新线程异步加载,利用接口回调
    public void getUsernames(final UsernamesCallback callback) {
        if (NUMBER_OF_USERS < 0) {
            callback.setError();
            return;
        }
        new Thread(){
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);  //模拟网络耗时
                    // Create a fake list of usernames
                    Log.i("MainActivity","current "+Thread.currentThread().getName()+" "+currentThread().getId());
                    String name1 = "Joe";
                    String name2 = "Amanda";
                    final List<String> usernames = new ArrayList<String>();
                    Random random = new Random();
                    for (int i = 0; i < NUMBER_OF_USERS; i++) {
                        int number = random.nextInt(50);
                        if (System.currentTimeMillis() % 2 == 0) {
                            usernames.add(name1 + number);
                        } else {
                            usernames.add(name2 + number);
                        }
                    }
                    callback.setUsernames(usernames.toArray(new String[usernames.size()]));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
    //回调接口,用于区分数据获取成功还是失败
    public interface UsernamesCallback {
        void setError();
        void setUsernames(String[] usernames);
    }
}```
上面这个类是具体的获取数据的类,里面封装了获取数据的函数和相关回调接口。之后便是最为关键的UsernamesRepository:

//该类需要实现observable,updatable和supplier功能
public class UsernamesRepository extends BaseObservable
implements Supplier<String[]>, Updatable, UsernamesFetcher.UsernamesCallback {

private String[] usernames;//姓名数据列表
private boolean lastRefreshError;//用于判定是否更新成功
private final UsernamesFetcher usernamesFetcher;

public UsernamesRepository(UsernamesFetcher usernamesFetcher) {
    super();
    this.usernamesFetcher = usernamesFetcher;
}

/**
 * 获取最新的数据,继承自Supplier
 */
@NonNull
@Override
public String[] get() {
    return usernames;
}

/**
 * 返回值表示最近更新是否成功
 */
public boolean isError() {
    return lastRefreshError;
}

/**
 * 继承自updatable,更新姓名数据
 */
@Override
public void update() {
    usernamesFetcher.getUsernames(this);
}

/**
 * 当数据获取失败时,回调接口调用
 */
@Override
public void setError() {
    lastRefreshError = true;
    dispatchUpdate();  //通知UsernamesRepositoryuser的监听者更新
}

/**
 * 获取数据成功时调用
 */
@Override
public void setUsernames(String[] usernames) {
    this.usernames = usernames;
    lastRefreshError = false;
    dispatchUpdate();
}

/**
 * 当从0个监听者到1个监听者时调用。
 */
@Override
protected void observableActivated() {
    update();
}

}```
之后就是MainFragment:

public class MainFragment extends Fragment implements Updatable {

 
    private OnRefreshObservable refreshObservable;

   
    private UsernamesRepository usernamesRepository;

    private ListAdapter listAdapter;

    private ListView listView;

    private SwipeRefreshLayout swipeRefreshLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.main_frag, container, false);

        listView = (ListView) root.findViewById(R.id.list);

        //设置下拉刷新相关设置并且将监听器绑定到view上,这样,refreshObservable就设置好了
        refreshObservable = new OnRefreshObservable();
        swipeRefreshLayout = (SwipeRefreshLayout) root.findViewById(R.id.refresh_layout);
        swipeRefreshLayout.setColorSchemeColors(
                ContextCompat.getColor(getActivity(), R.color.colorPrimary),
                ContextCompat.getColor(getActivity(), R.color.colorAccent),
                ContextCompat.getColor(getActivity(), R.color.colorPrimaryDark));
        swipeRefreshLayout.setOnRefreshListener(refreshObservable);

        // 初始化UsernamesRepository
        usernamesRepository = new UsernamesRepository(new UsernamesFetcher());

        return root;
    }

    @Override
    public void onResume() {
        super.onResume();

        //使repository监听refreshObservable
        refreshObservable.addUpdatable(usernamesRepository);

        //mainFragment监听repository
        usernamesRepository.addUpdatable(this);

        // 确保每次进入应用时显示刷新动画
        swipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                swipeRefreshLayout.setRefreshing(true);
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();
        //避免内存泄漏,移除观察者
        refreshObservable.removeUpdatable(usernamesRepository);
        usernamesRepository.removeUpdatable(this);
    }

  
    @Override
    public void update() {
       //更新完数据后取消动画
        swipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                swipeRefreshLayout.setRefreshing(false);
            }
        });

        // 检查数据获取错误
        if (usernamesRepository.isError()) {
            Toast.makeText(getContext(), getResources().getString(R.string.error),
                    Toast.LENGTH_LONG).show();
        } else {
            // 更新页面数据
            listAdapter = new ArrayAdapter<String>(getContext(),
                    android.R.layout.simple_list_item_1, usernamesRepository.get());
            listView.setAdapter(listAdapter);
        }
    }
}

MainActivity则是简单的几行代码:

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }}

既然代码写好了,接下来就结合代码分析下事件的流程,但是要想知道代码如何运行,就要先知道Agera的事件传递机制:

  1. observable首次添加updatable->addUpdatable(Updatable)->workerhandler(handler.obtainMessage(WorkerHandler.MSG_FIRST_ADDED, this).sendToTarget();)->workerHandler.callFirstUpdatableAdded()->observable.observableActivated().
  2. 当observable发出事件->调用dispatchUpdate()->workerhandler发送信息(handler.obtainMessage(MSG_UPDATE, this).sendToTarget();)->workerhandler调用sendUpdate()->如果是当前线程和添加updatable时所在的线程是同一线程,监听者直接开始update,否则workhandler发送消息(handler.obtainMessage(WorkerHandler.MSG_CALL_UPDATABLE, updatable).sendToTarget();),然后updatable更新。
  3. 当observable移除最后一个updatable->removeUpdatable(Updatable)->workerhandler发送信息(handler.obtainMessage(MSG_LAST_REMOVED, this).sendToTarget();)->workerHandler调用callLastUpdatableRemoved()->observable.observableDeactivated()

上面讲了Agera的几个事件的传递流程,接下来就结合demo分析代码的执行流程了:

  1. 进入应用 onResume()->为refreshObservable添加监听者usernamesRepository->为usernamesRepository添加监听者MainFragment->(中间省略了一些Agera的传递)usernamesRepository.observableActivated->usernamesRepository.update(重写了observableActivated(),调用了update())->swipeRefreshLayout.setRefreshing(true)(进入应用时显示刷新动画)->MainFragment.update().这样当进入界面的时候就更新完毕了。
  2. 下拉刷新触发OnRefreshObservable.onRefresh()->(重写了onRefresh方法)dispatchUpdate()(继承自BaseObservable)->(省略了Agera的传递机制)UsernamesRepository.update()->usernamesFetcher.getUsernames()获取数据->如果获取成功UsernamesRepository调用setUsernames,否则调用serError->dispatchUpdate()(继承自BaseObservable)->MainFragment开始updata()。这样一次下拉刷新就完成了数据的更新。
  3. 退出应用或者使其成为后台应用一定会发生onpause()->refreshObservable.removeUpdatable(usernamesRepository)为refreshObservable移除监听者->refreshObservable.observableDeactivated()->usernamesRepository.removeUpdatable(this)为usernamesRepository移除监听者->usernamesRepository.observableDeactivated().这样但不需要下拉刷新的时候就移除观察者使其不能再刷新数据,同时这也是为了避免内存泄漏。让observable添加和删除updatable与fragment等的生命周期相对应。

利用CompiledRepository

首先你得知道Repository是什么吧

public interface Repository<T> extends Observable, Supplier<T> {}

所以我们知道repository实现了被观察者的作用同时也能提供数据。那么CompiledRepository

final class CompiledRepository extends BaseObservable    implements Repository, Updatable, Runnable{
    ...
}

那么如何使用它呢?

public class MainFragment extends Fragment implements Updatable {

    
    private OnRefreshObservable refreshObservable;

    
    private Repository<Result<List<String>>> usernamesRepository;

    private ListAdapter listAdapter;

    private ListView listView;

    private SwipeRefreshLayout swipeRefreshLayout;

    private ExecutorService networkExecutor;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.main_frag, container, false);

        listView = (ListView) root.findViewById(R.id.list);

  
        refreshObservable = new OnRefreshObservable();
        swipeRefreshLayout = (SwipeRefreshLayout) root.findViewById(R.id.refresh_layout);
        swipeRefreshLayout.setColorSchemeColors(
                ContextCompat.getColor(getActivity(), R.color.colorPrimary),
                ContextCompat.getColor(getActivity(), R.color.colorAccent),
                ContextCompat.getColor(getActivity(), R.color.colorPrimaryDark));
        swipeRefreshLayout.setOnRefreshListener(refreshObservable);

        setUpRepository();

        return root;
    }

    private void setUpRepository() {
        //后台执行
        networkExecutor = newSingleThreadExecutor();

        //设置repository,关键代码
        usernamesRepository = Repositories
                .repositoryWithInitialValue(Result.<List<String>>absent())
                .observe(refreshObservable)
                .onUpdatesPerLoop()
                .goTo(networkExecutor)
                .thenGetFrom(new UsernamesSupplier())
                .compile();
    }

    @Override
    public void onResume() {
        super.onResume();
  
        usernamesRepository.addUpdatable(this);

        swipeRefreshLayout.post(new Runnable() {
            @Override
            public void run() {
                update();
            }
        });
    }

    @Override
    public void onPause() {
        super.onPause();

        usernamesRepository.removeUpdatable(this);
    }

  
    @Override
    public void update() {
        //进行获取数据的判定
        //如果拿到的是最初的数据就开始刷新
        if (usernamesRepository.get().isAbsent()) {
            swipeRefreshLayout.setRefreshing(true);
          //如果数据获取失败就提示
        } else if (usernamesRepository.get().failed()) {
        
            Toast.makeText(getContext(), getResources().getString(R.string.error),
                    Toast.LENGTH_LONG).show();
            swipeRefreshLayout.setRefreshing(false);
        } else {
            listAdapter = new ArrayAdapter<String>(getContext(),
                    android.R.layout.simple_list_item_1, usernamesRepository.get().get());
            listView.setAdapter(listAdapter);
            swipeRefreshLayout.setRefreshing(false);
        }
    }
}```
大部分代码和之前类似。。而这一句代码便是CompiledRepository的使用方法

usernamesRepository = Repositories
.repositoryWithInitialValue(Result.<List<String>>absent())
.observe(refreshObservable)
.onUpdatesPerLoop()
.goTo(networkExecutor)
.thenGetFrom(new UsernamesSupplier())
.compile();

感觉没有看过源代码也能理解这句话,果然使用很简单
 .repositoryWithInitialValue(Result.<List<String>>absent())是创建一个Repository并为其赋初值;
 .observe(refreshObservable)表示监听refreshObservable;
.onUpdatesPerLoop()表示更新的频率
.goTo(networkExecutor)表示将指令在后台执行
 .thenGetFrom(new UsernamesSupplier())表示从UsernamesSupplier中获取数据
.compile得到repository实例。但是为什么要这么写呢?因为这种repository是有state的,你得按照状态一步一步来

public interface RepositoryCompilerStates {

interface REventSource<TVal, TStart> {

@NonNull
RFrequency<TVal, TStart> observe(@NonNull Observable... observables);

}

interface RFrequency<TVal, TStart> extends REventSource<TVal, TStart> {

@NonNull
RFlow<TVal, TStart, ?> onUpdatesPer(int millis);


@NonNull
RFlow<TVal, TStart, ?> onUpdatesPerLoop();

}

interface RFlow<TVal, TPre, TSelf extends RFlow<TVal, TPre, TSelf>>
extends RSyncFlow<TVal, TPre, TSelf> {

@NonNull
@Override
<TCur> RFlow<TVal, TCur, ?> getFrom(@NonNull Supplier<TCur> supplier);

@NonNull
@Override
<TCur> RTermination<TVal, Throwable, RFlow<TVal, TCur, ?>> attemptGetFrom(
    @NonNull Supplier<Result<TCur>> attemptSupplier);

@NonNull
@Override
<TAdd, TCur> RFlow<TVal, TCur, ?> mergeIn(@NonNull Supplier<TAdd> supplier,
    @NonNull Merger<? super TPre, ? super TAdd, TCur> merger);

@NonNull
@Override
<TAdd, TCur> RTermination<TVal, Throwable, RFlow<TVal, TCur, ?>> attemptMergeIn(
    @NonNull Supplier<TAdd> supplier,
    @NonNull Merger<? super TPre, ? super TAdd, Result<TCur>> attemptMerger);

@NonNull
@Override
<TCur> RFlow<TVal, TCur, ?> transform(@NonNull Function<? super TPre, TCur> function);

@NonNull
@Override
<TCur> RTermination<TVal, Throwable, RFlow<TVal, TCur, ?>> attemptTransform(
    @NonNull Function<? super TPre, Result<TCur>> attemptFunction);



@NonNull
TSelf goTo(@NonNull Executor executor);


@NonNull
RSyncFlow<TVal, TPre, ?> goLazy();

}

interface RSyncFlow<TVal, TPre, TSelf extends RSyncFlow<TVal, TPre, TSelf>> {

@NonNull
<TCur> RSyncFlow<TVal, TCur, ?> getFrom(@NonNull Supplier<TCur> supplier);


@NonNull
<TCur>
RTermination<TVal, Throwable, ? extends RSyncFlow<TVal, TCur, ?>> attemptGetFrom(
    @NonNull Supplier<Result<TCur>> attemptSupplier);


@NonNull
<TAdd, TCur> RSyncFlow<TVal, TCur, ?> mergeIn(@NonNull Supplier<TAdd> supplier,
    @NonNull Merger<? super TPre, ? super TAdd, TCur> merger);


@NonNull
<TAdd, TCur>
RTermination<TVal, Throwable, ? extends RSyncFlow<TVal, TCur, ?>> attemptMergeIn(
    @NonNull Supplier<TAdd> supplier,
    @NonNull Merger<? super TPre, ? super TAdd, Result<TCur>> attemptMerger);


@NonNull
<TCur> RSyncFlow<TVal, TCur, ?> transform(@NonNull Function<? super TPre, TCur> function);


@NonNull
<TCur> RTermination<TVal, Throwable, ? extends RSyncFlow<TVal, TCur, ?>> attemptTransform(
    @NonNull Function<? super TPre, Result<TCur>> attemptFunction);


@NonNull
RTermination<TVal, TPre, TSelf> check(@NonNull Predicate<? super TPre> predicate);


@NonNull
<TCase> RTermination<TVal, TCase, TSelf> check(
    @NonNull Function<? super TPre, TCase> caseFunction,
    @NonNull Predicate<? super TCase> casePredicate);


@NonNull
TSelf sendTo(@NonNull Receiver<? super TPre> receiver);


@NonNull
<TAdd> TSelf bindWith(@NonNull Supplier<TAdd> secondValueSupplier,
    @NonNull Binder<? super TPre, ? super TAdd> binder);


@NonNull
RConfig<TVal> thenSkip();


@NonNull
RConfig<TVal> thenGetFrom(@NonNull Supplier<? extends TVal> supplier);


@NonNull
RTermination<TVal, Throwable, RConfig<TVal>> thenAttemptGetFrom(
        @NonNull Supplier<? extends Result<? extends TVal>> attemptSupplier);


@NonNull
<TAdd> RConfig<TVal> thenMergeIn(@NonNull Supplier<TAdd> supplier,
    @NonNull Merger<? super TPre, ? super TAdd, ? extends TVal> merger);


@NonNull
<TAdd> RTermination<TVal, Throwable, RConfig<TVal>> thenAttemptMergeIn(
        @NonNull Supplier<TAdd> supplier,
        @NonNull Merger<? super TPre, ? super TAdd,
            ? extends Result<? extends TVal>> attemptMerger);

/**
 * Perform the {@link #transform} directive and use the output value as the new value of the
 * compiled repository, with notification if necessary.
 */
@NonNull
RConfig<TVal> thenTransform(
    @NonNull Function<? super TPre, ? extends TVal> function);


@NonNull
RTermination<TVal, Throwable, RConfig<TVal>> thenAttemptTransform(
        @NonNull Function<? super TPre, ? extends Result<? extends TVal>> attemptFunction);

}

interface RTermination<TVal, TTerm, TRet> {

@NonNull
TRet orSkip();


@NonNull
TRet orEnd(@NonNull Function<? super TTerm, ? extends TVal> valueFunction);

}

interface RConfig<TVal> {

@NonNull
RConfig<TVal> notifyIf(@NonNull Merger<? super TVal, ? super TVal, Boolean> checker);


@NonNull
RConfig<TVal> onDeactivation(@RepositoryConfig int deactivationConfig);


@NonNull
RConfig<TVal> onConcurrentUpdate(@RepositoryConfig int concurrentUpdateConfig);


@NonNull
Repository<TVal> compile();

@NonNull
<TVal2> RFrequency<TVal2, TVal> compileIntoRepositoryWithInitialValue(@NonNull TVal2 value);

}
}

我们可以看到这个状态接口里面定义了很多状态,里面的方法真的很多,你会发现我们在使用的使用所调用的方法都包含在里面。而且每个方法返回的不是repository,而是一些状态,这就意味着我们在构建CompiledRepository时的流程是一步步往前推进的,这就说明过程是不可逆的。

接下来就介绍集中关键的状态,其它的状态基本是继承于它们:

REventSource:这个是初始状态,Repositories.repositoryWithInitialValue()这个方法的返回的结果就是REventSource,表明事件源的开始。

RFrequency:表示事件源发送的频率。

RFlow:表示数据处理流,这里定义的方法都是和数据处理相关的,比如getFrom(),mergeIn()等等。但是要注意函数的返回值,如果是RFlow说明处理还在继续,如果是RTermination说明处理已经结束。

RTermination:表示最后数据处理后的终止操作。

RConfig:其余各种配置,比如onDeactivation():repository去活化会执行什么操作之类。

这样定义状态之后,我们能很清楚的知道进行到哪一步流程,也就更好的使用CompliedRepository(用自动补全太爽了)。

初始化(Repositories.repositoryWithInitialValue(…))->

设置监听事件(observe())->

规定事件发送的频率(onUpdatesPerLoop()等)->

处理数据流(各种处理函数)->

结束数据流->

配置一些属性(onDeactivation()等)->

complie()。
这样整个处理流程就完整了。但是你可能会说,这些都只是接口,它怎么实现的呢?那么我们就得关注repositoryWithInitialValue()这个函数:

public static <T> REventSource<T, T> repositoryWithInitialValue(@NonNull final T initialValue) {
return RepositoryCompiler.repositoryWithInitialValue(initialValue);
}

static <TVal> RepositoryCompilerStates.REventSource<TVal, TVal> repositoryWithInitialValue(
@NonNull final TVal initialValue) {
。。。
return compiler.start(initialValue);
}
private RepositoryCompiler start(@NonNull final Object initialValue) {
。。。
return this;
}

也就是repositoryWithInitialValue(…)返回了一个RepositoryCompiler,而状态接口的所有使用方法都在其内部实现了。。那compile()返回了什么呢?

public Repository compile() {
Repository repository = compileRepositoryAndReset();
recycle(this);
return repository;
}

private Repository compileRepositoryAndReset() {
checkExpect(CONFIG);
Repository repository = compiledRepository(initialValue, eventSources, frequency, directives,
notifyChecker, concurrentUpdateConfig, deactivationConfig);
。。。
return repository;
}```
RepositoryCompiler通过compile()生成CompiledRepository。这样CompiledRepository的生成流程就完成了。是不是感觉用法很简单呀,整个流程是很清晰的,你只需要按照思路一步步往下些就好了。
最后附上UsernamesSupplierde代码:

public class UsernamesSupplier implements Supplier<Result<List<String>>> {

 
    public static int NUMBER_OF_USERS = 4;

    private static final String TAG = UsernamesSupplier.class.getSimpleName();

    private List<String> getUsernames() {
        //模拟延时
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Log.e(TAG, e.toString());
            return null;
        }

        if (NUMBER_OF_USERS < 0) {
            return null;
        }

        String name1 = "Joe";
        String name2 = "Amanda";
        final List<String> usernames = new ArrayList<String>();
        Random random = new Random();
        for (int i = 0; i < NUMBER_OF_USERS; i++) {
            int number = random.nextInt(50);
            if (System.currentTimeMillis() % 2 == 0) {
                usernames.add(name1 + number);
            } else {
                usernames.add(name2 + number);
            }
        }

        return usernames;
    }

    @NonNull
    @Override
    public Result<List<String>> get() {
        List<String> usernames = getUsernames();
        if (usernames == null) {
            return Result.failure();
        } else {
            return Result.success(getUsernames());
        }
    }
}

这样通过两种方法实现下拉刷新数据就完成了

小结

上面写的有点乱,第一种是使用基本的observable和updatable来实现;第二种是使用CompliedRepository来实现。这篇文章主要介绍了一下用法,具体的内部逻辑小伙伴还是要自己看源码哒!!!
写得有误的地方还请小伙伴们多多指出!!!

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

推荐阅读更多精彩内容