Skip to content

1. Router

gaowei edited this page Apr 8, 2024 · 21 revisions

Activity导航

典型应用场景

  • 不方便直接拿到Activity.class
  • 端外、push、h5通过URI跳转Activity页面
  • 回调式onActivityResult,无需在Activity中覆写方法接收结果

定义和注册

  • scheme和host都是可省的,如果仅限于app内跳转,建议只用path
  • scheme、host、path都支持正则表达式,需要匹配任意字符串,可以使用".*"
  • path如果不是正则表达式,必须以/开头
  • scheme、host、path都支持占位符,以<>作为标记如,会把url中该位置的值赋给<>内的这个变量
@Router(scheme = "didi", host = "router", path = "/login")
public class ActivityLogin extends Activity {
}

发起导航

  • url中会把?后面的部分作为参数传入到putExtra中
  • putExtra的参数会存放到Activity的Intent中
  • putAddition的参数无法传递到Intent
  • DRouter支持一些系统扩展能力,比如动画。参考Extend类,使用putExtra(key, value)添加
DRouter.build("didi://router/login?a=1&b=2")
       .putExtra(Extend.START_ACTIVITY_FLAGS, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)   // flag
       .putExtra(key, value)  // 自定义参数
       .start(context, new RouterCallback() {
            @Override
            public void onResult(@NonNull Result result) {
                boolean r = result.isActivityStarted();
            }
       });

回调式onActivityResult

  • 方法1:最新的android建议使用ActivityResultLauncher来接受回调(推荐)
DRouter.build("/activity/result")
        .setActivityResultLauncher(launcher)    // 自定义ActivityResultLauncher
        .start(this)
  • 方法2:省略覆写Activity的onActivityResult方法和requestCode定义(已废弃)
DRouter.build("didi://router/login")
       .putExtra(key, value)
       .start(this, new RouterCallback.ActivityCallback() {
            @Override
            public void onActivityResult(int resultCode, Intent data) {
            }
       });

获取参数需要在Activity的getIntent中获取
  • 方法3:如果不方便添加注解,可以使用原生intent方式打开Activity,同样支持回调式onActivityResult
DRouter.build(null)
       .putExtra(Extend.START_ACTIVITY_VIA_INTENT, intent)
       .putExtra(key, value)
       .start(this, new RouterCallback.ActivityCallback() {
            @Override
            public void onActivityResult(int resultCode, Intent data) {
            }
       });

端外跳转

  • 提供一个端外跳转的入口Activity,通过DRouter分发出去,然后关闭页面
<activity android:name=".SchemeActivity">
    <intent-filter>
        <data android:scheme="didi" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.BROWSABLE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
// 自定义入口Activity
public class SchemeActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DRouter.build(getIntent().getData()).start(this);
        finish();
    }
}

Fragment导航

典型应用场景

  • 获取Fragment实例或者Class
  • 无反射

定义和注册

  • scheme、host、path命名策略同Activity
@Router(scheme = "didi", host = "router", path = "/message")
public class MessageFragment extends Fragment {
}

发起导航

  • putExtra的参数会存放到Fragment的setArguments中
  • putAddition的参数无法传递到Fragment
  • putExtra(Extend.START_FRAGMENT_NEW_INSTANCE,false),可以关闭自动实例化
DRouter.build("didi://router/message")
       .putExtra(Extend.START_ACTIVITY_FLAGS, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)   // flag
       .putExtra(key, value)  // 自定义参数
       .start(context, new RouterCallback() {
            @Override
            public void onResult(@NonNull Result result) {
                   Fragment f = result.getFragment();
                   Class<?> fCls = result.getRouterClass();
            }
       });

View导航

典型应用场景

  • 获取View实例或者Class
  • 无反射

定义和注册

  • scheme、host、path命名策略同Activity
@Router(scheme = "didi", host = "router", path = "/view/circle")
public class CircleView extends View {
}

发起导航

  • putExtra的参数会存放到View的setTag中
  • putAddition的参数无法传递到View
  • putExtra(Extend.START_VIEW_NEW_INSTANCE,false),可以关闭自动实例化
DRouter.build("didi://router/view/circle")
       .putExtra(key, value)
       .start(context, new RouterCallback() {
            @Override
            public void onResult(@NonNull Result result) {
                   View v = result.getView();
                   Class<?> vCls = result.getRouterClass();
            }
       });

RouterHandler导航

典型应用场景

  • 端外、push、h5跳转到native代码
  • 无需下沉接口的组件间通信,有数据返回能力
  • 增强版EventBus

