ARouter使用方式及源碼學(xué)習(xí)

使用前配置

  1. 在每個module的build.gradle添加如下代碼,作用是為注解執(zhí)行器提供module的名稱
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
  1. 添加依賴
dependencies {
    api ''com.alibaba:arouter-api:1.4.1'
    annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
    ...
}
  1. 在Application初始化
if (isDebug()) {         
    ARouter.openLog(); 
    ARouter.openDebug();
}
ARouter.init(mApplication);
  1. 在需要使用的類聲明注解
@Route(path = "/test/activity")
public class YourActivity extend Activity {
    ...
}
  1. 調(diào)用api
// 1. Simple jump within application (Jump via URL in 'Advanced usage')
ARouter.getInstance().build("/test/activity").navigation();

// 2. Jump with parameters
ARouter.getInstance().build("/test/1")
            .withLong("key1", 666L)
            .withString("key3", "888")
            .withObject("key4", new Test("Jack", "Rose"))
            .navigation();
// 3. with Bundle
Bundle bundle= new Bundle();
ARouter.getInstance()
          .build("/test/1")
          .with(bundle)
          .navigation();
// 4. with Parcelable
public class LoginAction implements Parcelable {
}
@Route(path = ROUTE_LOGIN)
public class LoginActivity {
    @Autowired(name = Constants.INTENT_KEY_LOGIN_ACTION)
    public LoginAction loginAction;
}
ARouter.getInstance()
                    .build(ROUTE_LOGIN)
                    .withParcelable(Constants.INTENT_KEY_LOGIN_ACTION, loginAction)
                    .navigation();

注意:在工程的主module里需要依賴其他所有module纱注,否則會找不到路由

額外一些使用

  • 自定義Provider服務(wù)
// 1. 繼承IProvider接口
public interface MyService extends IProvider {
    String doSomething();
}
// 2. 實現(xiàn)MyService接口咪奖,加上注解
@Route(path = "/myservice/xxx")
public class MyServiceImpl implements MyService {
    @Override
    public void init(Context context) {
    }

    @Override
    public String doSomething() {
        return "haha";
    }
}
  • 獲取Provider服務(wù)的方法
// 1. 通過路徑獲取
ARouter.getInstance().build("/myservice/xxx").navigation()
// 2. 通過類名獲取
ARouter.getInstance().navigation(MyService.class)
  • 跳轉(zhuǎn)動畫(api >= 16)
ActivityOptionsCompat compat = ActivityOptionsCompat.makeCustomAnimation(this,
            R.anim.translate_in, R.anim.translate_none);

ARouter.getInstance()
           .build("/test/activity")
           .withOptionsCompat(compat)
           .navigation();
  • 跳轉(zhuǎn)攜帶參數(shù)不常用的一種内舟,原理是將實體類轉(zhuǎn)換成json字符串,通過String的方式進行傳遞
// 首先需要實現(xiàn)SerializationService
@Route(path = "/serializationservice/s1")
public class SerializationServiceIpml implements SerializationService {
    @Deprecated
    @Override
    public <T> T json2Object(String input, Class<T> clazz) {
        return null;
    }

    @Override
    public String object2Json(Object instance) {
        return null;
    }

    @Override
    public <T> T parseObject(String input, Type clazz) {
        return null;
    }

    @Override
    public void init(Context context) {

    }
}
ARouter.getInstance()
                    .build("/test/1")
                    .withObject("key_bean", bean)
                    .navigation();
  • 全局的降級策略
@Route(path = "/degradeservice/d1")
public class DegradeServiceImpl implements DegradeService {
    private static final String TAG = "DegradeServiceImpl";
    @Override
    public void onLost(Context context, Postcard postcard) {
        // do something.
        Log.d(TAG, "DegradeService##onLost");
    }

    @Override
    public void init(Context context) {
        Log.d(TAG, "DegradeService##init");
    }
}
  • 實現(xiàn)路徑轉(zhuǎn)換
@Route(path = "/pathservice/p1")
public class PathReplaceServiceImpl implements PathReplaceService {
    private static final String TAG = "PathReplaceServiceImpl";
    @Override
    public void init(Context context) {
        Log.d(TAG, "PathReplaceService##init");
    }

    @Override
    public String forString(String path) {
        Log.d(TAG, "PathReplaceService##forString");
        return path;
    }

