WMRouterソース分析(4)-ページルーティングインスタンス分析
5844 ワード
前述の論文では,
Activityのルーティング
は に設定する.は、アプリ内のインタフェースを優先的に起動します.すなわちintentに独自のpackage を設定する. APP内の起動に失敗し、APP外のインタフェースの起動が許可されている場合は、packageを空にし、 を再起動しようとします.起動時にアニメーションパラメータが設定されている場合は、 を追加する.
ここでは、公式demoでのブロッキングの使用を簡単に見てみましょう.
私のAndroidの進級計画を歓迎して、もっと干物を見てください.
WMRouter
の実装原理を大まかに理解したが,本稿では,Activityページに対するナビゲーションがどのように実装されているかを具体的な例を探してみる.Activityのルーティング
まず、@RouterUri
を使用して、Activity
がルーティング可能であることをマークします.@RouterUri(path = {DemoConstant.JUMP_ACTIVITY_1, DemoConstant.JUMP_ACTIVITY_2})
public class TestBasicActivity extends BaseActivity {}
ルーティングインタフェースを指定する場合は、scheme
、host
を指定せずに、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);
UriAnnotationHandler
のregister
メソッドは、前述の解析によれば、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)
を処理するUriHandler
はActivityClassNameHandler
であると判断できます.このクラスを見てみましょう.
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)
を呼び出すことです.この方法では主に以下のことをしました.
@RouterUri(path = {DemoConstant.JUMP_ACTIVITY_1, DemoConstant.JUMP_ACTIVITY_2})
public class TestBasicActivity extends BaseActivity {}
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);
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;
}
}
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);
}
}
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);
.....
}
UriRequest
の情報を取り出し、intentの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の進級計画を歓迎して、もっと干物を見てください.