静态定义和注册

  • 每次调用都会实例化
  • scheme、host、path命名策略同Activity
@Router(scheme = "didi", host = "router", path = "/sendOrder",
        thread = Thread.WORKER)   //指定执行线程
public class SendOrderHandler implements IRouterHandler {
    @Override
    void handle(@NonNull Request request, @NonNull Result result);
        // result可以添加数据,会返回给调用方
        // 如果需要拦截后面的所有结点可以执行,默认不拦截
        request.getInterceptor().onInterrupt();
    }
}

动态定义和注册

  • 在内部注册一个监听者,不会重新实例化,类似EventBus,比EventBus增加了数据返回的能力
  • 如果注册时使用了lifecycleOwner,会自动解注册
// 动态注册
IRegister register = 
       DRouter.register(
              RouterKey.build("/dynamic/handler").setLifecycleOwner(lifecycleOwner), 
              new IRouterHandler() {
                     @Override
                     public void handle(@NonNull Request request, @NonNull Result result) {
                     }
              });
// 解注册,如果注册时使用了生命周期,则可省
register.unregister();

发起导航

DRouter.build("didi://router/sendOrder")
       .putExtra(key, value)
       .start(context, new RouterCallback() {
            @Override
            public void onResult(@NonNull Result result) {
            }
       });

Hold

正常情况下Activity被start后以及RouterHandler的handle方法执行完成后,RouterCallback中的Result会立刻返回,如果希望RouterCallback中的Result可以等待目标某个触发时机然后才返回Result,同时不阻塞当前线程,可以考虑暂存Result

典型应用场景

  • 启动登录页,等待用户真正登陆成功后回调
  • 用户端外冷启动App,需要等待MainActivity的onResume回调或某些事情准备好后再回调
  • RouterHandler有耗时任务,希望等待执行完后再返回给调用方,又不阻塞调用方

配置

  • Activity和RouterHandler增加hold参数,就启用了HoldResult

异步Activity

@Router(scheme = "didi", host = "router", path = "/login"
        hold = "true")
public class ActivityLogin extends Activity {

    @Override
    protected void onCreate() {
        super.onCreate();
        Request request = RouterHelper.getRequest(this);
        Result result = RouterHelper.getResult(this);

        // 根据业务,在某个时间点触发这个释放(必须有)
        RouterHelper.release(this);
    }
}

异步RouterHandler

@Router(scheme = "didi", host = "router", path = "/sendOrder",
        hold = "true")
public class SendOrderHandler implements IRouterHandler {
    @Override
    void handle(@NonNull Request request, @NonNull Result result);
        
        // 根据业务,在某个时间点触发这个释放(必须有)
        RouterHelper.release(request);
    }
}

发起导航

  • 同普通的导航方式一样
DRouter.build("didi://router/sendOrder")
       .setHoldTimeout(3000)         // 设置超时时间内未返回则自动回调callback
       .start(context, new RouterCallback() {
            @Override
            public void onResult(@NonNull Result result) {
                // 只有目标被释放后才会回调,且不会阻塞该线程
            }
       });

RouterResult

典型应用场景

  • 监听请求结果,请求处理完后,会回调这个地方
  • 可以在这里做降级
@Service(function = IRouterResult.class)
public class RouterResult implements IRouterResult {

    @Override
    public void onResult(@NonNull Request request, @RouterState int state) {
   
    }
}

Interceptor

典型应用场景

  • 目标页面需要某种权限,比如登陆
  • 目标页面需要先进行某项操作,比如打开定位功能
  • 需要重定向

注意

  • 全局拦截器会在任意请求发起时执行
  • 非全局拦截器,只有当目标存在时,拦截器才会执行
  • 非全局@Interceptor注解可省略,但当使用注解时会避免使用反射,推荐使用

定义拦截器

  • 全局拦截器会在任意请求发起时都会执行

可以做一些预处理,比如重定向

@Interceptor(name = "interceptor1",          //可选,可以使用名字替代类耦合的方式来引用到
             priority = 1,                   //可选,优先级,值越大优先级越高
             global = true)                  //可选,是否是全局拦截器
public class LoginInterceptor implements IRouterInterceptor {
    @Override
    public void handle(@NonNull Request request) {

        if (isGo?) {
            request.getInterceptor().onContinue();
        } else {
            request.getInterceptor().onInterrupt();
        }
    }
}

应用

@Router(path = "/main",
        interceptor = LoginInterceptor.class)
public class MainActvity extends Activity {
}