ARouter學習之一——框架的使用

按照ARouter學習之三——註解解析器(arouter-compiler源碼)的結尾,似乎這應該是學習之四,但我選擇標題起爲之一,雖說是後面才寫,但畢竟學習的話都是先學會用,再去弄懂原理。而總結順序,則是根據好奇心的順序來整理。

本文的初衷:搞懂在項目中怎樣引入ARouter並加以使用


目錄

引入ARouter建立依賴

各類簡單的跳轉

目標界面接收參數

ARouter進階高級用法

1.通過URL跳轉

2.解析高級參數:List、Map、對象

3.處理跳轉結果

4.預處理服務

5.詳細API說明

小結


引入ARouter建立依賴

該小節的內容均引自github上的文檔,若需要請穩步:https://github.com/alibaba/ARouter/blob/master/README_CN.md

build.gradle文件內容如下:

android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
}

dependencies {
    // 替換成最新版本, 需要注意的是api
    // 要與compiler匹配使用,均使用最新版可以保證兼容
    compile 'com.alibaba:arouter-api:x.x.x'
    annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
    ...
}

最可能早的註冊ARouter,在MyApplication中進行初始化

if (isDebug()) {           // 這兩行必須寫在init之前,否則這些配置在init過程中將無效
    ARouter.openLog();     // 打印日誌
    ARouter.openDebug();   // 開啓調試模式(如果在InstantRun模式下運行,必須開啓調試模式!線上版本需要關閉,否則有安全風險)
}
ARouter.init(mApplication); // 儘可能早,推薦在Application中初始化

至此,完成依賴的建立,接下來就可以正常使用。

各類簡單的跳轉

通過前兩篇的源碼閱讀RouteType類,我們知道ARouter支持跳轉的對象包括:Activity、Fragment、Service,本節來看看如何使用ARouter框架來進行這樣的跳轉。其步驟可拆分成兩步:添加註解和發起路由操作。

添加註解:

// 在支持路由的頁面上添加註解(必選)
// 這裏的路徑需要注意的是至少需要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}

注意path必須不能少於兩級,若只是[/xx]的話,則ARouter會拋出數組越界異常,原因是在源碼中獲取路由“組”指明確指出的。下一篇文章重點分析爲什麼發起路由操作時就可以進行跳轉時,會分析到這塊的代碼。請穩步我之前的文章(在學習ARouter源碼前自己挖的坑)ARouter報錯:Failed to extract default group! String index out of range: -2

然後,就可以發起路由操作了。

// 1. 應用內簡單的跳轉(通過URL跳轉在'進階用法'中)
ARouter.getInstance().build("/test/activity").navigation();

// 2. 跳轉並攜帶參數
ARouter.getInstance().build("/test/1")
            .withLong("key1", 666L)
            .withString("key3", "888")
            .withObject("key4", new Test("Jack", "Rose"))
            .navigation();

簡而言之,就是獲取ARouter單例後,調用build傳入路徑,若有參數,則通過withType添加鍵值對,最後調用naigation()方法即可。

我怎麼知道這些的呢?這是我必須告訴讀者的,魚與漁。ARouter的github上的指南以及它的源碼。

上面是跳轉到Activity,並傳遞簡單的參數,下面列下跳轉Fragment和Service的代碼,實質實際是完全一樣的。

@Route(path = "/test/fragment")
public class BlankFragment extends Fragment {

    @Autowired
    String name;

    ...
}
case R.id.getFragment:
     Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
     Toast.makeText(this, "找到Fragment:" + fragment.toString(), Toast.LENGTH_SHORT).show();
     break;
import com.alibaba.android.arouter.facade.template.IProvider;
//需要繼承IProvider
public interface HelloService extends IProvider {
    void sayHello(String name);
}

//接口實現類
@Route(path = "/yourservicegroupname/hello")
public class HelloServiceImpl implements HelloService {
    Context mContext;

    @Override
    public void sayHello(String name) {
        Toast.makeText(mContext, "Hello " + name, Toast.LENGTH_SHORT).show();
    }

    /**
     * Do your init work in this method, it well be call when processor has been load.
     *
     * @param context ctx
     */
    @Override
    public void init(Context context) {
        mContext = context;
        Log.e("testService", HelloService.class.getName() + " has init.");
    }
}

發起Service路由,有兩種方式,一種通過路由路徑,一種通過類

case R.id.navByName:
	((HelloService) ARouter.getInstance().build("/yourservicegroupname/hello").navigation()).sayHello("mike");
	break;
case R.id.navByType:
	ARouter.getInstance().navigation(HelloService.class).sayHello("mike");
	break;

目標界面接收參數

前面通過.withString()等方法傳入了對應類似的數據,目標界面需要代碼實現這個數據的接收。有兩種方式:一通過註解;二通過Intent本身接收。下面摘錄ARouter源碼中Demo工程的Test1Activity.java來說明這兩種方式。

@Route(path = "/test/activity1", name = "測試用 Activity")
public class Test1Activity extends AppCompatActivity {

    @Autowired(desc = "姓名")
    String name = "jack";

    @Autowired
    int age = 10;

    @Autowired
    int height = 175;

    @Autowired(name = "boy", required = true)
    boolean girl;

    @Autowired
    char ch = 'A';

    //方式一,並附默認值
    @Autowired
    float fl = 12.00f;

    @Autowired
    double dou = 12.01d;

    @Autowired
    TestSerializable ser;

    @Autowired
    TestParcelable pac;

    @Autowired
    TestObj obj;

    @Autowired
    List<TestObj> objList;

    @Autowired
    Map<String, List<TestObj>> map;

    private long high;

    @Autowired
    String url;

