如何在按下button时防止活动加载两次
我想弄清楚的是,如果我按下button两次,防止活动加载两次。
我有一个点击button加载的活动,说
myButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { //Load another activity } });
现在,因为要加载的活动与web服务和其他操作有关,所以加载需要一些时间。 当然,我有一个加载视图。 但在此之前,如果我按下button两次,我可以看到两次加载的活动。
有谁知道如何防止这个?
在button的事件监听器中,禁用button并显示另一个活动。
Button b = (Button) view; b.setEnabled(false); Intent i = new Intent(this, AnotherActitivty.class); startActivity(i);
覆盖onResume()
重新启用button。
@Override protected void onResume() { super.onResume(); Button button1 = (Button) findViewById(R.id.button1); button1.setEnabled(true); }
将其添加到Androidmanifest.xml
的Activity
定义中
android:launchMode = "singleInstance"
你可以像这样使用意向标志。
Intent intent = new Intent(Class.class); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); activity.startActivity(intent);
在历史堆栈的顶部只能打开一个活动。
假设@wannik是正确的,但如果我们有超过1个button调用相同的动作监听器,我几乎在同一时间点击两个button开始下一个活动之前…
所以这是好的,如果你有场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,则仍将启用使用相同侦听器的其他button。 所以为了确保监听者的动作不被调用两次,你需要有一个全局的东西来禁用所有的监听者的调用(如果是新实例或者不是,
我的答案和其他答案有什么不同?
他们正在思考正确的方式,但他们没有考虑将来返回到调用活动的同一个实例:)
希望这可以帮助:
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请求,请在新启动的活动的后台线程中执行此操作(并在新活动中显示加载对话框)。 一旦后台请求线程完成,它可以更新活动并隐藏对话框。
这意味着您的新活动应立即启动并防止双击。
使用singleInstance来避免活动调用两次。
<activity android:name=".MainActivity" android:label="@string/activity" android:launchMode = "singleInstance" />
其他非常非常简单的解决scheme,如果你不想使用onActivityResult()
是禁用button2秒(或你想要的时间),是不是很理想,但可以部分解决问题是一些情况下,代码很简单:
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... } });
既然SO不允许我评论其他答案,我必须用一个新的答案来污染这个线程。
“活动打开两次”问题和我对这些解决scheme的经验(Android 7.1.1)的常见答案:
- 禁用button,启动活动:工作,但感觉有点笨拙。 如果您有多种方式来启动应用程序中的活动(例如,在操作栏中的button以及通过单击列表视图中的项目),则必须跟踪多个GUI元素的启用/禁用状态。 另外,例如,禁用列表视图中的单击项目并不是很方便。 所以,不是一个非常普遍的方法。
- launchMode =“singleInstance”:不使用startActivityForResult(),使用startActivity()取消导航,不build议Android清单文档的常规应用程序。
- launchMode =“singleTask”:不适用于startActivityForResult(),不build议Android清单文档的常规应用程序。
- FLAG_ACTIVITY_REORDER_TO_FRONT:中断返回button。
- FLAG_ACTIVITY_SINGLE_TOP:不工作,活动仍然打开两次。
- FLAG_ACTIVITY_CLEAR_TOP:这是唯一为我工作的人。
编辑:这是用startActivity()开始的活动。 当使用startActivityForResult()我需要设置FLAG_ACTIVITY_SINGLE_TOP和FLAG_ACTIVITY_CLEAR_TOP。
只需在buttononClick方法中维护一个标志为:
public boolean oneTimeLoadActivity = false;
myButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { if(!oneTimeLoadActivity){ //start your new activity. oneTimeLoadActivity = true; } } });
如果你使用onActivityResult,你可以使用一个variables来保存状态。
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; } }
在后退button上工作也是因为请求代码在事件上返回。
对于这种情况,我将singleTask
在manifest.xml或者Activity的onResume()
和onDestroy()
方法中使用两个接近的singleTask
中的一个。
对于第一个解决scheme:我喜欢在清单中使用singleTask
而不是singleInstance
,因为使用singleInstance
我发现在某些情况下,活动为自己创build一个新的独立实例,导致在两个单独的应用程序窗口在bcakground运行的应用程序,除了额外的内存分配,这将导致非常糟糕的用户体验,当用户打开应用程序视图select一些应用程序恢复。 因此,更好的方法是在manifest.xml中定义如下所示的活动:
<activity android:name=".MainActivity" android:launchMode="singleTask"</activity>
你可以在这里查看活动启动模式。
对于第二种解决scheme,您只需定义一个静态variables或一个首选variables,例如:
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); }
这只是为我工作时startActivity(intent)
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
myButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { myButton.setOnClickListener(null); } });
使用一个flag
variables将其设置to true
,检查它是否真正只是return
其他执行活动调用。
你也可以使用setClickable(false)来执行Activity Call
flg=false public void onClick(View view) { if(flg==true) return; else { flg=true; // perform click} }
你也可以试试这个
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); } });
你可以重写startActivityForResult并使用实例variables:
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); } }