    @Override
    public Uri forUri(Uri uri) {
        Log.d(TAG, "PathReplaceService##forUri");
        return uri;
    }
}
  • 使用帶回調(diào)的跳轉(zhuǎn)
ARouter.getInstance().build("/test/test1").navigation(this, new NavCallback() {
                @Override
                public void onFound(Postcard postcard) {
                     // 
                }

                @Override
                public void onLost(Postcard postcard) {
                    // 找不到路徑對應(yīng)的目標(biāo)
                }

                @Override
                public void onArrival(Postcard postcard) {
                    // 跳轉(zhuǎn)完成
                }

                @Override
                public void onInterrupt(Postcard postcard) {
                    // 被攔截了赞哗,Important! 該方法運行在子線程
                }
            });
  • 使用攔截器巧号,priority值越小,優(yōu)先級越高煎娇,值不能定義一樣的
@Interceptor(priority = 5)
public class Test1Interceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
       // process方法運行在子線程
       //在此方法中如果沒有調(diào)用以下兩個方法其中之一,那么不再執(zhí)行后續(xù)的攔截器
       //需等待300s(默認(rèn)值贪染,可設(shè)置改變)的時間缓呛,才能拋出攔截器中斷
       callback.onContinue(postcard);
       callback.onInterrupt(exception)
    }

    @Override
    public void init(Context context) {
       // 攔截器的初始化發(fā)生在跳轉(zhuǎn)之前
    }
}

源碼分析

ARouter提供了兩個SDK,分別是面向兩個不同的階段杭隙。API這個SDK是面向運行期的哟绊,而Compiler這個SDK則是作用于編譯期的。

一痰憎、 注解執(zhí)行器生成java代碼

此階段發(fā)生在編譯期票髓,主要是通過自定義的注解執(zhí)行器對代碼中的@Route、@Autowired和@Interceptor這三個注解進行解析铣耘,生成java文件洽沟。具體的細(xì)節(jié)請看這篇文章 阿里ARouter使用及源碼解析,注解執(zhí)行器的使用看這篇文章 Android編譯時注解APT實戰(zhàn)蜗细。

編譯生成的文件路徑和文件內(nèi)容如下:


文件路徑和文件名
public class ARouter$$Group$$mylibrary implements IRouteGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> atlas) {
    atlas.put("/mylibrary/MyLibActivity", RouteMeta.build(RouteType.ACTIVITY, MyLibActivity.class, 
    "/mylibrary/mylibactivity", "mylibrary", new java.util.HashMap<String, Integer>(){{
     put("name", 8); }}, -1, -2147483648));
  }
}

public class ARouter$$Providers$$mylibrary implements IProviderGroup {
  @Override
  public void loadInto(Map<String, RouteMeta> providers) {
  }
}

public class ARouter$$Root$$mylibrary implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("mylibrary", ARouter$$Group$$mylibrary.class);
  }
}

public class MyLibActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    MyLibActivity substitute = (MyLibActivity)target;
    substitute.name = substitute.getIntent().getStringExtra("name");
  }
}

public class ARouter$$Interceptors$$common implements IInterceptorGroup {
  @Override
  public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
    interceptors.put(5, Test1Interceptor.class);
  }
}

二裆操、 應(yīng)用啟動時初始化

// Application的onCreate方法中調(diào)用
ARouter.init(this);
 
public static void init(Application application) {
       if (!hasInit) {
           // 步驟1
           hasInit = _ARouter.init(application);
           if (hasInit) {
               // 步驟2
               _ARouter.afterInit();
           }
       }
 }
1. 步驟1主要是將自動生成的類加載進內(nèi)存?zhèn)}庫

ARouter 僅載入了 Group 清單怒详,并沒有具體載入每個 Group 中包含的具體的路由節(jié)點清單,只有當(dāng)使用到具體的 Group 時踪区,才會加載對應(yīng)的 Group 列表

首先判斷是否使用了插件來獲取“com.alibaba.android.arouter.routes”這個包底下的類名信息昆烁,如果沒有的話需要掃描dex文件來獲取這些信息。

// _ARouter的init方法
// 創(chuàng)建了一個核心數(shù)和最大數(shù)都為cpu+1的線程池缎岗,隊列為64
protected static synchronized boolean init(Application application) {
        mContext = application;
        // 主要方法
        LogisticsCenter.init(mContext, executor);
        hasInit = true;
        mHandler = new Handler(Looper.getMainLooper());
        return true;
}

