Próbuję zapobiec dwukrotnemu załadowaniu działania, naciskając przycisk dwa razy natychmiast po pierwszym kliknięciu.
Mam działanie, które ładuje się na przykład po kliknięciu przycisku
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//Load another activity
}
});
Ponieważ ładowana czynność ma wywołania sieciowe, jej załadowanie zajmuje trochę czasu (MVC). W tym celu pokazuję widok ładowania, ale jeśli wcześniej dwukrotnie naciśnę przycisk, mogę zobaczyć, że czynność jest ładowana dwukrotnie.
Czy ktoś wie, jak temu zapobiec?
Odpowiedzi:
W detektorze zdarzeń przycisku wyłącz przycisk i pokaż inną czynność.
Button b = (Button) view; b.setEnabled(false); Intent i = new Intent(this, AnotherActitivty.class); startActivity(i);
Zastąp,
onResume()
aby ponownie włączyć przycisk.@Override protected void onResume() { super.onResume(); Button button1 = (Button) findViewById(R.id.button1); button1.setEnabled(true); }
źródło
Dodaj to do swojej
Activity
definicji wAndroidManifest.xml
...android:launchMode = "singleTop"
Na przykład:
<activity android:name=".MainActivity" android:theme="@style/AppTheme.NoActionBar" android:launchMode = "singleTop"/>
źródło
android:launchMode = "singleTop"
, który osiąga efekt bez przerywania wielozadaniowości Androida. Dokumentacja stwierdza, że większość aplikacji nie powinna używać tejsingleInstance
opcji.Możesz użyć flag intencji w ten sposób.
Intent intent = new Intent(Class.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); activity.startActivity(intent);
Spowoduje to, że tylko jedno działanie będzie otwarte na górze stosu historii.
źródło
android:launchMode = "singleTop"
ten sposób zostanie rozwiązany bez konieczności dodawania flagi do każdej intencji.Ponieważ SO nie pozwala mi komentować innych odpowiedzi, muszę zaśmiecić ten wątek nową odpowiedzią.
Typowe odpowiedzi na problem „aktywność otwiera się dwukrotnie” i moje doświadczenia z tymi rozwiązaniami (Android 7.1.1):
EDYCJA: służyło do rozpoczynania działań za pomocą startActivity (). Używając startActivityForResult (), muszę ustawić zarówno FLAG_ACTIVITY_SINGLE_TOP, jak i FLAG_ACTIVITY_CLEAR_TOP.
źródło
To działało dla mnie tylko wtedy
startActivity(intent)
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
źródło
android:launchMode = "singleInstance"
w pliku manifestu swojego tagu aktywności?Użyj singleInstance, aby uniknąć dwukrotnego wywołania.
<activity android:name=".MainActivity" android:label="@string/activity" android:launchMode = "singleInstance" />
źródło
Powiedzmy, że @wannik ma rację, ale jeśli mamy więcej niż 1 przycisk wywołujący tę samą akcję nasłuchiwania i klikam dwa przyciski raz prawie w tym samym czasie przed rozpoczęciem następnej czynności ...
Więc dobrze, jeśli masz pole
private boolean mIsClicked = false;
i słuchacz:if(!mIsClicked) { mIsClicked = true; Intent i = new Intent(this, AnotherActitivty.class); startActivity(i); }
I
onResume()
musimy zwrócić stan:@Override protected void onResume() { super.onResume(); mIsClicked = false; }
Jaka jest różnica między odpowiedzią my i @ wannik?
Jeśli ustawisz Enabled na false w odbiorniku jego wywołania, inny przycisk używający tego samego odbiornika będzie nadal włączony. Aby mieć pewność, że akcja słuchacza nie jest wywoływana dwukrotnie, musisz mieć coś globalnego, które wyłącza wszystkie wywołania słuchacza (nieważne, czy jest to nowa instancja, czy nie)
Jaka jest różnica między moją odpowiedzią a innymi?
Myślą we właściwy sposób, ale nie myślą o przyszłym powrocie do tej samej instancji czynności wzywającej :)
źródło
synchronized(mIsClicked) {...}
być w 100% bezpiecznym, musisz również użyć .W tej sytuacji skorzystam z jednego z dwóch podejść
singleTask
w pliku manifest.xml LUB flagi wonResume()
&onDestroy()
metod odpowiednio.W przypadku pierwszego rozwiązania: wolę używać
singleTask
do działania w manifeście niżsingleInstance
, zgodnie z użyciem,singleInstance
doszedłem do wniosku, że w niektórych przypadkach aktywność tworzy dla siebie nową oddzielną instancję, co skutkuje posiadaniem dwóch oddzielnych okien aplikacji w uruchomionych aplikacjach w bcakground i poza dodatkowymi alokacjami pamięci, które spowodowałyby bardzo złe wrażenia użytkownika, gdy użytkownik otwiera widok aplikacji, aby wybrać aplikację do wznowienia. Dlatego lepszym sposobem jest zdefiniowanie aktywności w pliku manifest.xml w następujący sposób:<activity android:name=".MainActivity" android:launchMode="singleTask"</activity>
można sprawdzić tryby uruchamiania działalność tutaj .
W przypadku drugiego rozwiązania wystarczy zdefiniować zmienną statyczną lub zmienną preferencji, na przykład:
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; } }
a z drugiej strony, jeśli chcesz uruchomić tę aktywność, po prostu sprawdź:
private void launchMainActivity(){ if(MainActivity.isRunning) return; Intent intent = new Intent(ThisActivity.this, MainActivity.class); startActivity(intent); }
źródło
Myślę, że zamierzasz rozwiązać problem w niewłaściwy sposób. Na ogół jest to zły pomysł na działalność do podejmowania długotrwałych żądań internetowych w żadnej ze swoich metod cyklu życia (startup
onCreate()
,onResume()
itp). Naprawdę, te metody powinny być po prostu używane do tworzenia instancji i inicjalizacji obiektów, których będzie używać twoja aktywność, a zatem powinny być stosunkowo szybkie.Jeśli musisz wykonać żądanie sieciowe, zrób to w wątku w tle z nowo uruchomionej aktywności (i pokaż okno dialogowe ładowania w nowym działaniu). Po zakończeniu wątku żądania w tle może zaktualizować działanie i ukryć okno dialogowe.
Oznacza to, że Twoja nowa aktywność powinna zostać natychmiast uruchomiona i uniemożliwić dwukrotne kliknięcie.
źródło
Mam nadzieję że to pomoże:
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() }`
źródło
Innym bardzo prostym rozwiązaniem, jeśli nie chcesz używać,
onActivityResult()
jest wyłączenie przycisku na 2 sekundy (lub na czas, który chcesz), nie jest idealne, ale może częściowo rozwiązać problem w niektórych przypadkach, a kod jest prosty: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... } });
źródło
// zmienna do śledzenia czasu zdarzenia
private long mLastClickTime = 0;
2. w onClick sprawdź, czy jeśli aktualny czas i różnica czasu ostatniego kliknięcia są mniejsze niż jedna sekunda, nie rób nic (zwróć), w przeciwnym razie przejdź do zdarzenia kliknięcia
@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. } } }
źródło
Po prostu zachowaj jedną flagę w metodzie onClick jako:
public boolean oneTimeLoadActivity = false;
myButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(!oneTimeLoadActivity){ //start your new activity. oneTimeLoadActivity = true; } } });
źródło
dodaj Tryb uruchamiania jako pojedyncze zadanie w manifeście, aby uniknąć dwukrotnego otwarcia działania po kliknięciu
<activity android:name=".MainActivity" android:label="@string/activity" android:launchMode = "singleTask" />
źródło
Jeśli używasz onActivityResult, możesz użyć zmiennej, aby zapisać stan.
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; } }
Działa również po naciśnięciu przycisku Wstecz, ponieważ kod żądania jest zwracany przy zdarzeniu.
źródło
myButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { myButton.setOnClickListener(null); } });
źródło
Użyj
flag
zmiennej ustaw jąto true
, sprawdź, czy jest prawdziwa, po prostureturn
wykonaj wywołanie aktywności.Możesz również użyć setClickable (false) one wykonując wywołanie działania
flg=false public void onClick(View view) { if(flg==true) return; else { flg=true; // perform click} }
źródło
perform click; wait; flg = false;
kiedy wrócimyMożesz po prostu nadpisać startActivityForResult i użyć zmiennej instancji:
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); } }
źródło
Możesz też spróbować tego
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); } });
źródło