一個MVP+RxJava+Retrofit的乾貨集中營

歡迎掘金的小夥伴們訪問個人博客網站,原文連接:wensibo.top/2017/05/15/… ,未經容許不得轉載!java

今天想要與你們一塊兒分享的五月份的時候用一個星期開發的一個app——乾貨集中營客戶端,由於已經得到了掘金的專欄因此就把以前的文章發不上來與你們一塊兒分享。
其實網上已經有許多相似的項目,代碼家也在他的乾貨集中營中推薦了幾款優秀的做品,我也借鑑了其中的一些,本身開發出一款乾貨集中營客戶端,目前項目已經發布到github,若是你想了解整個工程的具體內容,那麼你能夠fork或者clone,若是你以爲我作得還能夠,那麼請你賜給我一個star唄!你的支持會是我努力的動力。android

前言

慢慢的已經養成了每篇文章都會來一個前言,也慢慢地將寫文章潛移默化的轉變成寫故事,因此每一個故事都會有前言,也都會有結果,此次也不例外。
距離上篇引發熱烈反響的文章發佈已通過去一個月了,承蒙廣大網友對個人支持以及建議,固然做爲一個90後,我也很虛心的接受來自各方的吐槽,畢竟我並不優秀,只是一直在優秀的路上努力的奔跑着。下面我想跟你們一塊兒分享一下這一個月裏我作了些什麼事,以及接下來一段時間的計劃和打算。git

Have Done List

  • 持續22天在github上出現,看看下面這棵貢獻樹
    contributions
    contributions
  • 博客瀏覽量突破35000
    blog
    blog
  • 看了1本好書——《網絡是怎樣鏈接的》
  • 研究Retrofit與RxJava的源碼(待我葡萄成熟時再把文章放出來吧,如今太嫩了,很差意思讓你們看到)
  • 2次擔任演講的主講人(以後會寫一篇文章講述個人演講技巧)
  • 看了錘子科技新品發佈會(我是羅粉但也是加油,心疼老羅一秒)
  • 努力尋找實習(投了許多簡歷,可是無一倖免:sob: ,有同窗能夠推薦一波嗎?沒有的話我待會再問問)
  • 1個全新的乾貨集中營客戶端app(也是寫這篇文章的原因)

Todo List

  • xposed插件開發(這個閃念是有一天夜裏驚醒過來的想法)
  • 繼續寫好的文章與你們一塊兒分享,不只僅是技術方面的,還有許多我以爲有用的文章,都會爲你們奉上,感謝老鐵們的支持
  • 繼續看書
  • 繼續找實習(嗚嗚嗚~~(>_<)~~,體會到工做難找了,尤爲是互聯網寒冬)

老鐵別廢話了
老鐵別廢話了

好啦,上面講了一大堆廢話終於能夠進入正題了,我也很基動,開車咯!

項目介紹

logo
logo

GankClient(又稱乾貨集中營客戶端)是一個全新的乾貨集中營客戶端,它獲取的是來自 乾貨集中營API的數據,利用全新的Material Design的設計語言展現數據內容。整個項目採用MVP的設計架構,而且大量使用RxJava2,網絡框架使用的是Retrofit。我用下面幾個裝逼的句子來形容一下這個APP:

  • 更快速的加載速度
  • 更流暢的頁面體驗
  • 更有趣的刷新效果
  • 更精美的網頁瀏覽
  • 更美觀的視覺享受

這個只是個人我的感覺,大神請輕噴:joy: ,不過仍是但願你們可以喜歡這個項目,而且積極的向我pull request以及反饋bug,但願你們多多支持。若是能夠的話給個star咯。 github

預覽

誰說不給圖的
誰說不給圖的

所有效果圖來一發

screenshot
screenshot
screenshot
screenshot
screenshot
screenshot

screenshot
screenshot
screenshot
screenshot
screenshot
screenshot

沒有gif圖都很差意思說話了

gif
gif

下載

酷安基佬羣

