最初のクリック後すぐにボタンを2回押すと、アクティビティが2回読み込まれないようにしようとしています。
ボタンをクリックするとロードするアクティビティがあります
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
//Load another activity
}
});
ロードされるアクティビティにはネットワークコールがあるため、ロードに少し時間がかかります(MVC)。これの読み込みビューを表示しますが、その前にボタンを2回押すと、アクティビティが2回読み込まれていることがわかります。
これを防ぐ方法を知っている人はいますか?
ボタンのイベントリスナーで、ボタンを無効にし、別のアクティビティを表示します。
_ 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);
}
_
これをAndroidManifest.xml
のActivity
定義に追加します...
Android:launchMode = "singleTop"
このようなインテントフラグを使用できます。
Intent intent = new Intent(Class.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
activity.startActivity(intent);
履歴スタックの一番上で1つのアクティビティのみが開かれます。
SOでは他の回答にコメントすることはできないため、このスレッドを新しい回答で汚染する必要があります。
「アクティビティが2回開く」問題に対する一般的な回答と、これらのソリューションに関する私の経験(Android 7.1.1):
編集:これはstartActivity()でアクティビティを開始するためのものでした。 startActivityForResult()を使用する場合、FLAG_ACTIVITY_SINGLE_TOPとFLAG_ACTIVITY_CLEAR_TOPの両方を設定する必要があります。
@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);
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()
}`
問題を間違った方法で解決しようとしていると思います。一般に、アクティビティがその起動ライフサイクルメソッド(onCreate()
、onResume()
など)で長時間実行されるWeb要求を作成するのは悪い考えです。実際、これらのメソッドは、アクティビティで使用するオブジェクトをインスタンス化および初期化するために使用する必要があるため、比較的高速である必要があります。
Webリクエストを実行する必要がある場合は、新しく起動したアクティビティのバックグラウンドスレッドでこれを実行します(新しいアクティビティに読み込みダイアログを表示します)。バックグラウンド要求スレッドが完了すると、アクティビティを更新してダイアログを非表示にできます。
これは、新しいアクティビティがすぐに起動され、ダブルクリックが不可能になることを意味します。
この状況では、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);
}
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つのクラスを追加することです
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 .... />
//イベント時間を追跡する変数
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.
}
}
}
追加:
Android:launchMode="singleTop"
AndroidManifest.xmlのアクティビティタグ内で問題を解決しました。
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;
}
}
イベントでリクエストコードが返されるため、戻るボタンでも押されます。
ボタンのonClickメソッドで1つのフラグを次のように維持するだけです。
public boolean oneTimeLoadActivity = false;
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(!oneTimeLoadActivity){
//start your new activity.
oneTimeLoadActivity = true;
}
}
});