Очистка намерения - PullRequest
       21

Очистка намерения

91 голосов
/ 07 ноября 2010

Мое Android-приложение вызывается из-за намерения, передающего информацию (ожидающего в строке состояния).

Когда я нажимаю кнопку «Домой» и снова открываю свое приложение, удерживая кнопку «Домой», оно снова вызывает намерениетакие же дополнения все еще есть.

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      super.onSaveInstanceState(savedInstanceState);
    }
    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
      super.onRestoreInstanceState(savedInstanceState);
    }

это код, который не запускается так, как предполагается

    String imgUrl;
    Bundle extras = this.getIntent().getExtras();


    if(extras != null){
        imgUrl = extras.getString("imgUrl");
        if( !imgUrl.equals(textView01.getText().toString()) ){

            imageView.setImageDrawable( getImageFromUrl( imgUrl ) );
            layout1.setVisibility(0);
            textView01.setText(imgUrl);//textview to hold the url

        }

    }

И мое намерение:

public void showNotification(String ticker, String title, String message, 
    String imgUrl){
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager mNotificationManager = 
        (NotificationManager) getSystemService(ns);
    int icon = R.drawable.icon;        // icon from resources
    long when = System.currentTimeMillis();         // notification time
    CharSequence tickerText = ticker;              // ticker-text

    //make intent
    Intent notificationIntent = new Intent(this, activity.class);
    notificationIntent.putExtra("imgUrl", imgUrl);
    notificationIntent.setFlags(
        PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);
    PendingIntent contentIntent = 
        PendingIntent.getActivity(this, 0, 
        notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT | 
        PendingIntent.FLAG_ONE_SHOT);

    //make notification
    Notification notification = new Notification(icon, tickerText, when);
    notification.setLatestEventInfo(this, title, message, contentIntent);
    //flags
    notification.flags = Notification.FLAG_SHOW_LIGHTS | 
        Notification.FLAG_ONGOING_EVENT | 
        Notification.FLAG_ONLY_ALERT_ONCE | 
        Notification.FLAG_AUTO_CANCEL;
    //sounds
    notification.defaults |= Notification.DEFAULT_SOUND;
    //notify
    mNotificationManager.notify(1, notification);
}

Есть ли способ очистить намерение или проверить, использовалось ли оно ранее?

Ответы [ 19 ]

155 голосов
/ 11 ноября 2011

UPDATE:

Я не знал, что этот ответ будет так часто упоминаться, когда я впервые написал его более 5 лет назад!

Я поясню, что, согласно ответу @ tato-rodrigo, это не поможет вам обнаружить уже обработанное намерение в некоторых ситуациях.

Также я должен отметить, что я поставил «очистить» в кавычках по причине - вы не действительно очищаете намерение, делая это, вы просто используете удаление лишнего как флаг, который это намерение уже было замечено действием.


У меня была точно такая же проблема.

Выше ответ поставил меня на правильный путь, и я нашел еще более простое решение, используйте:

getIntent().removeExtra("key"); 

вызов метода для «очистки» намерения.

Немного поздно отвечать, так как об этом спрашивали год назад, но, надеюсь, это поможет другим в будущем.

37 голосов
/ 27 августа 2014

РЕДАКТИРОВАТЬ: Я редактирую, чтобы опубликовать полное решение, которое я использую.

Это решение будет работать, если проблема "Не выполнять некоторый код при выполнении действияначинается с истории (Недавние приложения) ".

Прежде всего, объявите boolean в вашем Activity, чтобы указать, был ли Intent уже использован:

    private boolean consumedIntent;

Затем безопасно сохраните и восстановите это значение, используя методы onSaveInstanceState и onCreate для обработки изменений конфигурации и случаев, когда система может убить ваш Activity при переходе в фоновый режим.

    private final String SAVED_INSTANCE_STATE_CONSUMED_INTENT = "SAVED_INSTANCE_STATE_CONSUMED_INTENT";

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT, consumedIntent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set content view ...

        if( savedInstanceState != null ) {
            consumedIntent = savedInstanceState.getBoolean(SAVED_INSTANCE_STATE_CONSUMED_INTENT);
        }

        //other initializations
    }

