WMRouterソース分析(4)-ページルーティングインスタンス分析

5844 ワード

前述の論文では,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メソッドは、前述の解析によれば、PathHandlerを呼び出すregisterである.
    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)を呼び出すことです.この方法では主に以下のことをしました.
  • UriRequestの情報を取り出し、intentの
  • に設定する.
  • は、アプリ内のインタフェースを優先的に起動します.すなわちintentに独自のpackage
  • を設定する.
  • APP内の起動に失敗し、APP外のインタフェースの起動が許可されている場合は、packageを空にし、
  • を再起動しようとします.
  • 起動時にアニメーションパラメータが設定されている場合は、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が開く前に呼び出されます.ログインステータスをリスニングし、ログインに成功するとターゲットインタフェースをジャンプします.ソースコードの原理の前は実はすでに見たことがあって、ここはよく見ません.
    私のAndroidの進級計画を歓迎して、もっと干物を見てください.