web-dev-qa-db-de.com

So verhindern Sie, dass die Aktivität beim Drücken der Taste zweimal geladen wird

Ich versuche zu verhindern, dass die Aktivität zweimal geladen wird, wenn ich die Taste gleich nach dem ersten Klicken zweimal drücke.

Ich habe eine Aktivität, die beim Klicken auf eine Schaltfläche geladen wird

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

Jetzt, da die zu ladende Aktivität Netzwerkaufrufe hat, dauert das Laden etwas (MVC). Ich zeige zwar eine Ladeansicht dafür, aber wenn ich die Taste vorher zweimal drücke, kann ich sehen, dass die Aktivität zweimal geladen wird. 

Weiß jemand, wie man das verhindern kann? 

59
tejas

Deaktivieren Sie im Ereignis-Listener der Schaltfläche die Schaltfläche und zeigen Sie eine andere Aktivität an.

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

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

Überschreiben Sie onResume(), um die Schaltfläche wieder zu aktivieren.

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

        Button button1 = (Button) findViewById(R.id.button1);
        button1.setEnabled(true);
    }
46
wannik

Fügen Sie dies Ihrer Activity-Definition in Androidmanifest.xml... hinzu.

Android:launchMode = "singleTop"
119
Awais Tariq

Sie können die Absichtsflags auf diese Weise verwenden.

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

Es wird nur eine Aktivität oben im Protokollstapel geöffnet.

30
Carlos EduardoL

Da SO mir nicht erlaubt, andere Antworten zu kommentieren, muss ich diesen Thread mit einer neuen Antwort verschmutzen.

Häufige Antworten auf das Problem "Aktivität öffnet sich zweimal" und meine Erfahrungen mit diesen Lösungen (Android 7.1.1):

  1. Deaktivieren Sie die Schaltfläche, mit der die Aktivität gestartet wird: Funktioniert, fühlt sich jedoch etwas unbeholfen an. Wenn Sie die Aktivität auf verschiedene Arten in Ihrer App starten können (z. B. eine Schaltfläche in der Aktionsleiste UND durch Klicken auf ein Element in einer Listenansicht), müssen Sie den aktivierten/deaktivierten Status mehrerer GUI-Elemente nachverfolgen. Außerdem ist es nicht sehr praktisch, geklickte Elemente in einer Listenansicht zu deaktivieren. Also kein sehr universeller Ansatz.
  2. launchMode = "singleInstance": Arbeitet nicht mit startActivityForResult (), bricht die Navigation mit startActivity () ab und wird von Android-Manifestdokumentation nicht für reguläre Anwendungen empfohlen.
  3. launchMode = "singleTask": Funktioniert nicht mit startActivityForResult (), wird von Android-Manifestdokumentation nicht für reguläre Anwendungen empfohlen.
  4. FLAG_ACTIVITY_REORDER_TO_FRONT: bricht die Schaltfläche zurück.
  5. FLAG_ACTIVITY_SINGLE_TOP: Funktioniert nicht, Aktivität ist noch zweimal geöffnet.
  6. FLAG_ACTIVITY_CLEAR_TOP: Dies ist der einzige, der für mich arbeitet.

BEARBEITEN: Dies war für das Starten von Aktivitäten mit startActivity (). Bei der Verwendung von startActivityForResult () muss ich sowohl FLAG_ACTIVITY_SINGLE_TOP als auch FLAG_ACTIVITY_CLEAR_TOP einstellen.

11
Andy Roid

Sagen wir @wannik ist richtig, aber wenn wir mehr als eine Taste haben, rufen wir den gleichen Aktionslistener auf und ich klicke einmal fast zwei Mal auf dieselbe Schaltfläche, bevor ich mit der nächsten Aktivität beginne ...

Es ist also gut, wenn Sie das Feld private boolean mIsClicked = false; und im Listener haben:

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

Und onResume() müssen wir den Zustand zurückgeben:

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

    mIsClicked = false;
}

Was ist der Unterschied zwischen meiner und @ wannik's Antwort?

Wenn Sie für den Listener der aufrufenden Ansicht "Aktiviert" auf "False" setzen, wird die andere Schaltfläche mit demselben Listener weiterhin aktiviert. Um sicherzugehen, dass die Aktion des Listeners nicht zweimal aufgerufen wird, müssen Sie etwas Globales haben, das alle Aufrufe des Listeners deaktiviert (egal, ob es sich um eine neue Instanz handelt oder nicht).

Was ist der Unterschied zwischen meiner Antwort und anderen?

Sie denken in der richtigen Weise, aber sie denken nicht für die zukünftige Rückkehr zu derselben Instanz der aufrufenden Aktivität :)

