Android路由

一、模块化和组件化

Android开发中,随着功能的不断增加,整个项目越来约庞大,导致代码结构混乱,修改繁琐,管理困难,android模块化开发的思想应运而生。模块化主要时为了解耦,将功能以模块的形式进行封装,模块间通过接口调用形进行通信,不同功能可以由不同的开发人员去开发、维护,每个开发人员只需关注自己负责的模块即可。 简单的模块化开发只需将不同的模块代码放在不同的文家夹路径下即可区分,但是复杂的项目或者便于独立依赖引用的需要可能需要将不同的模块功能放置在不同的library中,此时依赖和接触依赖只需在build.gradle中配置即可。

那么什么时组件化呢?组件化和模块化有什么区别呢?其实组件化是模块化的延伸,模块化是以android library的形式等待其他模块依赖调用,组件化也有这个功能,区别就是组件化可以根据build.gradle中配置将自己作为android application,在自身功能调试时将自己设为android application称为一个独立的app方便开发调试,当功能调试完成后正式发布时再将自身设为android library供第三方调用,如下面设置

//build.gradle
if (!DEBUG) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}
……
//gradle.properties
……
DEBUG = true

 

二、ARouter

由于观察者模式的大量使用,模块之前的通信就更加频繁,为了不至于出现模块间相互依赖的混乱场面,各种路由通信机制也产生了。EventBus可以用于模块间的消息传递,在EventBus使用姿势和源码分析一文中有提到EventBus-2.4使用观察者订阅以及反射的方式来实现功能,也可以通过android的广播机制来通信,今天主要介绍阿里的路由框架ARouter。

2.1 使用

2.1.1 gradle配置

要使用ARouter的moudle所在的build.gradle中添加依赖(最新版本号可以查看ARouter/gradle.properties文件中arouter_main_version的值),添加module参数(主module和library中都需要添加)

//build.gradle
android {
    ……
	defaultConfig {
……
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName()]
            }
        }
    }
……
}
……
implementation 'com.alibaba:arouter-api:1.5.1'
annotationProcessor 'com.alibaba:arouter-compiler:1.5.1'

2.1.2初始化

越早越好,最好在Application的onCreate方法中去初始化 

public class MyApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ARouter.init(this); //初始化
        ARouter.openDebug(); //打开debug开关
        ARouter.openLog(); //打开log开关
    }
}

2.1.3添加module依赖

一个android工程有一个主module和多个library module。这里library module想被编译到apk中的话必须被主module依赖或者传递被主module依赖。比如本文中的主module依赖了两个library module

implementation project(path: ':mylibrary2')
implementation project(path: ':mylibrary')

 

这里可能会有人问了,既然主module都直接依赖library module,那么直接调用不就完了,还整路由干啥?这里需要注意,虽然我这里主module依赖两个library module,但是两个library module并没有相互依赖哦,两个library module是不能相互调用的,但是由于它们都依赖了路由库,现在它们可以通过路由库相互调用了。路由的另外一个优点是可以进行一些拦截处理,中间过程可控。

2.1.4 定义路由

在library的Activity中声明路由路径

//Lib1Activity.java
package com.shan.mylibrary;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;

@Route(path = "/lib1/Lib1Activity") //路由路径
public class Lib1Activity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lib1);
        Toast.makeText(this,"this is Lib1Activity toast",Toast.LENGTH_SHORT).show();
        ARouter.getInstance().build("/lib2/Lib2Activity") //跳转到Lib2Activity
                .navigation();
    }
}
//Lib2Activity.java
package com.shan.mylibrary2;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;

@Route(path = "/lib2/Lib2Activity") //路由路径
public class Lib2Activity extends AppCompatActivity {

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

2.1.5路由跳转和拦截

现在通过主moudle跳转到Lib1Activity,由于有Lib1Activity的onCreate又执行了跳转Lib2Activity的操作,虽然mylibrary没有依赖mylibrary2,但是通过路由库的中转, 最终跳转到了Lib2Activity界面

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MyRouterApp";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: ");
        ARouter.getInstance().build("/lib1/Lib1Activity")
                .navigation();

    }
}

