Как предотвратить активность при загрузке дважды при нажатии кнопки
Я пытаюсь предотвратить загрузку активности дважды, если дважды нажать кнопку сразу после первого щелчка.
У меня есть активность, которая загружается по нажатию кнопки, скажем
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//Load another activity
}
});
Теперь, поскольку загружаемое действие имеет сетевые вызовы, загрузка занимает немного времени (MVC). Я показываю вид загрузки для этого, но если я дважды нажму кнопку до этого, я вижу, что действие загружается дважды.
Кто-нибудь знает, как это предотвратить?
Ответы
Ответ 1
В прослушивателе событий кнопки отключите кнопку и покажите другую активность.
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);
}
Ответ 2
Добавьте это к определению Activity
в AndroidManifest.xml
...
android:launchMode = "singleTop"
Например:
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme.NoActionBar"
android:launchMode = "singleTop"/>
Ответ 3
Вы можете использовать флаги намерения как это.
Intent intent = new Intent(Class.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(intent);
В верхней части стека истории будет открыто только одно действие.
Ответ 4
Так как SO не позволяет мне комментировать другие ответы, я должен загрязнить этот поток новым ответом.
Общие ответы на проблему "активность открывается дважды" и мой опыт с этими решениями (Android 7.1.1):
- Кнопка отключения, которая запускает действие: Работает, но чувствует себя немного неуклюжей. Если у вас есть несколько способов начать работу в вашем приложении (например, кнопку на панели действий И, щелкнув элемент в представлении списка), вы должны отслеживать состояние включения/отключения нескольких элементов GUI. Кроме того, не очень удобно отключать нажатые элементы в виде списка, например. Таким образом, это не очень универсальный подход.
- launchMode = "singleInstance": не работает с startActivityForResult(), отключает навигацию с помощью startActivity(), не рекомендуется для обычных приложений в документации к манифесту Android.
- launchMode = "singleTask": не работает с startActivityForResult(), не рекомендуется для обычных приложений в документации к манифесту Android.
- FLAG_ACTIVITY_REORDER_TO_FRONT: кнопка "Отключает".
- FLAG_ACTIVITY_SINGLE_TOP: не работает, активность все еще открывается дважды.
- FLAG_ACTIVITY_CLEAR_TOP: Это единственная работающая для меня.
EDIT: Это было для начала работы с startActivity(). При использовании startActivityForResult() мне нужно установить FLAG_ACTIVITY_SINGLE_TOP и FLAG_ACTIVITY_CLEAR_TOP.
Ответ 5
Скажем, @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?
Если вы установили enabled в false в прослушивателе, вызывающий вызов другой кнопки, используя тот же прослушиватель, все равно будет включен. Поэтому, чтобы убедиться, что действие прослушивателя не вызывается дважды, вам нужно иметь что-то глобальное, которое отключает все вызовы слушателя (неважно, если это новый экземпляр или нет)
В чем разница между моим ответом и другими?
Они думают правильно, но они не думают о будущем возвращении к тому же экземпляру вызывающей активности:)
Ответ 6
Используйте singleInstance, чтобы избежать активизации активности дважды.
<activity
android:name=".MainActivity"
android:label="@string/activity"
android:launchMode = "singleInstance" />
Ответ 7
Это работало только для меня, когда startActivity(intent)
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Ответ 8
Я думаю, вы собираетесь решить проблему неправильно. Как правило, плохой идеей для деятельности является создание длительных веб-запросов в любом из его методов жизненного цикла запуска (onCreate()
, onResume()
и т.д.). На самом деле эти методы должны просто использоваться для создания и инициализации объектов, которые ваша деятельность будет использовать, и поэтому должны быть относительно быстрыми.
Если вам нужно выполнить веб-запрос, сделайте это в фоновом потоке из недавно запущенного действия (и покажите диалог загрузки в новом действии). Как только поток фонового запроса завершается, он может обновить действие и скрыть диалог.
Это означает, что ваша новая активность должна немедленно запускаться и предотвратить двойной щелчок.
Ответ 9
Надеюсь, что это поможет:
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()
}`
Ответ 10
Другое очень простое решение, если вы не хотите использовать onActivityResult()
, отключает кнопку в течение 2 секунд (или время, которое вы хотите), не является идеальным, но может частично решить проблему - это некоторые случаи, и код прост:
final Button btn = ...
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//start activity here...
btn.setEnabled(false); //disable button
//post a message to run in UI Thread after a delay in milliseconds
btn.postDelayed(new Runnable() {
public void run() {
btn.setEnabled(true); //enable button again
}
},1000); //1 second in this case...
}
});
Ответ 11
В этой ситуации я перейду к одному из двух подходов, singleTask
в manifest.xml ИЛИ в методах Activity onResume()
и onDestroy()
соответственно.
Для решения first: я предпочитаю использовать 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);
}
Ответ 12
Просто поддерживайте один флаг в методе onClick в качестве:
public boolean oneTimeLoadActivity = false;
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(!oneTimeLoadActivity){
//start your new activity.
oneTimeLoadActivity = true;
}
}
});
Ответ 13
Если вы используете onActivityResult, вы можете использовать переменную для сохранения состояния.
private Boolean activityOpenInProgress = false;
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if( activityOpenInProgress )
return;
activityOpenInProgress = true;
//Load another activity with startActivityForResult with required request code
}
});
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if( requestCode == thatYouSentToOpenActivity ){
activityOpenInProgress = false;
}
}
Нажимается кнопка "Назад", так как код запроса возвращается на событие.
Ответ 14
Добавление:
android:launchMode="singleTop"
Внутри тега активности в AndroidManifest.xml проблема решена.
Ответ 15
более общее решение, которое будет применено только один раз для всех приложений, состоит в добавлении следующих двух классов, как показано ниже
public class SingleClickButton extends AppCompatButton {
public SingleClickButton(Context context) {
super(context);
}
public SingleClickButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SingleClickButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setOnClickListener(@Nullable OnClickListener l) {
if(l!=null){
super.setOnClickListener(new DebouncedClickListener() {
@Override
public void onClicked(View v) {
l.onClick(v);
}
});
}else{
super.setOnClickListener(l);
}
}
}
public abstract class DebouncedClickListener implements View.OnClickListener {
private static final long MAX_TIME_INTERVAL = 750L;
private long lastClickedTime;
public abstract void onClicked(View v);
@Override public void onClick(View v) {
Logger.d("Click Test trying to click");
long now = SystemClock.elapsedRealtime();
long diff = now - lastClickedTime;
if (diff > MAX_TIME_INTERVAL) {
Logger.d("Click Test allowed to click");
onClicked(v);
}else{
Logger.d("Click Test not allowed to click time ");
}
lastClickedTime = now;
}
}
поэтому всякий раз, когда вы хотите кнопку одним щелчком мыши, просто добавьте пользовательский вид в XML, как показано ниже
<yourpackagge.SingleClickButton .... />
Ответ 16
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
myButton.setOnClickListener(null);
}
});
Ответ 17
Используйте переменную flag
, установите ее to true
,
Проверьте, действительно ли его true return
выполняет Activity Call.
Вы также можете использовать setClickable (false), выполняющий вызов Activity
flg=false
public void onClick(View view) {
if(flg==true)
return;
else
{ flg=true;
// perform click}
}
Ответ 18
Вы можете просто переопределить startActivityForResult и использовать переменную экземпляра:
boolean couldStartActivity = false;
@Override
protected void onResume() {
super.onResume();
couldStartActivity = true;
}
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
if (couldStartActivity) {
couldStartActivity = false;
intent.putExtra(RequestCodeKey, requestCode);
super.startActivityForResult(intent, requestCode, options);
}
}
Ответ 19
//переменная для отслеживания времени события
private long mLastClickTime = 0;
2. В onClick проверьте, что если текущее время и разница во времени последнего клика меньше, чем я секунда, то не предпринимайте никаких действий (возврат), иначе перейдите к событию клика.
@Override
public void onClick(View v) {
// Preventing multiple clicks, using threshold of 1 second
if (SystemClock.elapsedRealtime() - mLastClickTime < 1000) {
return;
}
mLastClickTime = SystemClock.elapsedRealtime();
// Handle button clicks
if (v == R.id.imageView2) {
// Do ur stuff.
}
else if (v == R.id.imageView2) {
// Do ur stuff.
}
}
}
Ответ 20
Вы также можете попробовать это.
Button game = (Button) findViewById(R.id.games);
game.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view)
{
Intent myIntent = new Intent(view.getContext(), Games.class);
startActivityForResult(myIntent, 0);
}
});