Теперь проверьте, можете ли вы запустить свой код по методу onResume.

    @Override
    protected void onResume() {
        super.onResume();

        //check if this intent should run your code
        //for example, check the Intent action
        boolean shouldThisIntentTriggerMyCode = [...];
        Intent intent = getIntent();
        boolean launchedFromHistory = intent != null ? (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 : false;
        if( !launchedFromHistory && shouldThisIntentTriggerMyCode && !consumedIntent ) {
            consumedIntent = true;
            //execute the code that should be executed if the activity was not launched from history
        }
    }

Кроме того, если ваш Activity настроен на singleTop, вы должны сбросить свой флаг, когда новый Intentдоставлено.

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        consumedIntent = false;
    }
19 голосов
/ 12 февраля 2013

Maks answer работает для очистки лишнего:

    getIntent().removeExtra("key"); 

Другая полезная команда:

    getIntent().setAction("");

Вы также можете пометить намерение, вызвав:

    getIntent().putExtra("used", true);

, а затем просто проверьте значение.

12 голосов
/ 29 декабря 2016

Когда мы запускаем Android-приложения из History (Недавние приложения), приложение может запускаться в основном с тремя различными флагами Intent.

  1. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
    Это когда активность запускается изистория приложения, которое было свернуто (долгое нажатие на клавишу возврата домой).
    Постоянное значение: 1048576 (0x00100000)
  2. FLAG_ACTIVITY_NEW_TASK
    Это когда действие запускается через "щелкнув значок приложения "или через" Фильтры намерений".Здесь действие станет началом новой задачи в этом стеке истории.
    Постоянное значение: 268435456 (0x10000000)
  3. FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | FLAG_ACTIVITY_NEW_TASK
    Это когда приложение было закрытопутем нажатия кнопки «Назад» и затем возобновления из «Журнала» (последние приложения).
    Постоянное значение: 269484032 (0x10100000)

Постоянное значение можно получить с помощью getIntent().getFlags()

В третьем случае Android перезагружает последние значения Intent из своей памяти.Таким образом, у намерения вашего приложения (getIntent) будут значения из последнего намерения, которое запустило приложение.

На самом деле, приложение должно вести себя так, как будто это новый запуск, со значениями намерений для нового запуска, а незначения намерений предыдущего запуска. Такое поведение можно увидеть, если вы запустите приложение, щелкнув значок приложения, оно никогда не будет иметь старых значений намерений.Это связано с тем, что Android использует следующий фильтр намерений для этого сценария

 <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER"/>
 </intent-filter>

Но в третьем случае (приложение, которое было закрыто, запускается из Истории последних приложений), ОС Android использует это последнеенамерение, которое запустило приложение до того, как оно было закрыто (нажатием кнопки назад).Таким образом, в конечном итоге вы получаете старые значения намерений, а поток приложения не является правильным.

Удаление намерения - это один из способов его решения, но это не решит проблему полностью!Поскольку ОС Android перезагружает Намерение из последнего запуска приложений, а не последний экземпляр намерения запуска.

Чистый способ избежать этого - обработать его путем получения типа Намерение для определения типа запуска.

Таким образом, в вашей LaunchActivity (той, в которой фильтр намерений определен в манифесте) вы можете использовать следующий код в onCreate(), onStart() или onResume() методов.

if(getIntent().getFlags() == (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)) {
    //app is launched from recent apps after it was closed
        normalLaunch();
    } else {
        String intentAction = getIntent().getAction();
        String scheme = getIntent().getScheme();
        //app is launched via other means
        // URL intent scheme, Intent action etc
        if("https".equalsIgnoreCase(scheme)) {
            // URL intent for browser
        } else if("com.example.bb".equalsIgnoreCase(intentAction)) {
            // App launched via package name
        } else {
            // App was launched via Click on App Icon, or other means
            normalLaunch();
        }
    }

Полагаю, normalLaunch(), не следует использовать параметры из намерения;в противном случае вам потребуется разделить и оптимизировать метод запуска по умолчанию, чтобы не использовать параметры Intent.

11 голосов
/ 29 апреля 2015

Очистка намерения объект :

