如何在按下按钮时阻止活动加载两次

时间:2011-11-10 09:59:37

标签: android button android-activity onclick

如果我在第一次点击后立即按两次按钮,我试图阻止活动加载两次。

我有一个活动,点击按钮加载,比如说

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

现在因为要加载的活动有网络调用,所以加载(MVC)需要一点时间。我确实显示了加载视图,但如果我在此之前按下按钮两次,我可以看到活动被加载两次。

有人知道如何防止这种情况吗?

20 个答案:

答案 0 :(得分:126)

将其添加到Activity ...

中的AndroidManifest.xml定义中
android:launchMode = "singleTop"

答案 1 :(得分:48)

在按钮的事件监听器中,禁用该按钮并显示另一个活动。

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

答案 2 :(得分:32)

你可以使用这样的意图标志。

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

只会在历史堆栈的顶部打开一个活动。

答案 3 :(得分:15)

由于SO不允许我评论其他答案,我不得不用新答案污染这个帖子。

"活动的常见答案会打开两次"问题和我使用这些解决方案的经验(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:无效,活动仍然打开两次。
  6. FLAG_ACTIVITY_CLEAR_TOP:这是唯一一个为我工作的人。
  7. 编辑:这是用于启动startActivity()的活动。使用startActivityForResult()时,我需要设置FLAG_ACTIVITY_SINGLE_TOP和FLAG_ACTIVITY_CLEAR_TOP。

答案 4 :(得分:5)

假设@wannik是正确的,但如果我们有多个按钮调用同一个动作监听器,我在开始下一个活动之前几乎同时点击两个按钮......

所以如果你有一个字段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,则仍将启用使用相同侦听器的其他按钮。因此,为了确保侦听器的动作不被调用两次,你需要有一些全局禁用侦听器的所有调用(如果它是新实例则不用,或者没有)

我的回答与其他人有什么区别?

他们正在以正确的方式思考,但他们没有考虑将来返回到调用活动的同一个实例:)

答案 5 :(得分:4)

使用singleInstance可以避免活动两次调用。

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

答案 6 :(得分:3)

startActivity(intent)

时,它只适用于我
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

答案 7 :(得分:3)

希望这会有所帮助:

 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()
}`

答案 8 :(得分:3)

我认为你正在以错误的方式解决问题。通常,活动在其任何启动生命周期方法(onCreate()onResume()等)中制作长时间运行的Web请求是一个坏主意。实际上,这些方法应该仅用于实例化和初始化您的活动将使用的对象,因此应该相对较快。

如果您需要执行Web请求,请在新启动的活动的后台线程中执行此操作(并在新活动中显示加载对话框)。后台请求线程完成后,它可以更新活动并隐藏对话框。

这意味着您的新活动应立即启动并防止双击。

答案 9 :(得分:2)

其他非常简单的解决方案,如果你不想使用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...
        }
    });

答案 10 :(得分:2)

对于这种情况,我会在manifest.xml中找到两个中的一个,singleTask或者在活动的onResume()&amp;分别为onDestroy()个方法。

对于第一个解决方案:我更喜欢使用singleTask来表示清单中的活动,而不是singleInstance,因为使用singleInstance我发现了在某些情况下,活动为自己创建一个新的单独实例,导致在bcakground中运行的应用程序中有一个两个单独的应用程序窗口,另外还有额外的内存分配,当用户打开应用程序视图选择某些内容时会导致非常糟糕的用户体验应用程序恢复。 因此,更好的方法是在manifest.xml中定义活动,如下所示:

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

您可以查看活动发布模式here

对于 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);
}

答案 11 :(得分:1)

将启动模式作为清单中的单个任务添加,以避免活动在单击时打开两次

<activity
        android:name=".MainActivity"
        android:label="@string/activity"
        android:launchMode = "singleTask" />

答案 12 :(得分:0)

添加:

android:launchMode="singleTop"

AndroidManifest.xml中的活动标签内部解决了该问题。

答案 13 :(得分:0)

只需在按钮onClick方法中保留一个标志:

public boolean oneTimeLoadActivity = false;

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

答案 14 :(得分:0)

If you're using onActivityResult, you could use a variable to save state.

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

Works on back button pressed too because request code is returned on event.

答案 15 :(得分:0)

//用于跟踪事件时间的变量

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

答案 16 :(得分:-1)

您可以覆盖startActivityForResult并使用实例变量:

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

答案 17 :(得分:-1)

使用flag变量设置to true, 检查其真实的return是否执行活动调用。

您还可以使用setClickable(false)执行活动调用

flg=false
 public void onClick(View view) { 
       if(flg==true)
         return;
       else
       { flg=true;
        // perform click}
    } 

答案 18 :(得分:-1)

myButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
      myButton.setOnClickListener(null);
    }
});

答案 19 :(得分:-2)

你也可以尝试这个

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

        });