Rewrite the plaid APP in Kotlin language: Lessons Learned (II)

Source: Internet
Author: User

Original title: Converting Plaid to Kotlin:lessons learned (Part 2)

Original link:http://antonioleiva.com/plaid-kotlin-2/

Original Antonio Leiva (http://antonioleiva.com/about/)

Published in the original: 2015-11-17

The significant improvements that we see in the first section are attributed to the use of the Kotlin language in the activity. However, due to the fact that the main overloaded methods do something, there are still some formulaic code, so this type of class is not very good to show its effect.

I continue to rewrite the app in Kotlin language (everyone can see all the changes in repo ) and have some interesting things to do. Today, I focus DataManager on the transformation of classes. To reveal, the size of the class has been reduced from 422 rows to 177 rows . I think it's easy to understand.

when

Throughout this class, the first thing you see most is that loadSource there are a large number of statements in the class if/else . In the first instance, you can use switch a statement to improve readability, but it's always a bit difficult to understand. In the Kotlin language, you can Use when expression, which is very similar to a statement in the Java language switch , but more powerful. Conditions can be written according to needs, and can be a good substitute for if/else statements. Using its simplest version here, it is also possible to make this method easier to read:

1 When (Source.key) {2Sourcemanager.source_designer_news_popularloaddesignernewstopstories (page)3Sourcemanager.source_designer_news_recentloaddesignernewsrecent (page)4Sourcemanager.source_dribbble_popularloaddribbblepopular (page)5Sourcemanager.source_dribbble_followingloaddribbblefollowing (page)6Sourcemanager.source_dribbble_user_likesloaddribbbleuserlikes (page)7Sourcemanager.source_dribbble_user_shotsloaddribbbleusershots (page)8Sourcemanager.source_dribbble_recentloaddribbblerecent (page)9Sourcemanager.source_dribbble_debutsloaddribbbledebuts (page)Tensourcemanager.source_dribbble_animatedloaddribbbleanimated (page) OneSourcemanager.source_product_huntloadproducthunt (page) A     Else-When (source) { -Is Source.dribbblesearchsourceloaddribbblesearch (source, page) -Is Source.designernewssearchsourceloaddesignernewssearch (source, page) the   -     } -}

However, this is not a case, it is an when expression, so you can return a value, which is useful.

Mapping Processing

Although, this example does not reduce the number of code (lines), but it is interesting to see how to handle the mapping table in the Kotlin. In the Java language, the getNextPageIndex following:

1 Private intGetnextpageindex (String dataSource) {2     intNextPage = 1;//default to one–i.e. Newly added sources3     if(Pageindexes.containskey (DataSource)) {4NextPage = Pageindexes.get (dataSource) + 1;5     }6 pageindexes.put (DataSource, nextPage);7     returnNextPage;8}

What is that in the Kotlin language?

1 Private Fun Getnextpageindex (datasource:string): Int {2     val nextPage = 1 + pageindexes.getorelse ( DataSource) {0 }3     pageindexes + = dataSource to nextPage4      return  nextPage5 }

Here are some interesting things, the first is the getOrElse function, and if the element is not found in the mapping table, it is allowed to return the default value :

1 val nextPage = 1 + pageindexes.getorelse (DataSource) {0}

Thanks to this, we can save some condition check code. And the other thing that's more interesting is how to add a new item to the mapping table. The Kotlin Language mapping table implements the "+" operator so that new items can be added: Yes map = map + Pair map += Pair . namely:

1 pageindexes + = Pair (DataSource, NextPage)

However, as I may have said before, it is possible to return using the to (infix function ) Pair . The previous line is like this:

1 pageindexes + = DataSource to NextPage

will beCallback(callback function) is converted toLambdaAn expression

It's like magic. There are a lot of duplicate code in the Load class. Most of them have the same structure copied, while others call the API. First, create the Retrofit callback function. If the request succeeds, you can obtain the necessary information from the result, whatever you need. Finally, the data Mount Listener is called. In any case, whether successful or unsuccessful, loadingCount it is updated.

To cite only one example:

1 Private voidLoaddesignernewstopstories (Final intpage) {2Getdesignernewsapi (). Gettopstories (page,NewCallback<storiesresponse>() {3 @Override4          Public voidSuccess (Storiesresponse storiesresponse, Response Response) {5             if(Storiesresponse! =NULL6&&sourceisenabled (sourcemanager.source_designer_news_popular)) {7 setpage (storiesresponse.stories, page);8 Setdatasource (storiesresponse.stories,9 sourcemanager.source_designer_news_popular);Ten ondataloaded (storiesresponse.stories); One             } A loadingcount.decrementandget (); -         } -   the @Override -          Public voidfailure (retrofiterror error) { - loadingcount.decrementandget (); -         } +     }); -}

If not analyzed, this code is quite difficult to understand. We can create a callback function that creates a retrofit callback function that implements the structure of the preceding callback function. The difference is getting the necessary information from the results :

1 PrivateInline Fun <T>callback (Page:int, sourcekey:string,2Crossinline extract: (T), list<plaiditem>)3= retrofitcallback<t> {result, response4     if(sourceisenabled (Sourcekey)) {5Val items =Extract (Result)6 setpage (items, page)7 setdatasource (items, Sourcekey)8 ondataloaded (items)9     }Ten}

This is very similar: check whether the source is enabled, invoke if enabled, setPage setDataSource and onDataLoaded get related items from the results. the implementation of Retrofitcallback can make the previous function simpler, and it can be omitted:

1 PrivateInline Fun <T> retrofitcallback (crossinline code: (T, Response), Unit): callback<t>2= object:callback<t> {3Override fun success (T:t?, Response:response) {4T?. Let {code (it, response)}5 Loadingcount.decrementandget ()6     }7  8 Override fun Failure (Error:retrofiterror) {9 Loadingcount.decrementandget ()Ten     } One}

inlineA modifier is a method of optimizing a function that has parameters that contain other functions. When a function contains a lambda expression, its transformation is equivalent to the object containing the implementation code of the function. However, if used inline , thelambda expression will be replaced by its code when it is called. If a lambda expression returns a value, it will be used crossinline . For more information, please read Kotlin reference .

Two functions are generic, so you can accept any type of requirement. In this way, the preceding request can be as follows:

1 Private Fun loaddesignernewstopstories (page:int) {2    designernewsapi.gettopstories (page, 3             Callback (page, sourcemanager.source_designer_news_popular) {it.stories}) 4 }

The function call getTopStories creates a callback function that receives the page and source key, and the function obtains the stories from the result . A similar structure runs for other parts of the call, but can do whatever results are required. For example, another response needs to modify the contained User:

1 PrivateFun Loaddribbbleusershots (page:int) =dribbblelogged {2Val user =Dribbbleprefs.user3 dribbbleapi.getusershots (page, Dribbbleservice.per_page_default,4 Callback (page, sourcemanager.source_dribbble_user_shots) {5                 //This API call doesn ' t populate the shot user field but we need it6it.apply {forEach {it.user =User}}7             })8}

As you can see, the former is also required to be recorded in Dribbble. the dribbblelogged function is responsible for checking, if not just doing other things.

1 private Inline Fun dribbblelogged (code: (), Unit) {2     if  ( Dribbbleprefs.isloggedin) {3        code ()4     else  { 5         loadingcount.decrementandget ()6    }7 }
Summary

This section shows the lambda expression capabilities and the use of the "first Class citizen" function. The reduction in code is huge ( reducing 238%), but it is not the most important improvement. The code is now easier to read and less error-prone. Remember to read my final submission in the plaid branch of GitHub .

Rewrite the plaid APP in Kotlin language: Lessons Learned (II)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.