// LogisticsCenter的init方法
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
        mContext = context;
        executor = tpe;

        try {
            // 判斷是否用插件掃描加載類信息
            if (registerByPlugin) {
                logger.info(TAG, "Load router map by arouter-auto-register plugin.");
            } else {
                Set<String> routerMap;

                // It will rebuild router map every times when debuggable.
                if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                    logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                    // 掃描dex
                    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                    if (!routerMap.isEmpty()) {
                        context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                    }

                    PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
                } else {
                   // 從緩存取
                    routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
                }

                logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                startInit = System.currentTimeMillis();
                // 反射生成對應(yīng)的類静尼,保存到內(nèi)存?zhèn)}庫
                for (String className : routerMap) {
                    if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                        // This one of root elements, load root.
                        ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                        // Load interceptorMeta
                        ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                        // Load providerIndex
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                    }
                }
            }
        } catch (Exception e) {
            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
        }
    }
2. 步驟2主要是初始化攔截器
  // _ARouter的afterInit方法
  static void afterInit() {
        interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
    }

此處初始化攔截器的方法和第三步要分析的調(diào)用過程是同一個,所以放一起分析传泊。

三鼠渺、調(diào)用過程分析

調(diào)用方法如下:

ARouter.getInstance().build("/arouter/service/interceptor").navigation();

1. ARouter.getInstance().build("/arouter/service/interceptor")最終會調(diào)用到_ARouter中的build方法
 protected Postcard build(String path) {
        if (TextUtils.isEmpty(path)) {
            throw new HandlerException(Consts.TAG + "Parameter is invalid!");
        } else {
            PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
            return build(path, extractGroup(path));
        }
    }

    protected Postcard build(String path, String group) {
        if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
            throw new HandlerException(Consts.TAG + "Parameter is invalid!");
        } else {
            PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
            if (null != pService) {
                path = pService.forString(path);
            }
            return new Postcard(path, group);
        }
    }

public final class Postcard extends RouteMeta {
    // Base
    private Uri uri;
    private Object tag;             // A tag prepare for some thing wrong.
    private Bundle mBundle;         // Data to transform
    private int flags = -1;         // Flags of route
    private int timeout = 300;      // Navigation timeout, TimeUnit.Second
    private IProvider provider;     // It will be set value, if this postcard was provider.
    private boolean greenChannel;
    private SerializationService serializationService;
    // Animation
    private Bundle optionsCompat;    // The transition animation of activity
    private int enterAnim = -1;
    private int exitAnim = -1;
}


這里主要做的事情就是生成一個Postcard對象,根據(jù)路徑截取group名稱或渤,保存在里面系冗。Postcard是RouteMeta的子類,保存了跳轉(zhuǎn)時相關(guān)的信息薪鹦。此處可以看到掌敬,如果我們實現(xiàn)了PathReplaceService,會調(diào)用forString方法進行轉(zhuǎn)換path

2. 拿到Postcard對象之后調(diào)用navigation池磁,最終調(diào)用的是_ARouter的navigation方法奔害,如下
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        try {
            // 方法1
            LogisticsCenter.completion(postcard);
        } catch (NoRouteFoundException ex) {
            // 如果拋異常了,有設(shè)置回調(diào)的話地熄,調(diào)用回調(diào)的onLost
            if (null != callback) {
                callback.onLost(postcard);
            } else {  
            // 如果沒有設(shè)置回調(diào)华临,則調(diào)用全局的降級策略,需要自己實現(xiàn)
                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                if (null != degradeService) {
                    degradeService.onLost(context, postcard);
                }
            }

            return null;
        }

        // 沒有拋異常端考,有設(shè)置回調(diào)的話雅潭,調(diào)用回調(diào)的onFound
        if (null != callback) {
            callback.onFound(postcard);
        }

        // 判斷是否需要經(jīng)過攔截器
        if (!postcard.isGreenChannel()) {
            // 關(guān)鍵方法3
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
            
                @Override
                public void onContinue(Postcard postcard) {
                   // 關(guān)鍵方法2
                    _navigation(context, postcard, requestCode, callback);
                }

                @Override
                public void onInterrupt(Throwable exception) {
                    if (null != callback) {
                        // 被攔截器攔截了,有設(shè)置回調(diào)的話却特,調(diào)用回調(diào)的onInterrupt
                        callback.onInterrupt(postcard);
                    }
                }
            });
        } else {
            // 關(guān)鍵方法2扶供,不管經(jīng)不經(jīng)過攔截器,最終都調(diào)用此方法
            return _navigation(context, postcard, requestCode, callback);
        }

        return null;
    }