Verwenden Sie singleInstance, um zu vermeiden, dass Aktivitäten zweimal aufgerufen werden. 

<activity
            Android:name=".MainActivity"
            Android:label="@string/activity"
            Android:launchMode = "singleInstance" />

Hoffe das hilft: 

 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
thanhbinh84

Es funktionierte nur für mich, wenn startActivity(intent)

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
3
Shylendra Madda

Ich denke, Sie wollen das Problem falsch lösen. Im Allgemeinen ist es eine schlechte Idee, dass eine Aktivität in ihrer Startlebenszyklusmethode (onCreate(), onResume() usw.) lang andauernde Webanforderungen stellt. Eigentlich sollten diese Methoden einfach dazu verwendet werden, Objekte zu instanziieren und zu initialisieren, die von Ihrer Aktivität verwendet werden, und sollten daher relativ schnell sein. 

Wenn Sie eine Webanforderung durchführen müssen, führen Sie dies in einem Hintergrundthread Ihrer neu gestarteten Aktivität aus (und zeigen Sie den Ladedialog in der neuen Aktivität an). Sobald der Hintergrundanforderungsthread abgeschlossen ist, kann er die Aktivität aktualisieren und den Dialog ausblenden. 

Dies bedeutet dann, dass Ihre neue Aktivität sofort gestartet werden sollte und der Doppelklick nicht möglich ist. 

3
tomtheguvnor

Für diese Situation wende ich mich an eine der beiden angeführten Variablen singleTask in manifest.xml OR, die jeweils in den onResume() & onDestroy()-Methoden der Aktivität angezeigt werden.

Für die Lösung first: Ich ziehe es vor, singleTask für die Aktivität im Manifest zu verwenden, anstatt singleInstance, wie mit singleInstance ausgeführt. Ich habe herausgefunden, dass die Aktivität in manchen Fällen eine neue separate Instanz für sich selbst erzeugt, die zu einer Zwei führt separates Anwendungsfenster in den laufenden Apps in bcakground und zusätzlich zu zusätzlicher Speicherzuordnung, die zu einer sehr schlechten Benutzererfahrung führen würde, wenn der Benutzer die Apps-Ansicht öffnet, um eine App auszuwählen, die wieder aufgenommen werden soll .. Die beste Möglichkeit besteht darin, die Aktivität zu definieren in der manifest.xml wie folgt:

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

sie können die Startmodi für Aktivitäten überprüfen - hier .


Für die second -Lösung müssen Sie nur eine statische Variable oder eine Präferenzvariable definieren. Beispiel:

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;
    }

}

und von der anderen Seite aus, wenn Sie diese Aktivität starten möchten, überprüfen Sie Folgendes:

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

Andere sehr einfache Lösung, wenn Sie nicht wollen onActivityResult() ist die Taste für 2 Sekunden deaktivieren (oder Zeit, die Sie wollen), ist nicht ideal, aber teilweise lösen kann das Problem in einigen Fällen und der Code ist einfach

   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...
        }
    });
1
Gilian

eine allgemeinere Lösung, die nur einmal für alle Apps angewendet werden soll, ist das Hinzufügen der folgenden zwei Klassen (siehe unten) 

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;
    }

}

wenn Sie also eine Schaltfläche mit einem einzigen Mausklick wünschen, wurde die benutzerdefinierte Ansicht der XML-Datei hinzugefügt (siehe unten)

<yourpackagge.SingleClickButton .... />
0
has19

// Variable zum Verfolgen der Ereigniszeit

private long mLastClickTime = 0;

2.Überprüfen Sie in onClick, ob die aktuelle Zeit und die Zeitdifferenz für den letzten Klick kleiner als 1 Sekunde sind. Tun Sie dann nichts (Rückgabe). Andernfalls wird ein Klickereignis ausgelöst

 @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.
         }
      }
 }
0
44kksharma

Hinzufügen:

Android:launchMode="singleTop"

Im Activity-Tag in AndroidManifest.xml wurde das Problem behoben.

0
Fabio Trotta

Wenn Sie onActivityResult verwenden, können Sie den Status mit einer Variablen speichern.

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;
  }
}

Funktioniert auch bei gedrückter Zurück-Taste, da bei Ereignis der Anforderungscode zurückgegeben wird.

0
Umang

Pflegen Sie einfach ein Flag in button onClick als:

public boolean oneTimeLoadActivity = false;

    myButton.setOnClickListener(new View.OnClickListener() {
          public void onClick(View view) {
               if(!oneTimeLoadActivity){
                    //start your new activity.
                   oneTimeLoadActivity = true;
                    }
        }
    });
0
Balaji Khadake