在mylibrary2中创建Lib2Interceptor.java,使用@Interceptor注解标注类名,拦截是app全局的,这里使用onContinue放任了跳转继续执行,也可以使用onInterrupt来阻止跳转。

package com.shan.mylibrary2;

import android.content.Context;
import android.util.Log;

import com.alibaba.android.arouter.facade.Postcard;
import com.alibaba.android.arouter.facade.annotation.Interceptor;
import com.alibaba.android.arouter.facade.callback.InterceptorCallback;
import com.alibaba.android.arouter.facade.template.IInterceptor;

@Interceptor(priority = 8)
public class Lib2Interceptor implements IInterceptor {
    private Context mContext;
    private static final String TAG  = "Lib2Interceptor";

    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        Log.d(TAG, "process: "+postcard.getPath()+",本次放行");
        callback.onContinue(postcard);
		// callback.onInterrupt(postcard);//放行
    }

    @Override
    public void init(Context context) {
        mContext = context;
        Log.d(TAG, "init: ");
    }
}

2.1.6 路由调用

前面提到了通过path方式来指定module之间activity的跳转,那么两个module间怎么调用不同module的类方法呢?此时就需要IProvider上场了。首先定义一个基本库baselibrary定义接口方法供其他module去实现,baselibrary也需要依赖路由库并且指定相关参数。然后在baselibrary创建一个BaseService接口,并创建一个接口方法。

//BaseService.java
package com.shan.baselibrary;
import com.alibaba.android.arouter.facade.template.IProvider;

public interface BaseService extends IProvider {
    void sayHello();
}

 这里为了演示,我在mylibrary中创建Lib1ServiceImpl.java去实现BaseService接口方法 

 

//Lib1ServiceImpl.java
package com.shan.mylibrary;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.shan.baselibrary.BaseService;

@Route(path = "/Lib1ServiceImpl/hello")
public class Lib1ServiceImpl implements BaseService {
    private Context mContext;
    @Override
    public void sayHello() {
        Toast.makeText(mContext,"Lib1ServiceImpl sayHello",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void init(Context context) {
        Log.d("Lib1ServiceImpl", "init: ");
        mContext = context;
    }
}

然后在mylibrary2的Lib2Activity的点击事件中去调用Lib1ServiceImpl.sayHello方法,点击执行go方法后就有toast提示了,跨module类方法调用,真他么香。

package com.shan.mylibrary2;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.shan.baselibrary.BaseService;

@Route(path = "/lib2/Lib2Activity") //路由路径
public class Lib2Activity extends AppCompatActivity {

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

    public void go(View view) {
       ((BaseService) ARouter.getInstance().build("/Lib1ServiceImpl/hello").navigation()).sayHello();
    }
}

2.2 原理分析

2.2.1 路由库jar

上面提到需要在build.gardle中依赖路由库com.alibaba:arouter-api和com.alibaba:arouter-compiler,可以在as的External Libraries中找到已下载到本地的arouter-annotation-1.0.6.jar和jetified-arouter-api-1.5.1.aar

(1)arouter-annotation-1.0.6.jar

arouter-annotation-1.0.6.jar中声明了注解元数据,Autowired在上面用到过,可以通过注解的方式传递一些成员变量;Interceptor用于声明跳转拦截器,注意这里的拦截器是全局的,路由库初始化时拦截器就会初始化;Route声明activity和服务的跳转路径。 

 

(2)jetified-arouter-api-1.5.1.aar

jetified-arouter-api-1.5.1.aar中主要涉及一些api接口供三方app调用,路由库的具体实现逻辑都在这里展开。

2.2.2 注解生成类

路由库使用了注解来自动生成相关辅助类,可以在module的build/generated/ap_generated_sources/debug/out/com.alibaba.android.arouter.routes目录下看到自动生成的java文件

这些注解的作用就是搜集被路由库元数据注解的类或成员变量,等待后续被路由库具体实现jetified-arouter-api-1.5.1.aar调用。

2.2.3路由库初始化

ARouter.init(this)调用了_ARouter的init方法,实际上这里使用了门面模式,_ARouter的init方法调用了LogisticsCenter的init方法。

 

//_ARouter.java
protected static synchronized boolean init(Application application) {
    mContext = application;
    LogisticsCenter.init(mContext, executor);
    logger.info(Consts.TAG, "ARouter init success!");
    hasInit = true;
    mHandler = new Handler(Looper.getMainLooper());

    return true;
}

LogisticsCenter的init方法根据是否是debug模式选择不同的加载方式:如果是debug模式则获取dex文件中以ROUTE_ROOT_PAKCAGE = "com.alibaba.android.arouter.routes"开头的的class;否则,从sp文件中读取。然后遍历含有路由库集合routerMap,将注解类添加到Warehouse.groupsIndex中,实际上会调用2.2.2中生成的com.alibaba.android.arouter.routes开头的类,比如ARouter\$\$Root$$mylibrary.java的loadInto方法会被调用。这样就完成了所有module中注解生成类的添加。

//LogisticsCenter.java
    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {

            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.");
                    // These class was generated by arouter-compiler.
                    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 {
                    logger.info(TAG, "Load router map from cache.");
                    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();

                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); //加载IRouteRoot
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
                        // Load interceptorMeta
                        ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex); //加载IInterceptorGroup
                    } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                        // Load providerIndex
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex); //加载IProviderGroup
                    }
                }
            }          
    }
