Android:开关(切换按钮)和线程

Android:开关(切换按钮)和线程,android,multithreading,layout,button,toggle,Android,Multithreading,Layout,Button,Toggle,在我针对安卓4.0.3的应用程序中,我曾经有一个按钮用作开关。单击按钮正在进行资源更改(在播放/暂停之间切换),一些任务正在后台执行。特殊之处在于,当按下按钮时,我希望切换在短时间内不可用(以防止快速切换) 为此,我创建了一个等待X秒的线程,如下所示: void blockButton(){ new Thread() { public void run(){ try { synchronized(th

在我针对安卓4.0.3的应用程序中,我曾经有一个按钮用作开关。单击按钮正在进行资源更改(在播放/暂停之间切换),一些任务正在后台执行。特殊之处在于,当按下按钮时,我希望切换在短时间内不可用(以防止快速切换)

为此,我创建了一个等待X秒的线程,如下所示:

void blockButton(){
    new Thread() {
        public void run(){
            try {
                        synchronized(this){
                             button_ready = false;
                             sleep(5000);
                             button_ready = true;
                        }
                }
                catch(InterruptedException ex){}
            }
        }.start();
    }
}
基本上是在我的活动中

if(button_ready){
    // Start background stuff
    changeButtonResource();
    button.setEnabled(false);
    blockButton();
    button.setEnabled(true);
}
到目前为止一切都很顺利。但我最终还是想把它更新成一个开关。代码基本相同(除了变成OnCheckedChangeListener的onClickListener)

但是现在,当我单击一次按钮时,再次单击它将允许更改其资源-但是后台任务不会启动(我已经用可控震源和其他工具尝试过了,它只会更改资源)


因此,我几乎有我的按钮过去的行为,但资源变得一团糟。任何想法都是非常受欢迎的!谢谢。

您不需要创建其他线程
View.postDelayed(Runnable)
为您提供了一种在超时后启用按钮(或执行其他UI操作)的简便方法。您的代码应该如下所示:

class ... extends Fragment {
    private final Runnable enabler = new Runnable() { public void run() {
        button.setEnabled(true);
    }};

    private View button;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {
        View result = ...
        button = result.findViewById(...);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                button.setEnabled(false);
                ...
            }
        });
        ...
    }

    public void onDestroyView() {
        ...
        button = null;
    }

    public void onPause() {
        ...
        button.removeCallbacks(enabler);
    }

    public void onResume() {
        ...
        button.setEnabled(true);
    }
}

片段
活动
消失之前调用
removeCallbacks
,对于避免用户在禁用期间离开而导致并发问题非常重要。在这种情况下禁用回调后,当用户返回到
片段
活动
并且
视图
恢复其保存状态时,确保您不会“卡在”禁用状态非常重要。

您不需要创建另一个线程
View.postDelayed(Runnable)
为您提供了一种在超时后启用按钮(或执行其他UI操作)的简便方法。您的代码应该如下所示:

class ... extends Fragment {
    private final Runnable enabler = new Runnable() { public void run() {
        button.setEnabled(true);
    }};

    private View button;

    public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {
        View result = ...
        button = result.findViewById(...);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                button.setEnabled(false);
                ...
            }
        });
        ...
    }

    public void onDestroyView() {
        ...
        button = null;
    }

    public void onPause() {
        ...
        button.removeCallbacks(enabler);
    }

    public void onResume() {
        ...
        button.setEnabled(true);
    }
}

片段
活动
消失之前调用
removeCallbacks
,对于避免用户在禁用期间离开而导致并发问题非常重要。在这种情况下禁用回调后,当用户返回到
片段
活动
并且
视图
恢复其保存状态时,确保您不会“卡在”禁用状态非常重要。

您的同步块不会做任何事情(
this
引用的线程是一个局部变量,因此不共享。)
button\u ready
是如何声明的?
volatile
?button\u ready是类中的一个正则变量,在onCreate()方法中初始化。同样,该方法与一个简单的按钮一起工作非常好,因此线程可以做一些事情(change var,wait,change var)。要使代码线程安全(这可能解决问题,也可能无法解决问题):删除同步块并将变量声明为volatile:
private volatile boolean button_ready;
。感谢您的提示(尽管没有解决问题),您的同步块没有做任何事情(
this
引用的线程是一个局部变量,因此不共享。)
button\u ready
是如何声明的?
volatile
?button\u ready是类中的一个正则变量,在onCreate()方法中初始化。同样,该方法与一个简单的按钮一起工作非常好,因此线程可以做一些事情(change var,wait,change var)。要使代码线程安全(这可能解决问题,也可能无法解决问题):删除同步块并将变量声明为volatile:
private volatile boolean button\u ready;
。感谢您的提示(尽管没有解决问题)nevermind编辑的评论:我忘了改变另一种方式!效果很好。我仍然想知道为什么它不能与我的旧解决方案一起工作,但嘿,我只想让它工作!谢谢。如果你依赖你的
If(按钮准备就绪)
为了避免状态更改,问题是
切换按钮和
切换器在内部更改其选中状态:您无法从
OnClickListener
中避免这种情况。我相信调用enable(false)是正确的在开关上会阻止它切换状态!我的意思是,我在没有使用所有周围代码的情况下尝试了它-只使用了一个禁用它的按钮-它成功了!无需编辑注释:我忘了改变另一种方式!工作得很好。我仍然想知道为什么它不能与我的旧解决方案一起工作,但嘿,我只想让它工作!谢谢。我如果您依靠
if(button_ready)
来避免状态更改,问题是
ToggleButton
Switcher
在内部更改其选中状态:您无法通过
OnClickListener
来避免这种情况。我相信调用enable(false)打开开关会阻止它切换状态!我的意思是,我在没有使用所有周围代码的情况下尝试了它-只使用了一个禁用它的按钮-它成功了!