1. 首先我們看關(guān)鍵方法1
public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }

        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
            Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
            if (null == groupMeta) {
                throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
            } else {
                // Load route and cache it into memory, then delete from metas.
                try {
                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }

                    IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                    iGroupInstance.loadInto(Warehouse.routes);
                    Warehouse.groupsIndex.remove(postcard.getGroup());

                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }
                } catch (Exception e) {
                    throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                }

                completion(postcard);   // Reload
            }
        } else {
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());

            Uri rawUri = postcard.getUri();
            if (null != rawUri) {   // Try to set params into bundle.
                Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                Map<String, Integer> paramsType = routeMeta.getParamsType();

                if (MapUtils.isNotEmpty(paramsType)) {
                    // Set value by its type, just for params which annotation by @Param
                    for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                        setValue(postcard,
                                params.getValue(),
                                params.getKey(),
                                resultMap.get(params.getKey()));
                    }

                    // Save params name which need auto inject.
                    postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                }

                // Save raw uri
                postcard.withString(ARouter.RAW_URI, rawUri.toString());
            }

            switch (routeMeta.getType()) {
                case PROVIDER:  // if the route is provider, should find its instance
                    // Its provider, so it must implement IProvider
                    Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                    IProvider instance = Warehouse.providers.get(providerMeta);
                    if (null == instance) { // There's no instance of this provider
                        IProvider provider;
                        try {
                            provider = providerMeta.getConstructor().newInstance();
                            provider.init(mContext);
                            Warehouse.providers.put(providerMeta, provider);
                            instance = provider;
                        } catch (Exception e) {
                            throw new HandlerException("Init provider failed! " + e.getMessage());
                        }
                    }
                    postcard.setProvider(instance);
                    postcard.greenChannel();    // Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
    }

此方法首先判斷內(nèi)存?zhèn)}庫Warehouse里面是否已經(jīng)有該路徑對應(yīng)的RouteMeta裂明,如果沒有則調(diào)用自動生成的IRouteGroup的loadInto方法加載進來椿浓,然后通過RouteMeta對postcard對象賦值。此外可以看到闽晦,IProvider和Fragment是不需要經(jīng)過攔截器的扳碍。

2. 接著我們看關(guān)鍵方法2
   private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
        final Context currentContext = null == context ? mContext : context;

        switch (postcard.getType()) {
            case ACTIVITY:
                // Build intent
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());

                // Set flags.
                int flags = postcard.getFlags();
                if (-1 != flags) {
                    intent.setFlags(flags);
                } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }

                // Set Actions
                String action = postcard.getAction();
                if (!TextUtils.isEmpty(action)) {
                    intent.setAction(action);
                }

                // Navigation in main looper.
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        startActivity(requestCode, currentContext, intent, postcard, callback);
                    }
                });

                break;
            case PROVIDER:
                return postcard.getProvider();
            case BOARDCAST:
            case CONTENT_PROVIDER:
            case FRAGMENT:
                Class fragmentMeta = postcard.getDestination();
                try {
                    Object instance = fragmentMeta.getConstructor().newInstance();
                    if (instance instanceof Fragment) {
                        ((Fragment) instance).setArguments(postcard.getExtras());
                    } else if (instance instanceof android.support.v4.app.Fragment) {
                        ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                    }

                    return instance;
                } catch (Exception ex) {
                    logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
                }
            case METHOD:
            case SERVICE:
            default:
                return null;
        }

        return null;
    }