    @Autowired
    HelloService helloService;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test1);

        ARouter.getInstance().inject(this);    //方式一:通過註解,必須添加該句

        //方式二:爲下方註釋掉的代碼,它取Intent本身的bundle,其實方式一本質也是
        //只是被註解解釋處理了。

        // No more getter ...
        // name = getIntent().getStringExtra("name");
        // age = getIntent().getIntExtra("age", 0);
        // girl = getIntent().getBooleanExtra("girl", false);
        // high = getIntent().getLongExtra("high", 0);
        // url = getIntent().getStringExtra("url");

    }
}

截止目前,我們完成了構建依賴和路由跳轉及參數傳遞。下面看下高級用法。

ARouter進階高級用法

1.通過URL跳轉

// 新建一個Activity用於監聽Schame事件,之後直接把url傳遞給ARouter即可
public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //        直接通過ARouter處理外部Uri
        Uri uri = getIntent().getData();
        ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
            @Override
            public void onArrival(Postcard postcard) {
                finish();
            }
    }
}

//---------AndroidManifest.xml---------//
<activity android:name=".activity.SchameFilterActivity">
    <!-- Schame -->
    <intent-filter>
        <data
        android:host="m.aliyun.com"
        android:scheme="arouter"/>

        <action android:name="android.intent.action.VIEW"/>

        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
    </intent-filter>
</activity>

2.解析高級參數:List、Map、對象

ARouter對高級對象的參數傳遞也是支持,實現如下

// 爲每一個參數聲明一個字段,並使用 @Autowired 標註
// URL中不能傳遞Parcelable類型數據,通過ARouter api可以傳遞Parcelable對象
@Route(path = "/test/activity")
public class Test1Activity extends Activity {
    @Autowired
    public String name;
    @Autowired
    int age;
    
    // 通過name來映射URL中的不同參數
    @Autowired(name = "girl") 
    boolean boy;
    
    // 支持解析自定義對象,URL中使用json傳遞
    @Autowired
    TestObj obj;      
    
    // 使用 withObject 傳遞 List 和 Map 的實現了
    // Serializable 接口的實現類(ArrayList/HashMap)
    // 的時候,接收該對象的地方不能標註具體的實現類類型
    // 應僅標註爲 List 或 Map,否則會影響序列化中類型
    // 的判斷, 其他類似情況需要同樣處理        
    @Autowired
    List<TestObj> list;
    @Autowired
    Map<String, List<TestObj>> map;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ARouter.getInstance().inject(this);

    // ARouter會自動對字段進行賦值,無需主動獲取
    Log.d("param", name + age + boy);
    }
}


// 如果需要傳遞自定義對象,新建一個類(並非自定義對象類),然後實現 SerializationService,並使用@Route註解標註(方便用戶自行選擇序列化方式),例如:
@Route(path = "/yourservicegroupname/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);
    }
}

3.處理跳轉結果

// 使用兩個參數的navigation方法,可以獲取單次跳轉的結果
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
    @Override
    public void onFound(Postcard postcard) {
    ...
    }

    @Override
    public void onLost(Postcard postcard) {
    ...
    }
});

4.預處理服務

// 實現 PretreatmentService 接口,並加上一個Path內容任意的註解即可
@Route(path = "/xxx/xxx")
public class PretreatmentServiceImpl implements PretreatmentService {
    @Override
    public boolean onPretreatment(Context context, Postcard postcard) {
        // 跳轉前預處理,如果需要自行處理跳轉,該方法返回 false 即可
    }

    @Override
    public void init(Context context) {

    }
}

5.詳細API說明

// 構建標準的路由請求
ARouter.getInstance().build("/home/main").navigation();

// 構建標準的路由請求,並指定分組
ARouter.getInstance().build("/home/main", "ap").navigation();

// 構建標準的路由請求,通過Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();

// 構建標準的路由請求,startActivityForResult
// navigation的第一個參數必須是Activity,第二個參數則是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);

// 直接傳遞Bundle
Bundle params = new Bundle();
ARouter.getInstance()
    .build("/home/main")
    .with(params)
    .navigation();

// 指定Flag
ARouter.getInstance()
    .build("/home/main")
    .withFlags();
    .navigation();

// 獲取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
                    
// 對象傳遞
ARouter.getInstance()
    .withObject("key", new TestObj("Jack", "Rose"))
    .navigation();

// 覺得接口不夠多,可以直接拿出Bundle賦值
ARouter.getInstance()
        .build("/home/main")
        .getExtra();

// 轉場動畫(常規方式)
ARouter.getInstance()
    .build("/test/activity2")
    .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
    .navigation(this);

// 轉場動畫(API16+)
ActivityOptionsCompat compat = ActivityOptionsCompat.
    makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

// ps. makeSceneTransitionAnimation 使用共享元素的時候,需要在navigation方法中傳入當前Activity

ARouter.getInstance()
    .build("/test/activity2")
    .withOptionsCompat(compat)
    .navigation();
        
// 使用綠色通道(跳過所有的攔截器)
ARouter.getInstance().build("/home/main").greenChannel().navigation();

// 使用自己的日誌工具打印日誌
ARouter.setLogger();

// 使用自己提供的線程池
ARouter.setExecutor();

小結

使用一個框架來講,還是相對簡單。就像剛開始學習Java一樣,人家API就是這麼定義,根據你想實現的效果去找到對應的API,然後進行實現即可。

PS:高級進階用法是不全面的,詳細請穩步github上的文檔。中文地址:https://github.com/alibaba/ARouter/blob/master/README_CN.md

看完後,來打我吧。哈哈,因爲本文除了部分源碼外,多數出自github上的文檔,但這也是學習一個框架最官方的方法(假設沒有前輩整理)。

下一篇是最難的,源碼功能分析,解釋爲什麼API就生效,完成了我們想要的路由跳轉和參數傳遞等功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章