/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$mylibrary implements IRouteRoot {
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
    routes.put("Lib1ServiceImpl", ARouter$$Group$$Lib1ServiceImpl.class);
    routes.put("lib1", ARouter$$Group$$lib1.class);
  }
}

2.2.4 activity路由跳转代码追踪

//MainActivity.java,调用者
ARouter.getInstance().build("/lib1/Lib1Activity")
        .withInt("age",66)
        .navigation();
//Lib1Activity.java,被调用者
@Route(path = "/lib1/Lib1Activity") //路由路径
public class Lib1Activity extends AppCompatActivity {
    @Autowired //注解成员变量,可以通过路由传参数
    int age = 10;  //成员变量默认值

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lib1);
        ARouter.getInstance().inject(this);//与Autowired配合使用
        Toast.makeText(this,"this is Lib1Activity toast:"+age,Toast.LENGTH_SHORT).show();
    }
}

 

(1)Autowired

先说参数Autowired,跟进ARouter.getInstance().inject(this)跳转到_ARouter.inject,这里是个门面模式的使用,具体逻辑功能实现在_ARouter.java,暴露给三方app的是ARouter.java。 

 

//ARouter.java
/**
 * Inject params and services.
 */
public void inject(Object thiz) {
    _ARouter.inject(thiz);
}

_ARouter的inject方法创建了一个接口服务,然后调用接口服务的autowire实现方法

//_ARouter.java
static void inject(Object thiz) {
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());//路由库自身创建了一个接口服务
    if (null != autowiredService) {
        autowiredService.autowire(thiz);//自动绑定
    }
}

autowiredService的具体实现是AutowiredServiceImpl.java,AutowiredServiceImpl的的autowire方法调用了类内的doInject方法。doInject是个递归方法,先将传递的实例进行绑定,如果实例还有父类,则将父类也进行绑定。首先调用getSyringe方法获取ISyringe实例,然后 调用ISyringe实例的inject方法。2.2.2中提到自动生成的注解类中有个类Lib1Activity\$\$ARouter$$Autowired.java,它就是一个ISyringe实例。Lib1Activity\$\$ARouter$$Autowired.java中实现了inject方法,并且将目标注解的age对象赋值为传递过来的intent值。

//AutowiredServiceImpl.java
/**
 * Recursive injection
 *
 * @param instance who call me.
 * @param parent   parent of me.
 */
private void doInject(Object instance, Class<?> parent) {
    Class<?> clazz = null == parent ? instance.getClass() : parent;

    ISyringe syringe = getSyringe(clazz);
    if (null != syringe) {
        syringe.inject(instance); //绑定
    }

    Class<?> superClazz = clazz.getSuperclass();
    // has parent and its not the class of framework.
    if (null != superClazz && !superClazz.getName().startsWith("android")) {
        doInject(instance, superClazz);
    }
}
//Lib1Activity$$ARouter$$Autowired.java
package com.shan.mylibrary;

