diff --git a/arouter-api/build.gradle b/arouter-api/build.gradle index e43a5777..c8e54073 100644 --- a/arouter-api/build.gradle +++ b/arouter-api/build.gradle @@ -1,4 +1,8 @@ apply plugin: 'com.android.library' +apply plugin: 'maven' + + + ext { bintrayName = 'arouter-api' diff --git a/arouter-api/src/main/java/com/alibaba/android/arouter/facade/Postcard.java b/arouter-api/src/main/java/com/alibaba/android/arouter/facade/Postcard.java index b87a3b6d..4346cefe 100644 --- a/arouter-api/src/main/java/com/alibaba/android/arouter/facade/Postcard.java +++ b/arouter-api/src/main/java/com/alibaba/android/arouter/facade/Postcard.java @@ -1,9 +1,11 @@ package com.alibaba.android.arouter.facade; import android.app.Activity; +import android.app.Fragment; import android.content.Context; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; @@ -166,6 +168,27 @@ public void navigation(Activity mContext, int requestCode, NavigationCallback ca ARouter.getInstance().navigation(mContext, this, requestCode, callback); } + + public void navigation(android.support.v4.app.Fragment fragment, int requestCode) { + navigation(fragment, requestCode, null); + } + + public void navigation(android.support.v4.app.Fragment fragment, int requestCode, NavigationCallback callback) { + ARouter.getInstance().navigation(fragment, this, requestCode, callback); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + public void navigation(Fragment fragment, int requestCode) { + navigation(fragment, requestCode, null); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + public void navigation(Fragment fragment, int requestCode, NavigationCallback callback) { + ARouter.getInstance().navigation(fragment, this, requestCode, callback); + } + + + /** * Green channel, it will skip all of interceptors. * diff --git a/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/ARouter.java b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/ARouter.java index aa9d3d7e..eb141ebd 100644 --- a/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/ARouter.java +++ b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/ARouter.java @@ -1,8 +1,11 @@ package com.alibaba.android.arouter.launcher; import android.app.Application; +import android.app.Fragment; import android.content.Context; import android.net.Uri; +import android.os.Build; +import android.support.annotation.RequiresApi; import com.alibaba.android.arouter.exception.InitException; import com.alibaba.android.arouter.facade.Postcard; @@ -181,6 +184,17 @@ public T navigation(Class service) { * @param callback cb */ public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) { - return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback); + return _ARouter.getInstance().navigation(mContext, null, postcard, requestCode, callback); } + + + public Object navigation(android.support.v4.app.Fragment fragment, Postcard postcard, int requestCode, NavigationCallback callback) { + return _ARouter.getInstance().navigation(fragment.getContext(), fragment, postcard, requestCode, callback); + } + + @RequiresApi(api = Build.VERSION_CODES.M) + public Object navigation(Fragment fragment, Postcard postcard, int requestCode, NavigationCallback callback) { + return _ARouter.getInstance().navigation(fragment.getContext(), fragment, postcard, requestCode, callback); + } + } diff --git a/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/CurrentActivityLifecycleCallback.java b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/CurrentActivityLifecycleCallback.java new file mode 100644 index 00000000..cbd196a3 --- /dev/null +++ b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/CurrentActivityLifecycleCallback.java @@ -0,0 +1,61 @@ +package com.alibaba.android.arouter.launcher; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Application; +import android.os.Build; +import android.os.Bundle; + +import java.lang.ref.WeakReference; + + +/** + * 获取当期activity + */ +@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) +final class CurrentActivityLifecycleCallback implements Application.ActivityLifecycleCallbacks { + + private WeakReference mCurrentActivity; + + public CurrentActivityLifecycleCallback() { + } + + public Activity getCurrentActivity() { + return mCurrentActivity == null ? null : mCurrentActivity.get(); + } + + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + mCurrentActivity = new WeakReference<>(activity); + } + + @Override + public void onActivityStarted(Activity activity) { + + } + + @Override + public void onActivityResumed(Activity activity) { + + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } +} diff --git a/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/_ARouter.java b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/_ARouter.java index f14eae3d..ad5b98bd 100644 --- a/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/_ARouter.java +++ b/arouter-api/src/main/java/com/alibaba/android/arouter/launcher/_ARouter.java @@ -4,8 +4,10 @@ import android.app.Application; import android.app.Fragment; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.support.v4.app.ActivityCompat; @@ -34,6 +36,8 @@ import java.lang.reflect.Method; import java.util.concurrent.ThreadPoolExecutor; +import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH; + /** * ARouter core (Facade patten) * @@ -54,6 +58,8 @@ final class _ARouter { private static InterceptorService interceptorService; + private static CurrentActivityLifecycleCallback currentActivityLifecycleCallback; + private _ARouter() { } @@ -64,9 +70,24 @@ protected static synchronized boolean init(Application application) { hasInit = true; mHandler = new Handler(Looper.getMainLooper()); + + if (Build.VERSION.SDK_INT >= ICE_CREAM_SANDWICH) { + currentActivityLifecycleCallback = new CurrentActivityLifecycleCallback(); + application.registerActivityLifecycleCallbacks(currentActivityLifecycleCallback); + } + return true; } + + static synchronized Activity getCurrentActivity() { + if (Build.VERSION.SDK_INT >= ICE_CREAM_SANDWICH && currentActivityLifecycleCallback != null) { + return currentActivityLifecycleCallback.getCurrentActivity(); + } else { + return null; + } + } + /** * Destroy arouter, it can be used only in debug mode. */ @@ -244,6 +265,7 @@ static void afterInit() { interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation(); } + @SuppressWarnings("unchecked") protected T navigation(Class service) { try { Postcard postcard = LogisticsCenter.buildProvider(service.getName()); @@ -271,11 +293,14 @@ protected T navigation(Class service) { * Use router navigation. * * @param context Activity or null. + * @param jumper Context or Fragment * @param postcard Route metas * @param requestCode RequestCode * @param callback cb */ - protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { + protected Object navigation(final Context context, Object jumper, final Postcard postcard, final int requestCode, final NavigationCallback callback) { + final Object _jumper = jumper == null ? context : jumper; + try { LogisticsCenter.completion(postcard); } catch (NoRouteFoundException ex) { @@ -318,7 +343,7 @@ public void run() { */ @Override public void onContinue(Postcard postcard) { - _navigation(context, postcard, requestCode, callback); + _navigation(_jumper, postcard, requestCode, callback); } /** @@ -336,26 +361,43 @@ public void onInterrupt(Throwable exception) { } }); } else { - return _navigation(context, postcard, requestCode, callback); + return _navigation(_jumper, postcard, requestCode, callback); } return null; } - private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) { - final Context currentContext = null == context ? mContext : context; + /** + * @param jumper fragment或context + */ + private Object _navigation(final Object jumper, final Postcard postcard, final int requestCode, final NavigationCallback callback) { + final Object _jumper; + + final Activity activity = getActivity(jumper); + boolean uiContext = activity != null; + if (uiContext) { + _jumper = jumper; + } else { + final Activity currentActivity = getCurrentActivity(); + if (currentActivity == null) { + _jumper = mContext; + } else { + uiContext = true; + _jumper = currentActivity; + } + } switch (postcard.getType()) { case ACTIVITY: // Build intent - final Intent intent = new Intent(currentContext, postcard.getDestination()); + final Intent intent = new Intent(mContext, 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. + } else if (!uiContext) { // Non activity, need less one flag. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } @@ -369,7 +411,7 @@ private Object _navigation(final Context context, final Postcard postcard, final runInMainThread(new Runnable() { @Override public void run() { - startActivity(requestCode, currentContext, intent, postcard, callback); + startActivity(requestCode, _jumper, intent, postcard, callback); } }); @@ -416,25 +458,77 @@ private void runInMainThread(Runnable runnable) { /** * Start activity - * @see ActivityCompat + * + * @param requestCode + * @param jumper + * @param intent + * @param postcard + * @param callback */ - private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) { - if (requestCode >= 0) { // Need start for result - if (currentContext instanceof Activity) { - ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle()); + private void startActivity(int requestCode, Object jumper, Intent intent, Postcard postcard, NavigationCallback callback) { + if (jumper instanceof Context) { + if (requestCode >= 0) { // Need start for result + ActivityCompat.startActivityForResult(getActivityByContext((Context) jumper) + , intent, requestCode, postcard.getOptionsBundle()); + } else { + ActivityCompat.startActivity((Context) jumper, intent, postcard.getOptionsBundle()); + } + } else if (jumper instanceof android.support.v4.app.Fragment) { + if (requestCode >= 0) { + ((android.support.v4.app.Fragment) jumper) + .startActivityForResult(intent, requestCode, postcard.getOptionsBundle()); + } else { + ((android.support.v4.app.Fragment) jumper).startActivity(intent, postcard.getOptionsBundle()); + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && jumper instanceof Fragment) { + if (requestCode >= 0) { + ((Fragment) jumper) + .startActivityForResult(intent, requestCode, postcard.getOptionsBundle()); } else { - logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]"); + ((Fragment) jumper).startActivity(intent, postcard.getOptionsBundle()); } } else { - ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle()); + throw new RuntimeException("the jumper type must be Context or Fragment"); } - if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) { // Old version. - ((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim()); + if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim())) { // Old version. + final Activity activity = getActivity(jumper); + + if (activity != null) { + activity.overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim()); + } } if (null != callback) { // Navigation over. callback.onArrival(postcard); } } + + private Activity getActivity(Object obj) { + if (obj instanceof Activity) { + return (Activity) obj; + } else if (obj instanceof Context) { + return getActivityByContext((Context) obj); + } else if (obj instanceof android.support.v4.app.Fragment) { + return ((android.support.v4.app.Fragment) obj).getActivity(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && obj instanceof Fragment) { + return ((Fragment) obj).getActivity(); + } + return null; + } + + + private Activity getActivityByContext(Context context) { + Activity activity = null; + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + activity = (Activity) context; + break; + } + + context = ((ContextWrapper) context).getBaseContext(); + } + + return activity; + } } diff --git a/gradle.properties b/gradle.properties index e0709cd5..a8a6f223 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,4 +39,4 @@ developerEmail=zhilong.liu@aliyun.com licenseName=The Apache Software License, Version 2.0 licenseUrl=http://www.apache.org/licenses/LICENSE-2.0.txt -allLicenses=["Apache-2.0"] \ No newline at end of file +allLicenses=["Apache-2.0"]