首页 文章

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

提问于
浏览
54

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

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

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

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

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

18 回答

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

    将其添加到 Androidmanifest.xml 中的 Activity 定义中...

    android:launchMode = "singleInstance"
    
  • 2

    你可以像这样使用意图标志 .

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

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

  • -1

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

    “活动打开两次”问题的常见答案以及我对这些解决方案的体验(Android 7.1.1):

    • 禁用启动活动的按钮:工作但感觉有点笨拙 . 如果您有多种方法在应用程序中启动活动(例如操作栏中的按钮和单击列表视图中的项目),则必须跟踪多个GUI元素的启用/禁用状态 . 例如,在列表视图中禁用单击的项目并不是很方便 . 所以,不是一个非常普遍的方法 .

    • launchMode = "singleInstance":不使用startActivityForResult(),使用startActivity()中断导航,不建议Android驱动程序文档使用常规应用程序 .

    • launchMode = "singleTask":不使用startActivityForResult(),不建议Android驱动程序文档使用常规应用程序 .

    • FLAG_ACTIVITY_REORDER_TO_FRONT:休息按钮 .

    • FLAG_ACTIVITY_SINGLE_TOP:无效,活动仍然打开两次 .

    • FLAG_ACTIVITY_CLEAR_TOP:这是唯一一个为我工作的人 .

    编辑:这是用startActivity()开始活动 . 使用startActivityForResult()时,我需要设置FLAG_ACTIVITY_SINGLE_TOP和FLAG_ACTIVITY_CLEAR_TOP .

  • 0

    假设@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;
    }
    

    What's the deifference between my and @wannik's answer?

    如果在其调用视图的侦听器中将enabled设置为false,则仍将启用使用相同侦听器的其他按钮 . 所以为了确保侦听器的动作没有被调用两次,你需要有一些全局禁用侦听器的所有调用(如果它是新实例或没有,则永远不要)

    What is the difference between my answer and others?

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

  • 1

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

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

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

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

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

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

    startActivity(intent) 这只对我有用

    intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    
  • 27

    对于这种情况,我将分别使用manifest.xml中的两个中的一个, singleTask 或者活动的 onResume()onDestroy() 方法中的一个标志 .

    对于 first 解决方案:我更喜欢使用 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);
    }
    
  • 0

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

    只需在按钮onClick方法中维护一个标志:

    public boolean oneTimeLoadActivity = false;

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

    如果您正在使用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;
      }
    }
    

    由于在事件上返回了请求代码,因此也会按下后退按钮 .

  • 4

    添加:

    android:launchMode="singleTop"
    

    AndroidManifest.xml中的activity标记内部解决了这个问题 .

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

    使用 flag 变量将其设置为 to true ,检查其是否为真仅 return 否则执行活动调用 .

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

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

    你也可以尝试一下

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

相关问题