若是你使用酷安的話,那就使勁點這裏,或者在酷安搜索乾貨集中營,認準個人圖標哦
web

乾貨集中營
乾貨集中營

fir.im

若是你沒有安裝酷安,那麼你能夠掃描下方的二維碼進行下載
chrome

QRCode
QRCode

測試

若是你想測試這個項目,那麼請手動clone數據庫

功能&特點

√表示已經實現的功能,X表示的的是還沒實現或者須要完善的功能。(吐槽一下,掘金的MarkDown編輯器仍是沒有實現一些基本的語法,例如打勾勾) 編程

√實時獲取服務器的最新數據,採用CardView的佈局以更好的展示數據。
√刷新效果很好玩,真的很精緻,感謝Phoenix
√若是你裝有Chrome瀏覽器,並將其設置爲默認瀏覽器,那麼你的網頁瀏覽效果就會十分酷炫。感謝Custom-Tabs-Client ! 牆裂推薦Chrome,若是你沒有安裝Chrome,那也不要緊,那就用傳統的WebView吧!
√更加統一的過渡動畫,相信你會愛上它。
√保存、分享圖片與連接,也能夠直接使用瀏覽器打開連接。
√更好看的Material Design設計風格。
√妹子很漂亮喲! api


X優化webview的視頻播放。
X增長使用系統瀏覽器的選項。
X修復在主界面中加載數據到2016/4/20左右時數據顯示錯亂的問題。
X加強分享功能。 瀏覽器

分解

終於到了這個純乾貨步驟了,別說話先看東西!

如何使用MVP的設計架構

我先展現如下這個項目的結構圖,讓你們內心有個底

  • http
    • GankRetrofit.java
    • GankRetrofitClient.java
  • mvp
    • model
      • BaseModel.java
    • presenter
      • BasePresenter.java
    • view
      • IBaseView.java
  • ui
    • activity
    • adapter
    • base
    • chromeviews
    • fragment
    • widget

能夠看到,整個項目的結構還算比較清晰,總體的架構都是在mvp目錄中定下來的,mvp架構分三層,model模型層,用於定義一些數據的類型;presenter呈現者層,用於處理view層的邏輯;view顯示層,這裏定義的都是接口,真正實現他們的是activity,這些activity只要實現相應的接口,就可以本身複寫其中的方法。
固然我這麼說你確定仍是一臉懵逼,並且我還必須跟你說,我這個不算最純粹的MVP模式,最純粹的寫法應該都是面向接口編程的,就是在model,presenter,以及view下都是定義接口,而到了具體的運用場景,就定義出具體的類去實現這些接口。固然了,爲了讓你們可以更清楚MVP是怎麼實現的,下面我會用代碼的形式爲你們展現,例如我要編寫MainActivity的代碼,首先已經知道在這個Activity中須要作以下這些事:

  • 初始化組件
  • 加載Fragment
  • FloatingActionButton的點擊事件——去到DailyActivity
  • drawer menu的點擊事件——去到AboutActivity

爲了讓Activity專一於界面的工做,而不用去考慮邏輯處理的操做,這個就是所謂的解耦,那麼咱們能夠將邏輯的操做放到presenter中去,而與界面有關的操做就放在view下,因而咱們就能夠這樣寫(爲了便於你們理解,我將項目中的代碼作了適當的修改,若是你想了解更加具體的邏輯,能夠仔細看看代碼):

  • IBaseView
public interface IBaseView {
        //界面初始化操做
        void init();
}複製代碼
  • BasePresenter&MainPresenter
/** * 將presenter的公共操做集成爲BasePresenter */
public abstract class BasePresenter <T extends IBaseView>{
        protected Disposable disposable;
        protected Context context;
        protected T iView;      //獲取到view的對象

        public BasePresenter(Context context, T iView) {
                this.context = context;
                this.iView = iView;
        }

        public void init() {
                iView.init();
        }

        public abstract void release();
        public abstract void initPresenter();
}

