1. 程式人生 > >你該擁有自己的一套專案結構----Kotlin+Dagger2+MVP+Rx+Retrofit

你該擁有自己的一套專案結構----Kotlin+Dagger2+MVP+Rx+Retrofit

前言:

架構是什麼?框架是什麼?
其實很簡單,一句話:框架是軟體,架構不是軟體。框架落腳在“架”字上,可以理解成名詞性的,是一個客觀性的名詞存在,如.Net Framework;而架構體現在“構”字上,理解成構造,是一個動詞性的,是一系列動作發生的策略性體現。先大局後區域性,就出現了架構;先通用後專用,就出現了框架。
讓我這個菜鳥LOL玩家看來:架構就是LOL裡面的一套打法、戰術,框架則是精確到QWER+走位。

1.以前不懂得架構思想的我,拿到一個專案之後,囫圇吞棗的按照需求文件,也能“有模有樣”的按時提交成果。這樣直接導致的後果就是,很怕leader又要改改改,加加加。
2.當然網上有很多優秀的架構,別人的東西不是百分百適合自己的專案,所以要結合理解,搭建出屬於自己熟悉的一套架構。隨著經驗的增長,從而不斷的完善自己的那一套。
3.本文難點不大,高手勿噴,歡迎指點。希望起到拋磚迎玉的作用,讓每個開發者都有自己熟悉的一套架構。

目錄

一、MVP 設計模式
二、網路請求框架(Rx+Retrofit )
三、Kotlin
四、Dagger2

二、網路請求框架(Rx+Retrofit )

其中相比上一次,我把網路請求的框架完全提取出來,直接無腦使用就行。
Android studio 匯入方法:
第一步:

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

第二步:

dependencies {
            compile 'com.github.KomoriWu:Http:v1.0.0'
}

在專案中的呼叫
//這裡框架我之前是用Java語言寫的,demo中的呼叫我用的Kotlin。之後我會響應號召,把網路請求的框架也改為Kotlin
1.這裡寫圖片描述
呼叫者只需編寫兩個簡單的類即可。


public class ArticleApi extends BaseApi {
    private String mPage;
    private String mSize;

    public ArticleApi(RxAppCompatActivity rxAppCompatActivity, String page, String size,
                      HttpOnNextListener listener) {
        super
(rxAppCompatActivity, listener,BASE_URL); this.mPage = page; this.mSize = size; //是否顯示載入框 setShowProgress(false); } //提供請求所需欄位的資料 @Override public Observable getObservable(Retrofit retrofit) { Map<String, String> map = new HashMap<>(); map.put("page", mPage); map.put("size", mSize); HttpService service = retrofit.create(HttpService.class); return service.getAllArticles(map);//傳資料到HttpService } }
public interface HttpService {
    @GET(GET_ALL_ARTICLES)
    Observable<ArticleBody> getAllArticles(@QueryMap Map<String, String> map);
}

在程式中呼叫:

 val articleApi: ArticleApi = ArticleApi(context as RxAppCompatActivity, page, size, object :
                HttpOnNextListener<ArticleBody>() {
            override fun onNext(t: ArticleBody?) {
                onLoadListListener.onSuccess(t);
            }

            override fun onError(e: Throwable?) {
                onLoadListListener.onFail(e);
            }
        })
        HttpManager.getInstance().doHttpDeal(articleApi)

十分清爽,無腦使用。實現原理可以看我上一篇部落格,這裡只是交大家如何使用。結合demo看,效果更佳。

三、kotlin

Demo中的程式碼大家可以發現,既有Java 也有 Kotlin。的確100%融合,有些地方用Kotlin省心很多。
kotlin是什麼?多的話我不說,早學晚學都要學。以後找Android,不會這個,估計就被擠下去了。
剛開始接觸kotlin時,十分懼怕,看網上部落格一臉懵逼。很難嗎?其實不然,大家只要搞懂幾個關鍵點,之後寫程式碼,多使用官方API文件。上手還是很快的。

1.配置
第一種:as在3.0以下的需要安裝外掛:
Android Studio的Kotlin外掛, 用於支援Kotlin的語言特性.
選擇: Preferences -> Plugins -> Install JetBrains plugin -> kotlin.

第二種:也是我極力推薦的,將as升級到3.0,一切省心省事,3.0的版本優化很大,完全支援kotlin。

2.新增依賴

 compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    compile 'org.jetbrains.anko:anko-sdk15:0.8.3'

//快捷鍵:選擇Code -> Convert Java File to Kotlin File, 更好的學習kotlin

Kotlin API 入門
1. 變數

⼀次賦值(只讀)的區域性變數:

val a: Int = 1 // ⽴即賦值
val b = 2 // ⾃動推斷出 `Int` 型別
val c: Int // 如果沒有初始值型別不能省略
c = 3 // 明確賦值

可變變數:

var x = 5 // ⾃動推斷出 `Int` 型別
x += 1

當某個變數的值可以為 null 的時候,必須在宣告處的型別後新增 ? 來標識該引⽤可為空。
如果 str 的內容不是數字返回 null

2.條件
在 Kotlin 中,if是⼀個表示式,即它會返回⼀個值。 因此就不需要三元運算子(條件 ? 然後 : 否則),因為普通的 if 就能勝任這個⻆⾊

// 傳統⽤法
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 作為表示式
val max = if (a > b) a else b

if的分⽀可以是程式碼塊,最後的表示式作為該塊的值:

val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}

如果你使⽤ if 作為表示式⽽不是語句(例如:返回它的值或者 把它賦給變數),該表示式需要有 else 分⽀。

3.迴圈
when 取代了類 C 語⾔的 switch 操作符。其最簡單的形式如下:

when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意這個塊
print("x is neither 1 nor 2")
}
}