intent.replaceExtras(new Bundle());
intent.setAction("");
intent.setData(null);
intent.setFlags(0);
7 голосов
/ 25 января 2014

Краткий ответ Ни в коем случае

Длинный ответ.Нет такого понятия, как намерение «одним выстрелом».Из эксперимента видно, что недавняя история активности в современных Android - это не что иное, как «История намерений».Последнее намерение, переданное действию, просто регистрируется в системе, и в этом дело.Люди выше предлагают использовать

setAction("")

Но это не работает, потому что намерение уже зарегистрировано до момента, когда вы получите его внутри метода onNewIntent () или onStart ().

Я решил проблему, избегая использования намерений.Моя проблема была похожа на ту, которую опубликовал автор.Я пытался реализовать Глобальный выход из приложения через контроль в области уведомлений.Это должно остановить основной сервис и закрыть все действия приложения.Вы можете найти то же поведение в приложении Waze.

Алгоритм:

  1. Создать PendingIntent для элемента управления уведомлением, который передает действие «Выход» в действие.Но к особой деятельности, которая является простым прокси.
  2. Код прокси-активности onStart () анализирует намерение, проверяет действие и устанавливает состояние какой-либо модели в «Выход».
  3. Код прокси-активности onStart () очищает исходное намерение с помощью setIntent (""), а затем перенаправляет его в целевое действие "Root", вызывая startActivity (intent).
  4. Код прокси-активности onStart ()вызовите finish ().
  5. Внутри onStart () и onNewIntent () целевого действия проверьте состояние модели и вызовите finish (), если она «завершена» (а также вызовите stopService () в моем случае).

Надеюсь, это кому-нибудь поможет, потому что я не нашел ответа в интернете.

4 голосов
/ 31 декабря 2015

Убедитесь, что вы используете PendingIntent.FLAG_UPDATE_CURRENT флаг для PendingIntent .

PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, mPutIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Где mPutIntent - ваш Intent.

Надеюсь, это поможет вам.

1 голос
/ 09 февраля 2011

У меня точно такая же проблема.Мое решение состояло в том, чтобы добавить boolean переменную, которая была установлена, когда Intent был «использован», и оператор if на основе этого boolean, чтобы проверить, следует ли вам использовать Intent или нет.

1 голос
/ 23 сентября 2016

У меня недавно была эта проблема, и я решил ее, добавив отметку времени в качестве дополнительного параметра в намерение:

private void launchActivity(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra("KEY_EXTRA_TIMESTAMP", System.currentTimeMillis());
    context.startActivity(intent);
}

После этого сохраните отметку времени в общих настройках:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    long time = getIntent().getLongExtra("KEY_EXTRA_TIMESTAMP", -1);
    long previousTime = getPreferences(MODE_PRIVATE).getLong("timestamp", -1);

    //ignore if the timestamp is the same as the previous one  
    if (time != previousTime) {
        handleIntent(getIntent());
        if (time != -1) {
            //save the timestamp
            getPreferences(MODE_PRIVATE).edit().putLong("timestamp", time).apply();
        }
    }
}
1 голос
/ 28 июля 2017

Я не смог найти способ удалить Intent Extra .Ни один из ответов о удалении лишних из намерения не работает, если вы включили «Не сохранять действия » в параметрах разработчика (таким образом вы можете уничтожить действие и вернуться к проверке, если дополнительные функции все еще остаютсятам).

В качестве решения проблемы я сохранил логическое значение в SharedPreferences после обработки Intent Extras.Когда тот же Intent доставлен в Activity, я проверяю значение SharedPreference и решаю обработать Intent Extra.Если вы отправляете еще одно новое Intent Extra для того же Activity, вы устанавливаете значение SharedPreference в false и Activity будет обрабатывать его. Пример :

// Start Activity with Intent Extras
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra("someData", "my Data");
// Set data as not processed
context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", false).commit();
context.startActivity(intent);

...

public class MyActivity{

    ...
    public void someMethod(){
        boolean isExtrasProcessed = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).getBoolean("myActivityExtraProccessed", false);  
         if (!isExtrasProcessed) {
              // Use Extras

              //Set data as processed
              context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE).edit().putBoolean("myActivityExtraProccessed", true).commit();
         }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...