Как предотвратить загрузку активности дважды при нажатии на кнопку - PullRequest
70 голосов
/ 10 ноября 2011

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

У меня есть действие, которое загружается при нажатии кнопки, скажем

 myButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
       //Load another activity
    }
});

Теперь, поскольку загружаемое действие имеет сетевые вызовы, загрузка занимает немного времени (MVC).Я показываю вид загрузки для этого, но если я нажму кнопку дважды до этого, я вижу, что действие загружается дважды.

Кто-нибудь знает, как это предотвратить?

Ответы [ 18 ]

131 голосов
/ 10 ноября 2011

Добавьте это к вашему Activity определению в AndroidManifest.xml ...

android:launchMode = "singleTop"
50 голосов
/ 10 ноября 2011

В прослушивателе событий кнопки отключите кнопку и покажите другое действие.

    Button b = (Button) view;
    b.setEnabled(false);

    Intent i = new Intent(this, AnotherActitivty.class);
    startActivity(i);

Переопределить onResume() для повторного включения кнопки.

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

        Button button1 = (Button) findViewById(R.id.button1);
        button1.setEnabled(true);
    }
33 голосов
/ 20 февраля 2014

Вы можете использовать такие флаги намерений, как этот.

Intent intent = new Intent(Class.class);    
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(intent);

Это сделает только одно действие открытым в верхней части стека истории.

15 голосов
/ 08 июня 2017

Так как SO не позволяет мне комментировать другие ответы, я должен загрязнить эту ветку новым ответом.

Общие ответы на проблему «активность открывается дважды» и мой опыт использования этих решений (Android 7.1.1):

  1. Отключить кнопку, которая запускает упражнение: работает, но чувствует себя немного неуклюже. Если у вас есть несколько способов запустить действие в вашем приложении (например, кнопка на панели действий И, нажав на элемент в виде списка), вы должны отслеживать состояние включения / выключения нескольких элементов GUI. Плюс, например, не очень удобно отключать нажатые элементы в виде списка. Итак, не очень универсальный подход.
  2. launchMode = "singleInstance": не работает с startActivityForResult (), прерывает навигацию с помощью startActivity (), не рекомендуется для обычных приложений в документации манифеста Android.
  3. launchMode = "singleTask": не работает с startActivityForResult (), не рекомендуется для обычных приложений в документации манифеста Android.
  4. FLAG_ACTIVITY_REORDER_TO_FRONT: кнопка возврата назад.
  5. FLAG_ACTIVITY_SINGLE_TOP: Не работает, действие все еще открывается дважды.
  6. FLAG_ACTIVITY_CLEAR_TOP: это единственный, кто работает на меня.

РЕДАКТИРОВАТЬ: Это было для начала деятельности с startActivity (). При использовании startActivityForResult () мне нужно установить FLAG_ACTIVITY_SINGLE_TOP и FLAG_ACTIVITY_CLEAR_TOP.

5 голосов
/ 24 июня 2013

Допустим, @wannik прав, но если у нас более одной кнопки, вызывающей один и тот же слушатель действий, и я нажимаю две кнопки один раз почти одновременно, прежде чем приступить к следующему действию ...

Так что хорошо, если у вас есть поле private boolean mIsClicked = false; и в слушателе:

if(!mIsClicked)
{
    mIsClicked = true;
    Intent i = new Intent(this, AnotherActitivty.class);
    startActivity(i);
}

И onResume() нам нужно вернуть состояние:

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

    mIsClicked = false;
}

В чем разница между ответами моего и @ wannik?

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

В чем разница между моим ответом и другими?

Они думают правильно, но они не думают о будущем возвращении к тому же случаю вызывающей деятельности:)

4 голосов
/ 25 октября 2017

Это работало только для меня, когда startActivity(intent)

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
4 голосов
/ 03 июня 2016

Используйте singleInstance, чтобы избежать активности, чтобы вызвать дважды.

<activity
            android:name=".MainActivity"
            android:label="@string/activity"
            android:launchMode = "singleInstance" />
3 голосов
/ 23 мая 2012

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

 protected static final int DELAY_TIME = 100;

// to prevent double click issue, disable button after click and enable it after 100ms
protected Handler mClickHandler = new Handler() {

    public void handleMessage(Message msg) {

        findViewById(msg.what).setClickable(true);
        super.handleMessage(msg);
    }
};

@Override
public void onClick(View v) {
    int id = v.getId();
    v.setClickable(false);
    mClickHandler.sendEmptyMessageDelayed(id, DELAY_TIME);
    // startActivity()
}`
3 голосов
/ 10 ноября 2011

Я думаю, что вы решаете проблему неправильно. Как правило, плохой идеей является выполнение длительных веб-запросов каким-либо из методов запуска жизненного цикла (onCreate(), onResume() и т. Д.). На самом деле эти методы должны просто использоваться для создания и инициализации объектов, которые будет использовать ваша деятельность, и поэтому должны быть относительно быстрыми.

Если вам нужно выполнить веб-запрос, сделайте это в фоновом потоке из вашего недавно запущенного действия (и покажите диалог загрузки в новом действии). После завершения потока фонового запроса он может обновить действие и скрыть диалоговое окно.

Это означает, что ваше новое действие должно быть запущено немедленно и не допустить двойного щелчка.

2 голосов
/ 09 апреля 2017

В этой ситуации я выберу один из двух подходов, singleTask в manifest.xml ИЛИ флаг в методах действия onResume() & onDestroy() соответственно.

Для первое решение: я предпочитаю использовать singleTask для действия в манифесте, а не singleInstance, как при использовании singleInstance Я выяснил, что в некоторых случаях действие создает для себя новый отдельный экземпляр, в результате чегоиметь два отдельных окна приложений в запущенных приложениях в bcakground и помимо дополнительного выделения памяти, что приведет к очень плохому пользовательскому интерфейсу, когда пользователь откроет представление приложений, чтобы выбрать какое-либо приложение для возобновления.Таким образом, лучший способ - определить активность в файле manifest.xml следующим образом:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"</activity>

вы можете проверить режимы запуска активности здесь .


Для решения second необходимо просто определить статическую переменную или переменную предпочтения, например:

public class MainActivity extends Activity{
    public static boolean isRunning = false;

    @Override
    public void onResume() {
        super.onResume();
        // now the activity is running
        isRunning = true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // now the activity will be available again
        isRunning = false;
    }

}

и с другой стороны, когда вы хотите запустить это действиеПросто проверьте:

private void launchMainActivity(){
    if(MainActivity.isRunning)
        return;
    Intent intent = new Intent(ThisActivity.this, MainActivity.class);
    startActivity(intent);
}
...