// startActivity方法
private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
       if (requestCode >= 0) {  // Need start for result
            if (currentContext instanceof Activity) {
                ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
            } else {
                logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
            }
        } else {
            ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
        }

        if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) {    // Old version.
            ((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
        }
        // 跳轉(zhuǎn)之后,如果有設(shè)置回調(diào)仙蛉,調(diào)用onArrival
        if (null != callback) {
            callback.onArrival(postcard);
        }
    }

此方法比較簡單笋敞,就是根據(jù)不同的類型做不同的事情,Activity的話就執(zhí)行startActivity跳轉(zhuǎn)荠瘪,如果是Fragment的話就返回Fragment對象液样,如果是IProvider的話就返回IProvider對象振亮。

3. 最后我們看關(guān)鍵方法3
      if (!postcard.isGreenChannel()) {
            interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                /**
                 * Continue process
                 *
                 * @param postcard route meta
                 */
                @Override
                public void onContinue(Postcard postcard) {
                    _navigation(context, postcard, requestCode, callback);
                }

                /**
                 * Interrupt process, pipeline will be destory when this method called.
                 *
                 * @param exception Reson of interrupt.
                 */
                @Override
                public void onInterrupt(Throwable exception) {
                    if (null != callback) {
                        callback.onInterrupt(postcard);
                    }

                    logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());
                }
            });
      }

interceptorService是InterceptorServiceImpl對象,是在ARouter初始化時鞭莽,調(diào)用_ARouter的afterInit方法創(chuàng)建的坊秸,即ARouter.getInstance().build("/arouter/service/interceptor").navigation();
這個方法的流程在上面關(guān)鍵方法1我們已經(jīng)分析過了,它主要是初始化了InterceptorServiceImpl對象澎怒,并調(diào)用了init方法

case PROVIDER:
        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
        IProvider instance = Warehouse.providers.get(providerMeta);
        if (null == instance) { // There's no instance of this provider
                 IProvider provider;
                 try {
                      provider = providerMeta.getConstructor().newInstance();
                      provider.init(mContext);
                      Warehouse.providers.put(providerMeta, provider);
                      instance = provider;
                  } catch (Exception e) {
                       throw new HandlerException("Init provider failed! " + e.getMessage());
                  }
         }
         postcard.setProvider(instance);
         postcard.greenChannel();    // Provider should skip all of interceptors
         break;

下面看看InterceptorServiceImpl對象init方法

    @Override
    public void init(final Context context) {
        LogisticsCenter.executor.execute(new Runnable() {
            @Override
            public void run() {
                if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
                    for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
                        Class<? extends IInterceptor> interceptorClass = entry.getValue();
                        try {
                            IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
                            iInterceptor.init(context);
                            Warehouse.interceptors.add(iInterceptor);
                        } catch (Exception ex) {
                            throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
                        }
                    }

                    interceptorHasInit = true;

                    logger.info(TAG, "ARouter interceptors init over.");

                    synchronized (interceptorInitLock) {
                        interceptorInitLock.notifyAll();
                    }
                }
            }
        });
    }

此方法主要是按照優(yōu)先級順序生成所有攔截器對象褒搔,并調(diào)用攔截器的init方法,是在線程池中操作的喷面,所有init執(zhí)行完之后會將標(biāo)志位置為true星瘾,interceptorHasInit = true;

接著看看interceptorService的doInterceptions方法

    @Override
    public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
        if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
            // 第一步先檢查是否所有攔截器都執(zhí)行完init方法
            checkInterceptorsInitStatus();

            if (!interceptorHasInit) {
                callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
                return;
            }
            // 第二步在線程池中執(zhí)行攔截器的process方法
            LogisticsCenter.executor.execute(new Runnable() {
                @Override
                public void run() {
                    CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                    try {
                        // 關(guān)鍵方法
                        _excute(0, interceptorCounter, postcard);
                        // 設(shè)置等待的時間
                        interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                        if (interceptorCounter.getCount() > 0) {    // Cancel the navigation this time, if it hasn't return anythings.
                            callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
                        } else if (null != postcard.getTag()) {
                            // 在攔截器中我們可以給postcard設(shè)置tag,如果tag不為null惧辈,最終會走我們設(shè)置的callback的onInterrupt琳状,tag一般用來設(shè)置異常
                            callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                        } else {
                            callback.onContinue(postcard);
                        }
                    } catch (Exception e) {
                        callback.onInterrupt(e);
                    }
                }
            });
        } else {
            // 沒有攔截器
            callback.onContinue(postcard);
        }
    }

   private static void checkInterceptorsInitStatus() {
        synchronized (interceptorInitLock) {
            while (!interceptorHasInit) {
                try {
                    interceptorInitLock.wait(10 * 1000);
                } catch (InterruptedException e) {
                    throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]");
                }
            }
        }
    }

