WMRouter源码分析(4)-页面路由实例分析

94 篇文章 0 订阅
94 篇文章 0 订阅

前面的文章我们大致了解了WMRouter的实现原理,本文就找一个具体的实例来看一下对于一个Activity页面的导航是如何实现的。

Activity的路由

首先我们使用@RouterUri标记一个Activity可被路由:

@RouterUri(path = {DemoConstant.JUMP_ACTIVITY_1, DemoConstant.JUMP_ACTIVITY_2})
public class TestBasicActivity extends BaseActivity {}

在指定路由界面时,我们可以不指定schemehost,直接指定path即可。这样指定后我们直接 Router.startUri(DemoConstant.JUMP_ACTIVITY_1),就可以打开这个界面,下面我们就根据我们前面对于源码的分析,来看一下这个具体是怎么完成的:

首先,按照WMRouter的设计,肯定会生成一个UriHandler来处理这个uri,那是由哪个UriHandler来处理呢?

按照我们前面的分析@RouterUri标记的page,会被UriAnnotationProcessor扫描,并在运行时动态注册到UriAnnotationHandler中:

handler.register("", "", "/jump_activity_1", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false);
handler.register("", "", "/jump_activity_2", "com.sankuai.waimai.router.demo.basic.TestBasicActivity", false);

UriAnnotationHandlerregister方法,按照前面的分析,其实是调用PathHandlerregister:

    public void register(String path, Object target, boolean exported, UriInterceptor... interceptors) {
        if (!TextUtils.isEmpty(path)) {
            path = RouterUtils.appendSlash(path);
            UriHandler parse = UriTargetTools.parse(target, exported, interceptors);
            UriHandler prev = mMap.put(path, parse);
        }
    }

    public static UriHandler parse(Object target, boolean exported,UriInterceptor... interceptors) {
        UriHandler handler = toHandler(target);
        ......
        return handler;
    }

    private static UriHandler toHandler(Object target) {
        if (target instanceof UriHandler) {
            return (UriHandler) target;
        } else if (target instanceof String) {
            return new ActivityClassNameHandler((String) target);
        } else if (target instanceof Class && isValidActivityClass((Class) target)) {
            //noinspection unchecked
            return new ActivityHandler((Class<? extends Activity>) target);
        } else {
            return null;
        }
    }

因此我们可以确定处理Router.startUri(DemoConstant.JUMP_ACTIVITY_1)UriHandlerActivityClassNameHandler,我们来看一下这个类:

ActivityClassNameHandler

我们来看一下它的定义:

public class ActivityClassNameHandler extends AbsActivityHandler {
    @NonNull
    private final String mClassName;
    public ActivityClassNameHandler(@NonNull String className) {
        mClassName = className;
    }
    @Override protected Intent createIntent(@NonNull UriRequest request) {
        return new Intent().setClassName(request.getContext(), mClassName);
    }
}

这个类继承自AbsActivityHandler, 重写了父类的createIntent(), 就是返回了一个设置了类名的intent

public abstract class AbsActivityHandler extends UriHandler {
    .....
    protected void handleInternal(@NonNull UriRequest request, @NonNull UriCallback callback) {
        Intent intent = createIntent(request);
        if (intent == null || intent.getComponent() == null) {
            callback.onComplete(UriResult.CODE_ERROR);
            return;
        }
        intent.setData(request.getUri());
        UriSourceTools.setIntentSource(intent, request);
        request.putFieldIfAbsent(ActivityLauncher.FIELD_LIMIT_PACKAGE, limitPackage());  // 启动Activity
        int resultCode = RouterComponents.startActivity(request, intent);
        callback.onComplete(resultCode);
    }

    //是否只启动当前APP中的Activity
    protected boolean limitPackage() {
        return true;
    }

    @NonNull
    protected abstract Intent createIntent(@NonNull UriRequest request);
    .....
}

可以看到在创建好intent后,真正的Activity的启动时委派给RouterComponents.startActivity(request, intent)。其实最终启动Activity是调用DefaultActivityLauncher.startActivity(UriRequest, context)
在这个方法中主要做了一下事情:

  1. 取出UriRequest中的一些信息,设置到intent中
  2. 优先启动APP内的界面。即在intent中设置自己的package
  3. APP内启动失败,如果允许启动APP外的界面,则清空package,再次尝试启动
  4. 启动时如果设置有动画参数,则添加上overridePendingTransition

拦截器的使用

我们这里就简单的看一下官方demo中对拦截器的使用 :

@RouterUri(path = DemoConstant.ACCOUNT_WITH_LOGIN_INTERCEPTOR,
        interceptors = LoginInterceptor.class)
public class UserAccountActivity extends BaseActivity {}

public class LoginInterceptor implements UriInterceptor {
    @Override
    public void intercept(@NonNull UriRequest request, @NonNull final UriCallback callback) {
        final IAccountService accountService = DemoServiceManager.getAccountService();
        if (accountService.isLogin()) {
            callback.onNext();
        } else {
            Toast.makeText(request.getContext(), "请先登录~", Toast.LENGTH_SHORT).show();
            accountService.registerObserver(new IAccountService.Observer() {
                @Override
                public void onLoginSuccess() {
                    accountService.unregisterObserver(this);
                    callback.onNext();
                }
                ....
            });
            DemoServiceManager.getAccountService().startLogin(request.getContext());
        }
    }
}

LoginInterceptor会在UserAccountActivity打开之前调用。监听登录状态,登录成功后则跳转目标界面。源码原理前面其实已经看过了,这里就不仔细看了。

 

 

+qq群:853967238。获取以上高清技术思维图,以及相关技术的免费视频学习资料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值