如果很多分⽀需要⽤相同的⽅式處理,則可以把多個分⽀條件放在⼀起,⽤逗號分隔:

when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}

我們可以⽤任意表達式(⽽不只是常量)作為分⽀條件

when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}

我們也可以檢測⼀個值在(in)或者不在(!in)⼀個區間或者集合中:

when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}

For 迴圈
for 迴圈可以對任何提供迭代器(iterator)的物件進⾏遍歷,語法如下:

for (item in collection) print(item)

如果你想要通過索引遍歷⼀個數組或者⼀個 list,你可以這麼做

for (i in array.indices) {
print(array[i])
}

4.函式
定義函式:帶有兩個 Int 引數、返回 Int 的函式:
fun+方法名+引數(引數名:型別)+返回型別(可以不寫,自動判斷。返回為空可省略)

fun sum(a: Int, b: Int): Int {
return a + b
}

將表示式作為函式體、返回值型別⾃動推斷的函式:

fun sum(a: Int, b: Int) = a + b

函式返回⽆意義的值:

fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}

Unit 返回型別可以省略
//以上為Kotlin一些基礎語法,簡單易上手,有了這些看懂demo無壓力

四、Dagger2在MVP中的使用

Dagger2:Dagger2現在由Google接手維護。是一個依賴注入的框架。
依賴注入:是面向物件程式設計的一種設計模式,其目的是為了降低程式耦合,這個耦合就是類之間的依賴引起的。
網上關於Dagger2的文章太多,比較後推薦這篇:
http://www.open-open.com/lib/view/open1482201981550.html

具體專案中我們如何使用呢?
先來看Demo的MVP+Dagger2的專案結構:
這裡寫圖片描述
可能你覺得分包太多,但是實際層次更分明,結構更簡單。日後維護、迭代再也不怕了。
MVP中的model :網路資料請求

class ArticleModelImpl : ArticleModel {

    override fun loaderArticle(context: Context, page: String, size: String,
                               onLoadListListener: OnLoadListListener) {

        val articleApi: ArticleApi = ArticleApi(context as RxAppCompatActivity, page, size, object :
                HttpOnNextListener<ArticleBody>() {
            override fun onNext(t: ArticleBody?) {
                onLoadListListener.onSuccess(t);
            }

            override fun onError(e: Throwable?) {
                onLoadListListener.onFail(e);
            }
        })
        //採用已經封裝完畢的RX+Retrofit框架
        HttpManager.getInstance().doHttpDeal(articleApi)
    }

    interface OnLoadListListener {
        fun onSuccess(t: ArticleBody?)
        fun onFail(e: Throwable?)
    }
}

MVP中的View :將Model中得到的資料傳給activity顯示出來

interface ArticleView {
    fun addArticleList(articleBody: ArticleBody?)
}

MVP中的Presenter :中間體。將model與view連線起來

class ArticlePresenterImpl(private var mContext: Context,
                           private var mArticleView: ArticleView) :
        ArticlePresenter, ArticleModelImpl.OnLoadListListener {

    private var mArticleModel: ArticleModel? = null

    init {
        mArticleModel = ArticleModelImpl()
    }

    override fun loaderArticle(page: String, size: String) {
        mArticleModel?.loaderArticle(mContext, page, size, this)
    }

    override fun onSuccess(t: ArticleBody?) {
        mArticleView.addArticleList(t)
    }

    override fun onFail(e: Throwable?) {
    }

}

activity中的呼叫:
常規呼叫為:

 lateinit var mArticlePresenter: ArticlePresenter
mArticlePresenter = ArticlePresenterImpl(this, this)     mArticlePresenter?.loaderArticle("1", "8")

結合Dagger2

1.Module :生成依賴物件。@Module就是用來標準這個類的,而@Provide則是用來標註具體提供依賴物件的方法。由@Module 與@Provides 完成。提供資料。
我們這裡提供資料的類是ArticlePresenterImpl

@Module
class ArticleModule(private var mContext: Context,
                    private var mArticleView: ArticleView) {
    @Provides
    fun providePresenter(): ArticlePresenter {
        return ArticlePresenterImpl(mContext, mArticleView)
    }
}

2.Component:是依賴需求方和依賴提供方之間的橋樑。
Dagger2提供依賴的是ArticleModule這個類。
Dagger2得到依賴的是MainActivity

@Component(modules = arrayOf(ArticleModule::class))
interface ArticleComponent {
    fun inject(mainActivity: MainActivity)
}

3.依賴需求方:在activity中的呼叫。
完成這些之後我們需要Build下專案,讓Dagger2幫我們生成相關的Java類。接著我們就可以在activity中呼叫Dagger2生成的DaggerArticleComponent來實現注入

 @Inject
    lateinit var mArticlePresenter: ArticlePresenter
  DaggerArticleComponent.builder().articleModule(ArticleModule(this, this)).build().inject(this)
 mArticlePresenter.loaderArticle("1", "8")