import com.alibaba.android.arouter.facade.service.SerializationService;
import com.alibaba.android.arouter.facade.template.ISyringe;
import com.alibaba.android.arouter.launcher.ARouter;
import java.lang.Object;
import java.lang.Override;

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class Lib1Activity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    Lib1Activity substitute = (Lib1Activity)target;
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
  }
}

 getSyringe方法先从classCache中判断该类是否已经添加过,如果没有则通过clazz.getName() + SUFFIX_AUTOWIRED格式创建一个syringeHelper 出来,看下常量的值就可以和Lib1Activity\$\$ARouter$$Autowired.java联系起来了,那么此时创建的就是一个Lib1Activity\$\$ARouter$$Autowired.java,将新建的Lib1Activity\$\$ARouter$$Autowired.java添加到classCache中,然后将Lib1Activity$$ARouter$$Autowired.java作为方法返回值返回,这就是路由库注解变量传参原理过程。

//Consts.java
public final class Consts {
    public static final String SDK_NAME = "ARouter";
    public static final String SEPARATOR = "$$";
    public static final String SUFFIX_AUTOWIRED = SEPARATOR + SDK_NAME + SEPARATOR + "Autowired";
}
//AutowiredServiceImpl.java
private ISyringe getSyringe(Class<?> clazz) {
    String className = clazz.getName();

    try {
        if (!blackList.contains(className)) {
            ISyringe syringeHelper = classCache.get(className);
            if (null == syringeHelper) {  // No cache.
                syringeHelper = (ISyringe) Class.forName(clazz.getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
            }
            classCache.put(className, syringeHelper);
            return syringeHelper;
        }
    } catch (Exception e) {
        blackList.add(className);    // This instance need not autowired.
    }

    return null;
}

 (2)跳转

刚才的Autowired实际上讲解的是withInt("age",66)方法,那么本小节的跳转主要讲解navigation()方法。Postcard.java的navigation()方法最终会调用ARouter.java的navigation()方法,ARouter.java的navigation()方法会调用门面具体实现_ARouter.java的navigation()方法。

//Postcard.java
public Object navigation(Context context, NavigationCallback callback) {
    return ARouter.getInstance().navigation(context, this, -1, callback);
}

ARouter.java的navigation()方法先通过LogisticsCenter.completion方法添加一些参数配置,然后根据拦截情况执行_navigation方法或者打断。

//_ARouter.java
protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
    if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
        // Pretreatment failed, navigation canceled.
        return null;
    }

    try {
        LogisticsCenter.completion(postcard);//判断此路由信息是否已添加到Warehouse.groupsIndex中,如果没有则调用loadInto方法添加
    } catch (NoRouteFoundException ex) {
        logger.warning(Consts.TAG, ex.getMessage());

        if (debuggable()) {
            // Show friendly tips for user.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "There's no route matched!\n" +
                            " Path = [" + postcard.getPath() + "]\n" +
                            " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();
                }
            });
        }

        if (null != callback) {
            callback.onLost(postcard);
        } else {
            // No callback for this invoke, then we use the global degrade service.
            DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
            if (null != degradeService) {
                degradeService.onLost(context, postcard); //丢失回调
            }
        }

        return null;
    }

    if (null != callback) {
        callback.onFound(postcard); //命中回调
    }

    if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.
        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());
            }
        });
    } else {
        return _navigation(context, postcard, requestCode, callback);
    }

    return null;
}

 LogisticsCenter.completion方法先检查该路由是否已加载到Warehouse.routes,如果没有则调用loadInto方法加载到Warehouse.routes,然后添加一些目的地、优先级等参数,对于接口服务使用IOC创建具体实例。

 //LogisticsCenter.java
   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.该路由还未加载到Warehouse.routes
            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); //通过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;
            }
        }
    }

继续看_navigation方法,_navigation就是根据不同的类型调用具体方法,这里的Activity就是调用了startActivity完成跳转

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;
}

 

 

 

 

 

 

 

 

 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值