Android徹底元件化—如何使用Arouter

格竹子發表於2018-01-03

得到Android元件化方案已經開源,參見Android元件化方案開源。方案的解讀文章是一個小的系列,這是系列的第五篇文章:

  1. Android徹底元件化方案實踐
  2. Android徹底元件化demo釋出
  3. Android徹底元件化-程式碼和資源隔離
  4. Android徹底元件化—UI跳轉升級改造
  5. Android徹底元件化—如何使用Arouter

上篇文章講到,AndroidComponent已經進行了UI跳轉的升級改造,可以支援路由的自動註冊和路由表的自動生成。但是很多使用元件化方案的同學都表示專案中已經接入ARouter來進行UI跳轉,遷移成本比較高。因此我就專門寫了這篇文章,講解一下如何在元件中使用ARouter。

不論用DDComponent自帶的方案還是ARouter,要做到元件之間自由並且可控的跳轉,需要做到下面幾點:

1、路由跳轉需要支援傳遞基本型別和自定義型別(例如Object) 2、路由的跳轉需要和元件的生命週期一致,即只有載入的元件才可以跳轉,解除安裝後的元件是不可達的 3、最好生成路由表,元件對外提供的路由可以輕鬆查閱到

下面我們就從配置開始一步步的講怎麼使用ARouter

增加必要的配置

basiclib模組中增加以下依賴,basiclib是元件化框架中共用的依賴庫:

compile 'com.alibaba:arouter-api:1.3.0'
複製程式碼

在跳轉的目標元件的build.gradle中,增加以下配置:

android {
    defaultConfig {
	...
	javaCompileOptions {
	    annotationProcessorOptions {
		arguments = [ moduleName : project.getName() ]
	    }
	}
    }
}
dependencies {
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
    ...
}
複製程式碼

在元件化框架中,我們的示例是從readercomponent跳轉到sharecomponent,所以上述配置增加在sharecomponent下面的build.gradle中。

在目標頁面增加相應的註解

我們以“分享圖書” 頁面為例

@Route(path = "/share/shareBook")
public class ShareActivity extends AppCompatActivity {
複製程式碼

在進入這個頁面,需要傳入兩個引數,一個是String型別的bookName,一個是自定義型別Author的author

@Autowired
String bookName;
@Autowired
Author author;
複製程式碼

如何傳遞自定義型別

由於自定義型別Author需要跨元件傳遞,我們知道,DDComponent的核心之處就是在元件之間見了一堵牆,在編譯期程式碼和資源都是完全隔離的,所以Author必須定義在share元件向外提供的服務中。所以我們在component中,定義Author類:

public class Author {
    private String name;
    private int age;
    private String county;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getCounty() {
        return county;
    }
    public void setCounty(String county) {
        this.county = county;
    }
}
複製程式碼

現在就解決了Author的可見性問題,但是為了能在路由中傳遞,按照ARouter的要求,還需要自己實現SerializationService:

@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
    @Override
    public void init(Context context) {}
    @Override
    public <t> T json2Object(String text, Class<t> clazz) {
        return JSON.parseObject(text, clazz);
    }
    @Override
    public String object2Json(Object instance) {
        return JSON.toJSONString(instance);
    }
    @Override
    public <t> T parseObject(String input, Type clazz) {
        return JSON.parseObject(input, clazz);
    }
}
複製程式碼

這裡筆者就遇到了一個坑,本來我把這個類定義在readercomponent中,結果執行之後會報空指標異常。只有我把類移到sharecomponent之後,異常才消失。暫時沒找到原因,但是定義在這裡,加入要跳轉到readercomponent怎麼辦呢?

發起跳轉

在元件化框架demo中,發起跳轉是readercomponent中的ReaderFragment中,demo中列出了兩個示例: 普通跳轉

private void goToShareActivityNormal() {
    Author author = new Author();
    author.setName("Margaret Mitchell");
    author.setCounty("USA");
    ARouter.getInstance().build("/share/shareBook")
            .withString("bookName", "Gone with the Wind")
            .withObject("author", author)
            .navigation();
}
複製程式碼

以及startActivityForResult

private void goToShareActivityForResult() {
    Author author = new Author();
    author.setName("Margaret Mitchell");
    author.setCounty("USA");
    ARouter.getInstance().build("/share/shareMagazine")
            .withString("bookName", "Gone with the Wind")
            .withObject("author", author)
            .navigation(getActivity(), REQUEST_CODE);
}
複製程式碼

控制生命週期

經過上面的操作,已經可以完成UI跳轉了。但是如果執行demo就可以發現,此時即使解除安裝了分享元件,分享書的頁面還是可以進入的,說明生命週期沒有同步。在DDComponent自帶的方案中是不存在這個問題的,因為跳轉的邏輯已經與元件化生命週期繫結在一起。 這裡就用到ARouter自帶的攔截器功能,每個元件都需要定義一個攔截器,當元件解除安裝之後需要攔截住該元件的跳轉入口。 下面是分享元件攔截器的示例程式碼:

@Interceptor(priority = 1, name = "分享元件攔截器")
public class ShareInterceptor implements IInterceptor {
    public static boolean isRegister;
    Context mContext;
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        if (isRegister) {
            callback.onContinue(postcard);
        } else if ("/share/shareBook".equals(postcard.getPath())
                || "/share/shareMagazine".equals(postcard.getPath())) {
            MainLooper.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "分享元件已經解除安裝", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
    @Override
    public void init(Context context) {
        mContext = context;
    }
}
複製程式碼

這裡通過一個isRegister開關來控制攔截器是否生效,為了保證生命週期一致性,在ShareApplike中增加賦值邏輯:

public class ShareApplike implements IApplicationLike {
    @Override
    public void onCreate() {
        ShareInterceptor.isRegister = true;
    }
    @Override
    public void onStop() {
        ShareInterceptor.isRegister = false;
    }
}
複製程式碼

但是這裡也遇到了兩個小坑,不知道是否是ARouter使用不當: (1)新增或者修改攔截器之後,必須解除安裝重灌app才能生效,不論是clean還是rebuild都是不生效的 (2)攔截器中需要硬編碼該元件的所有路由,例如/share/shareBook等,一旦路由發生了改變,一定要記得修改這個地方

路由表生成

這個ARouter暫時沒有提供,DDComponent自帶的方案增加了這個功能,當元件build生成之後,在根目錄生成UIRouterTable資料夾,裡面會列出每個元件向外提供的路由表以及具體引數

auto generated, do not change !!!! 

HOST : share

分享雜誌頁面
/shareMagazine
author:com.luojilab.componentservice.share.bean.Author
bookName:String

分享書籍頁面
/shareBook
author:com.luojilab.componentservice.share.bean.Author
bookName:String
複製程式碼

這點對於元件的協同開發是比較重要的,畢竟跳轉之前翻閱別人的程式碼是件比較費事的工作

簡單做一個總結:

  1. ARouter是一個優秀的路由跳轉方案,DDComponent自帶的方案也參考了很多其中的想法,功能很強大
  2. 使用中需要與元件化方案相容的地方主要是生命週期相關,在攔截器上增加部分邏輯就可以完成
  3. ARouter使用中還存在一些小的問題,可能是姿勢不對,接入中走了不少彎路,有熟悉這塊的朋友可以指出原因
  4. 路由表沒有自動生成,對外沒有暴露有哪些路由協議和引數,對於元件之間協同開發不太友好

上面的程式碼已經發布DDComponent的master-arouter分支,歡迎大家使用,原始碼地址: github.com/mqzhangw/An…

相關文章