#android #android-activity #notifications #android-notifications
#Android #android-активность #уведомления #android-уведомления
Вопрос:
В моем приложении у меня есть HomeActivity
приложение, которое запускает другие действия, давайте вызовем его SecondActivity
. Всякий раз, когда пользователь выбирает уведомление, я запускаю CommentsActivity
.
Всякий раз, когда приходит уведомление, и пользователь нажимает на баннер или нажимает на него в центре уведомлений, HomeActivity
onNewIntent
вызывается метод my, который запускает my . CommentsActivity
Это нормально, за исключением того, что я не могу сохранить задний стек таким, каким он был до того, как пользователь нажал на уведомление, что означает, что если пользователь
HomeActivity -> SecondActivity -> Taps Notification -> | Backstack is cleared and only HomeActivity remains -> CommentsActivity.
Поэтому, когда пользователь нажимает кнопку «Назад», они возвращаются домой.
Есть ли способ сделать так, чтобы мои SecondActivity
onNewIntent
вызывались, когда пользователь открывает уведомление, и они уже включены SecondActivity
, вместо того, чтобы открывать задний стек? Поток пользователей, который я хочу, следующий:
HomeActivity -> SecondActivity -> Taps Notification -> CommentsActivity (and backwards if the user presses the back button.
Имейте в виду, что я использую android:launchMode="singleTask"
in my AndroidManifest
для my HomeActivity
, поэтому я не получаю несколько HomeActivity
экземпляров при прослушивании уведомления.
Комментарии:
1. Небольшая хитрость, которая может помочь. Когда пользователь нажимает на уведомление, отправьте новое намерение SecondActivity и с этим намерением поместите некоторую строку. Во втором методе activity oncreate проверьте строку, и если это правда, просто запустите новое намерение прокомментировать действие из второго действия.
2. Я думал об этом взломе, но когда я говорю SecondActivity, у меня может быть еще 5 действий в заднем стеке, когда пользователь открывает уведомление, и все это нужно будет воссоздать (вместе с их позициями в RecyclerViews и data, что кажется не очень выполнимым), поэтому я былподумайте, есть ли способ заставить Android не открывать HomeActivity при каждом нажатии notificaiton и позволить текущей запущенной активности обрабатывать намерение.
Ответ №1:
Решение
Вы можете использовать действие, которое действует как маршрутизатор активности. Когда пользователи запускают приложение (щелкните значок приложения на главном экране или нажмите на уведомление), они откроют это действие маршрутизатора, отсюда оно примет решение:
- Если пользователи впервые открывают приложение (
HomeActivity
оно не существует в заднем стеке), запуститеHomeActivity
- В противном случае перенаправьте намерение на onNewIntent (намерение) текущего выполняемого действия (действие в верхней части стека)
Реализация
Шаг 1. Создайте класс с именем MyApp
, который простирается от класса Application. Его цель — прослушивать весь жизненный цикл приложения.
public class MyApp extends Application {
public static final String EXTRA_ORIGINAL_INTENT = "EXTRA_ORIGINAL_INTENT";
private final ActivityLifecycleCallbacksImpl callbacks = new ActivityLifecycleCallbacksImpl();
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(callbacks);
}
public boolean isHomeActivityStarted() {
return callbacks.isHomeActivityStarted();
}
public void routeIntentToCurrentRunningActivity(Intent original) {
Activity activity = callbacks.getCurrentRunningActivity();
Intent intent = new Intent(this, activity.getClass());
intent.putExtra(EXTRA_ORIGINAL_INTENT, original);
// Call onNewIntent() method of the activity at top of the stack.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
private static final class ActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
public static final int INVALID_TASK_ID = -1;
int homeActivityTaskId = INVALID_TASK_ID;
Activity currentRunningActivity = null;
@Override
public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
}
@Override
public void onActivityStarted(@NonNull Activity activity) {
}
@Override
public void onActivityResumed(@NonNull Activity activity) {
if (activity instanceof RouterActivity) {
return;
}
currentRunningActivity = activity;
if (activity instanceof HomeActivity) {
homeActivityTaskId = activity.getTaskId();
}
}
@Override
public void onActivityPaused(@NonNull Activity activity) {
}
@Override
public void onActivityStopped(@NonNull Activity activity) {
}
@Override
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
}
@Override
public void onActivityDestroyed(@NonNull Activity activity) {
if (activity instanceof RouterActivity) {
return;
}
if (activity instanceof HomeActivity) {
homeActivityTaskId = INVALID_TASK_ID;
}
}
boolean isHomeActivityStarted() {
return homeActivityTaskId != INVALID_TASK_ID;
}
@NonNull
Activity getCurrentRunningActivity() {
return currentRunningActivity;
}
}
}
Не забудьте добавить этот класс в файл манифеста.
Шаг 2. Создайте действие маршрутизатора с именем RouterActivity
public class RouterActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyApp myApp = (MyApp) getApplication();
if (!myApp.isHomeActivityStarted()) {
Intent intent = new Intent(this, HomeActivity.class);
intent.putExtras(getIntent());
startActivity(intent);
} else {
myApp.routeIntentToCurrentRunningActivity(getIntent());
}
finish();
overridePendingTransition(0, 0);
}
}
Шаг 3. Добавьте оба класса в файл манифеста
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.kotlinapp">
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".RouterActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HomeActivity"
android:launchMode="singleTask" />
<activity android:name=".SecondActivity" />
<activity android:name=".CommentsActivity" />
</application>
</manifest>