我們看看關(guān)鍵方法_excute

  private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
        if (index < Warehouse.interceptors.size()) {
            IInterceptor iInterceptor = Warehouse.interceptors.get(index);
            iInterceptor.process(postcard, new InterceptorCallback() {
                @Override
                public void onContinue(Postcard postcard) {
                    // Last interceptor excute over with no exception.
                    counter.countDown();
                    _excute(index + 1, counter, postcard);  
                }

                @Override
                public void onInterrupt(Throwable exception) {
                    postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());  
                    counter.cancel();

                }
            });
        }
    }

可以看到,這個方法主要是逐一取出攔截器盒齿,并執(zhí)行process方法念逞,在此方法中我們需要調(diào)用 callback.onContinue(postcard);或者callback.onInterrupt(exception);

四、 分析傳值的過程

傳值的方法在上面api使用已經(jīng)介紹過边翁,在相應(yīng)的界面翎承,我們可以通過注解和調(diào)用inject方法來獲取相應(yīng)的值

 @Autowired
 public String name;

 ARouter.getInstance().inject(this);

傳值的過程比較簡單,注解執(zhí)行器在編譯階段會將@Autowired注解生成對應(yīng)的文件符匾。

public class MyLibActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    MyLibActivity substitute = (MyLibActivity)target;
    substitute.name = substitute.getIntent().getStringExtra("name");
  }
}

當(dāng)你調(diào)用ARouter.getInstance().inject(this)時叨咖,根據(jù)類名取出相應(yīng)的ISyringe對象,該對象就是上面所說自動生成的類的對象

  static void inject(Object thiz) {
        AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
        if (null != autowiredService) {
            autowiredService.autowire(thiz);
        }
   }

    @Override
    public void autowire(Object instance) {
        String className = instance.getClass().getName();
        try {
            if (!blackList.contains(className)) {
                ISyringe autowiredHelper = classCache.get(className);
                if (null == autowiredHelper) {  // No cache.
                    autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                }
                autowiredHelper.inject(instance);
                classCache.put(className, autowiredHelper);
            }
        } catch (Exception ex) {
            blackList.add(className);    // This instance need not autowired.
        }
    }

最終調(diào)用了自動生成的類里面的inject方法啊胶,其實就是通過getIntent來對成員變量賦值

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    MyLibActivity substitute = (MyLibActivity)target;
    substitute.name = substitute.getIntent().getStringExtra("name");
  }

至此甸各,整個流程分析完了。

額外補充

  • Android Studio插件ARouterHelper可以方便的點擊跳轉(zhuǎn)到對應(yīng)的類
  • 通過gradle插件router表信息
apply plugin: 'com.alibaba.arouter'

 dependencies {
        classpath "com.alibaba:arouter-register:1.0.2"
   }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焰坪,一起剝皮案震驚了整個濱河市痴晦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琳彩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件部凑,死亡現(xiàn)場離奇詭異露乏,居然都是意外死亡,警方通過查閱死者的電腦和手機涂邀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門瘟仿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人比勉,你說我怎么就攤上這事劳较【灾梗” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵观蜗,是天一觀的道長臊恋。 經(jīng)常有香客問我,道長墓捻,這世上最難降的妖魔是什么抖仅? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮砖第,結(jié)果婚禮上撤卢,老公的妹妹穿的比我還像新娘。我一直安慰自己梧兼,他們只是感情好放吩,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羽杰,像睡著了一般渡紫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忽洛,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天腻惠,我揣著相機與錄音,去河邊找鬼欲虚。 笑死集灌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的复哆。 我是一名探鬼主播欣喧,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梯找!你這毒婦竟也來了唆阿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤锈锤,失蹤者是張志新(化名)和其女友劉穎驯鳖,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體久免,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡浅辙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了阎姥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片记舆。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呼巴,靈堂內(nèi)的尸體忽然破棺而出泽腮,到底是詐尸還是另有隱情御蒲,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布诊赊,位于F島的核電站厚满,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏豪筝。R本人自食惡果不足惜痰滋,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望续崖。 院中可真熱鬧敲街,春花似錦、人聲如沸严望。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽像吻。三九已至峻黍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拨匆,已是汗流浹背姆涩。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惭每,地道東北人骨饿。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像台腥,于是被迫代替她去往敵國和親宏赘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容