/** * 每個界面均可以編寫本身的Presenter,並指定View的泛型 */
public class MainPresenter extends BasePresenter<IBaseView> {

        public MainPresenter(Context context, IBaseView iView) {
                super(context, iView);
        }

        @Override
        public void release() {

        }

        public void toDailyActivity() {
                Intent intent = new Intent(context, DailyActivity.class);
                context.startActivity(intent);
        }

        public void toAboutActivity() {
                Intent intent = new Intent(context, AboutActivity.class);
                context.startActivity(intent);
        }

        public void toSettingActivity() {
                Intent intent = new Intent(context, SettingActivity.class);
                context.startActivity(intent);
        }複製代碼
  • MainActivity
public class MainActivity <MainPresenter> extends AppCompatActivity implements IBaseView{

        @OnClick(R.id.fab_main)
        void fabClick() {
                presenter.toDailyActivity();
        }

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
        }


        @Override
        protected void initPresenter() {
                presenter = new MainPresenter(this, this);
                presenter.init();
        }

        @Override
        public void init() {
                //全部的初始化操做
        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
                presenter.release();
        }

}複製代碼

大概就是這樣一個套路,講真我這樣講你確定迷糊,我當初在學這個的時候也是十分凌亂,後來才發現只有本身動手親自敲代碼才能瞭解整個思路,另外你們在學習MVP的過程當中應該擅於畫圖,無論是在紙上畫仍是使用思惟導圖都行,這樣可讓你更加宏觀的瞭解整個調用的順序以及各個類之間的關係,這毫不是你看了一篇文章就能懂的。

你真的用好RxJava了嗎

當我問這個問題的時候,其實我想說的是RxJava的用處很廣,咱們想固然的認爲只要RxJava與Retrofit相配合就算是完成任務了,但實際上只要涉及到耗時操做、線程切換:網絡請求、圖片解析、數據庫讀取等等須要用多個線程一塊兒完成的工做時,你均可以用到RxJava,而且若是你還一直用RxJava1的話,那麼你也OUT啦,當你認識RxJava2.x的時候你會發現他更強大了。關於RxJava,我後續會寫相關的文章與你們一塊兒分享,這裏我舉項目中遇到的一個例子,看看RxJava的用武之地是多麼的廣:

/** * 將圖片保存在本地 */
public void openWebView(final Gank gank) {
    disposable=Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(@NonNull ObservableEmitter e) throws Exception {
                    e.onNext(android.R.drawable.ic_menu_share);
            }
    }).subscribeOn(Schedulers.newThread())//開啓一個新線程來進行耗時操做
            .map(new Function<Integer, Bitmap>() {
                    @Override
                    public Bitmap apply(@NonNull Integer integer) throws Exception {
                            //將資源id解析爲bitmap是一個耗時操做
                            return BitmapFactory.decodeResource(activity.getResources(), integer);
                    }
            }).observeOn(AndroidSchedulers.mainThread())//回到主線程操做bitmap
            .subscribe(new Consumer<Bitmap>() {
                    @Override
                    public void accept(@NonNull Bitmap bitmap) throws Exception {
                            //拿到bitmap以後作的界面更新
                    }
            });
}

//釋放資源
public void release() {
                if (disposable != null&&!disposable.isDisposed()) {
                        disposable.dispose();
                }
        }複製代碼

爽快的Retrofit

還記得以前我寫過Volley的一系列文章,雖然以爲這個開源框架已經不錯了,但畢竟長江後浪推前浪,在Retrofit的面前,Volley簡直就是小巫見大巫,看看咱們應該如何在項目中使用:

  • 一、新建一個接口,用註解的形式在裏面定義網絡請求的方法:
public interface GankRetrofit {
        //獲取MainActivity界面的數據,具體的請求路徑應該詳細看官方的API說明,
        // Retrofit與RxJava配合以後才能顯示出更強的威力
        @GET("data/{type}/40/{page}")
        Observable<MainData> getMainData(@Path("type") String type, @Path("page") int page);
}複製代碼
  • 二、得到實例:
Gson date_gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://gank.io/api/")         //指定服務器地址
        .addConverterFactory(GsonConverterFactory.create(date_gson))    //添加一個gson的解析器
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())          // 若是想使用RxJava那就須要添加這個適配器 
        .build();
GankRetrofit gankRetrofit;
gankRetrofit = retrofit.create(GankRetrofit.class);            //獲取GankRetrofit的對象複製代碼
  • 三、獲取數據:
//返回的Observable<MainData>對象就可使用RxJava進行解析了
gankRetrofit.getMainData("Android",40);複製代碼

更好的網頁瀏覽體驗——Custom-Tabs-Client

若是你使用過Chrome瀏覽器,那麼你應該會喜歡上它,當咱們在使用webview開發的時候,會發現webview存在許多的限制,而且開發者對webview不能徹底控制,因而Chrome團隊爲了解決開發者的這些問題,就設計出這個開源庫,只要用戶手機上安裝Chrome而且設置爲默認瀏覽器,那麼打開網頁連接的時候就會看到以下的畫面:

custom-tabs-client
custom-tabs-client

是的!如此酷炫的畫面是用到了Chrome瀏覽器的內核,而且讀取Chrome的cookie,例如若是你在Chrome已經登陸過github了,那麼經過這個庫打開的github連接一樣也顯示你已經登陸了github。固然除了頁面效果十分好以外,咱們還能夠自定義許多東西,例如 過渡動畫ToolBar上方的ActionButton等等,個人項目中也已經實現了這兩個功能。接下來我帶你們一塊兒看看最簡單的實例應該怎麼編寫:

CustomTabsIntent.Builder customTabsIntent;
 customTabsIntent = new CustomTabsIntent.Builder();     //獲取到CustomTabsIntent實例
 //一系列的設置
customTabsIntent.setToolbarColor(activity.getResources().getColor(R.color.colorPrimaryDark));   //設置ToolBar的顏色
customTabsIntent.setShowTitle(true);    //設置是否顯示網頁的標題
customTabsIntent.setStartAnimations(activity, R.anim.slide_in_right, R.anim.slide_out_left);    //設置進入的動畫
customTabsIntent.setExitAnimations(activity, R.anim.slide_in_left,R.anim.slide_out_right);      //設置退出的動畫
//開啓網頁
CustomTabActivityHelper.openCustomTab(
    activity,       //當前的activity
    customTabsIntent.build(),
    view,
    gank,   //gank帶有要打開的網頁的url
    new CustomFallback() { //若是用戶沒有安裝Chrome並將其設置爲默認瀏覽器的話,應該作這樣的處理
            @Override
            public void openUri(Activity activity, View view,Gank gank) {
                    Log.d("Gank", gank.toString());
                    super.openUri(activity, view,gank);
            }
    });複製代碼

以上就是想要跟你們一塊兒分享的關於這個項目中一些重要的點,可能有些地方講得並不那麼清楚,但我以爲只有實踐才能出真知,因此老哥仍是乖乖打開AS擼擼代碼啦!

版本控制

目前app的版本爲V1.0.0,我會用下面的時間表記錄版本的迭代,若是有更新的版本,我會及時更新這個表格。

Version Date
V1.0.0 2017/5/14

致謝

做爲一名Android開發者,咱們都應該具備像羅老師同樣感激開源世界的情懷,而咱們如今能作的就是一樣爲開源世界作貢獻,不管是寫文章亦或是寫程序,記得都要時刻保持一顆感恩的心。很是感謝代碼家以及他的幹活集中營,也很是感謝許多前輩們作過的幹活集中營app。

後記

最近一個月,感受本身身體被掏空,吐槽學校對咱們專業的課程安排如此不合理,天天上那些本身不感興趣的課程確實很無趣,可是生活再難也要感激它,只有經過本身的雙手去努力,未來的你纔會爲如今的本身喝彩驕傲。下篇文章再見!

相關文章
相關標籤/搜索