There’s a lot of MVI on the Nuggets these days, but it’s all written in Mosby. PublishSubject is simple to achieve, this example is in the previous code to change, using Java we understand, plus welcome spray, not spray uncomfortable ha…


Concept of MVI

MVI is a concept that came along with MVVM and is an idea derived from Rxjava’s responsive thinking

The data layer passes Livedata -> Persenter -> to the UI layer to register listeners. This is a one-way process from data -> UI:

General MVVM is so we write, but also some people to write more thoroughly, the app interaction is a two-way process, first from the UI – > data to the data – > the UI, the common way we just realized side, improvement is even the click event for a more thorough response are responsive, registration data layer to monitor button click event, Receive data through the water pipe, and return data through the water pipe after remote data return:

MVI and MVVM have the same idea, but the difference is that MVI further abstracts the UI action, namely the I-intent in MVI. In MVI, any UI event is regarded as a responsive data source. The task of P layer is to bind and register the relationship between V and M layer. Connect the water pipes like a water heater:

The Intent in MVI has a mind of its own. Intents treat any changes to the UI page as a whole, represented by a data type, such as a ViewState object with loading, netError, The data layer returns the ViewState instead of the data directly. The UI layer displays different UI styles based on the state of the ViewState, so that the P layer doesn’t have to write a bunch of methods to control the state of the UI display. The real realization of the MVP idea of stratification, who cares who, of course, MVVM can also do, but the general MVVM are directly return data, really the page state also encapsulated into the data of few people

class NetViewState(
        var loading: Boolean = false.var success: Boolean = false.var netError: Boolean = false.var dataError: Boolean = false.var dataNo: Boolean = false.var message: String = "".var data: BookResponse = BookResponse()) {


    companion object Help {

        @JvmStatic
        fun loading(a): NetViewState {
            return NetViewState(loading = true)}@JvmStatic
        fun success(data: BookResponse): NetViewState {
            return NetViewState(success = true.data = data)}@JvmStatic
        fun netError(message: String): NetViewState {
            return NetViewState(netError = true, message = message)
        }

        @JvmStatic
        fun dataError(message: String): NetViewState {
            return NetViewState(dataError = true, message = message)
        }

        @JvmStatic
        fun dataNo(message: String): NetViewState {
            return NetViewState(dataNo = true,message = message)
        }
    }
}
Copy the code

Code to start

MVI I read a lot of articles, all with the help of mosby this library to achieve, MOSby brought a large number of derivative types, each role has its base class, virtually greatly increased the cost of learning, MVI is the MVVM thinking further, did not expect that everyone is more and more complex, all unnecessary, Simple is good, easy to understand, easy to read

Using RXJava thermal emission or Livedata can be simple to achieve MVI, I do not want to use MOSby, their own implementation of an MVI, the following Demo is just used to demonstrate, more please introspection encapsulation, optimization

The Ui layer provides event intents
    protected void onCreate(Bundle savedInstanceState) {
        btn_book.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bookIntent.onNext(new BookRequest("Life".""."0"."10")); }}); persenter.netActivity =this;
        persenter.bingIntent(bookIntent);
    }

    void updata(NetViewState netViewState) {

        if (netViewState.getLoading()) {
            Log.d("AA"."loading ...");
            return;
        }

        if (netViewState.getNetError()) {
            Log.d("AA"."NetError." + netViewState.getMessage());
        }

        if (netViewState.getDataError()) {
            Log.d("AA"."DataError." + netViewState.getMessage());
        }

        if (netViewState.getSuccess()) {
            List<BookResponse.Book> books = netViewState.getData().getBooks();
            if(books ! =null && books.size() == 0) {
                ToastComponent.Companion.getInstance().show("No data.", Toast.LENGTH_SHORT); } adapter.refreshData(books); }}Copy the code
The M layer focuses on upstream UI layer events and provides downstream data layer observers
public class BookRepositroy {

    public static final String URL_BOOK_LIST = "book/search";
    public PublishSubject<NetViewState> bookData = PublishSubject.create();

    public void bingIntent(Observable<BookRequest> bookIntent) {
        bookIntent.subscribe(new Consumer<BookRequest>() {
            @Override
            public void accept(BookRequest bookRequest) throws Exception { getBookData(bookRequest); }}); }private void getBookData(BookRequest bookRequest) {

        Map<String, String> map = new HashMap<>();
        map.put("q", bookRequest.getTitle());
        map.put("tag", bookRequest.getTag());
        map.put("start", bookRequest.getStartCount());
        map.put("count", bookRequest.getWantCount());

        HttpClient.Companion.getInstance().get(URL_BOOK_LIST, map)
                .map(new Function<ResponseBody, NetViewState>() {
                    @Override
                    public NetViewState apply(ResponseBody responseBody) throws Exception {
                        BookResponse bookResponse = null;
                        try {
                            bookResponse = new Gson().fromJson(responseBody.string(), BookResponse.class);
                        } catch (Exception e) {
                            Observable.error(e);
                        }
                        return NetViewState.success(bookResponse);
                    }
                })
                .onErrorReturn(new Function<Throwable, NetViewState>() {
                    @Override
                    public NetViewState apply(Throwable throwable) throws Exception {

                        if (throwable instanceof HttpException) {
                            / / HTTP error
                            return NetViewState.netError("Network error");
                        } else if (throwable instanceof ConnectException
                                || throwable instanceof UnknownHostException) {
                            // Connection error
                            return NetViewState.netError("Connection error");
                        } else if (throwable instanceof InterruptedIOException) {
                            // Connection timed out
                            return NetViewState.netError("Connection timed out");
                        } else if (throwable instanceof JsonParseException
                                || throwable instanceof JSONException
                                || throwable instanceof ParseException) {
                            return NetViewState.dataError("Parsing error");
                        } else if (throwable instanceof ApiException) {
                            return NetViewState.netError(throwable.getMessage());
                        } else if (throwable instanceof IOException) {
                            return NetViewState.netError("Network error");
                        }
                        return NetViewState.netError("Wrong position");
                    }
                })
                .startWith(NetViewState.loading())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new Consumer<NetViewState>() {
                    @Override
                    public void accept(final NetViewState netViewState) throws Exception { bookData.onNext(netViewState); }}); }}Copy the code
The P layer binds the upstream and downstream (V and P) relationship
public class NetPersenter {

    public NetActivity netActivity;
    BookRepositroy repositroy = new BookRepositroy();

    public void bindBook(PublishSubject<BookRequest> bookIntent) {

        repositroy.bingIntent(bookIntent);
        repositroy.bookData.subscribe(new Consumer<NetViewState>() {
            @Override
            public void accept(NetViewState netViewState) throws Exception { netActivity.updata(netViewState); }}); }}Copy the code
Think about:
  • P layer registers downstream data instead of handing it over to V layer, because we may have business logic in P layer that needs to be processed first and cannot directly hand it over to U layer
  • Layer M uses startWith to preferentially send a loading event
  • ViewState can be further optimized, most of the page state is the same, it is necessary to abstract a base class, and koltin’s sealed class can do better, and now kotlin era, I should not post pure Java code. This is because the page is still written before and changed above, otherwise I would kotlin

The last

Not a few lines of code, was not intended to write an article, but later think of the Internet are using MOSby library to write MVI, I write out to provide you with another way of thinking, can be simple why more complex