web-dev-qa-db-ja.com

ボタンを押したときにアクティビティが2回読み込まれないようにする方法

最初のクリック後すぐにボタンを2回押すと、アクティビティが2回読み込まれないようにしようとしています。

ボタンをクリックするとロードするアクティビティがあります

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

ロードされるアクティビティにはネットワークコールがあるため、ロードに少し時間がかかります(MVC)。これの読み込みビューを表示しますが、その前にボタンを2回押すと、アクティビティが2回読み込まれていることがわかります。

これを防ぐ方法を知っている人はいますか?

75
tejas

ボタンのイベントリスナーで、ボタンを無効にし、別のアクティビティを表示します。

_    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);
    }
_
51
wannik

これをAndroidManifest.xmlActivity定義に追加します...

Android:launchMode = "singleTop"
133
Awais Tariq

このようなインテントフラグを使用できます。

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

履歴スタックの一番上で1つのアクティビティのみが開かれます。

33
Carlos EduardoL

SOでは他の回答にコメントすることはできないため、このスレッドを新しい回答で汚染する必要があります。

「アクティビティが2回開く」問題に対する一般的な回答と、これらのソリューションに関する私の経験(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:動作していません。アクティビティはまだ2回開かれています。
  6. FLAG_ACTIVITY_CLEAR_TOP:これは私のために働いている唯一のものです。

編集:これはstartActivity()でアクティビティを開始するためのものでした。 startActivityForResult()を使用する場合、FLAG_ACTIVITY_SINGLE_TOPとFLAG_ACTIVITY_CLEAR_TOPの両方を設定する必要があります。

15
Andy Roid

@wannikが正しいとしましょうが、同じアクションリスナーを呼び出す複数のボタンがあり、次のアクティビティを開始する前にほぼ同じ時間に2つのボタンをクリックした場合...

したがって、フィールド_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に設定すると、同じリスナーを使用する他のボタンが引き続き有効になります。したがって、リスナーのアクションが2回呼び出されないようにするには、リスナーのすべての呼び出しを無効にするグローバルなものが必要です(新しいインスタンスであるかどうかは気にしないでください)

私の回答と他の回答の違いは何ですか?

彼らは正しい方法で考えていますが、呼び出し活動の同じインスタンスへの将来の戻りを考えていません:)

startActivity(intent)の場合にのみ機能していました

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

SingleInstanceを使用して、アクティビティが2回呼び出されるのを避けます。

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

お役に立てれば:

 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

問題を間違った方法で解決しようとしていると思います。一般に、アクティビティがその起動ライフサイクルメソッド(onCreate()onResume()など)で長時間実行されるWeb要求を作成するのは悪い考えです。実際、これらのメソッドは、アクティビティで使用するオブジェクトをインスタンス化および初期化するために使用する必要があるため、比較的高速である必要があります。

Webリクエストを実行する必要がある場合は、新しく起動したアクティビティのバックグラウンドスレッドでこれを実行します(新しいアクティビティに読み込みダイアログを表示します)。バックグラウンド要求スレッドが完了すると、アクティビティを更新してダイアログを非表示にできます。

これは、新しいアクティビティがすぐに起動され、ダブルクリックが不可能になることを意味します。

3
tomtheguvnor

この状況では、manifest.xmlのsingleTask ORアクティビティのonResume()onDestroy()メソッド。

first解決策:singleTaskよりも、マニフェストのアクティビティにsingleInstanceを使用することを好みます。 singleInstanceを使用して、場合によっては、アクティビティがbcakgroundで実行中のアプリに2つの別々のアプリケーションウィンドウを作成し、さらに非常に悪いユーザーをもたらす余分なメモリ割り当てを行う新しいインスタンスを作成することがわかりました。ユーザーがアプリビューを開いて、再開するアプリを選択したときのエクスペリエンス。したがって、より良い方法は、次のように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);
}
2
Muhammed Refaat

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

すべてのアプリに一度だけ適用されるより一般的なソリューションは、以下に示すように次の2つのクラスを追加することです

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 .... />
0
has19

//イベント時間を追跡する変数

private long mLastClickTime = 0;

2. onClickで、現在の時刻と最後のクリックの時刻の差がi秒未満の場合、何もしない(リターン)か、クリックイベントに進むことを確認します。

 @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

追加:

Android:launchMode="singleTop"

AndroidManifest.xmlのアクティビティタグ内で問題を解決しました。

0
Fabio Trotta

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

イベントでリクエストコードが返されるため、戻るボタンでも押されます。

0
Umang

ボタンのonClickメソッドで1つのフラグを次のように維持するだけです。

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