【问题标题】:How to return to main thread AndroidAndroid如何返回主线程
【发布时间】:2014-10-16 19:00:37
【问题描述】:

我有一个简单的活动,有两个按钮“开”和“关”。我想用“On”按钮开始循环改变背景颜色,用“Off”按钮停止。我还需要通过单击“关闭”按钮获得红色。我写了简单的程序,一切都很好,但我无法理解一件事。为什么最后一种颜色不总是红色?如果我在主线程循环中使用代码

Thread.sleep(100);

Thread.sleep(1000);

我总是有红色,但如果我设置了

Thread.sleep(10);

我有随机的最后一种颜色。为什么??

谢谢!!

我有这个代码:

公共类 MyActivity 扩展 Activity {

final Handler myHandler = new Handler();

private int randColor;

final Runnable updateColor = new Runnable() {

    public void run() {
        final Random random = new Random();
        randColor = Color.rgb(random.nextInt (255), random.nextInt (255), random.nextInt (255));
        mRelativeLayout.setBackgroundColor(randColor);
    }
};

private ColorChanger myThread;

class ColorChanger extends Thread {

    private volatile boolean mIsStopped = false;

    @Override
    public void run() {
        super.run();

        do
        {
            if (!Thread.interrupted()) {
                myHandler.post(updateColor);
            }
            else
            {
                return;
            }
            try{
                Thread.sleep(100);      
            }catch(InterruptedException e){
                return; 
            }
        }
        while(true);


    }

    public void stopThis() {

        this.interrupt();
    }
}

private RelativeLayout mRelativeLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);

    mRelativeLayout = (RelativeLayout)findViewById(R.id.relativeLayout);

}

public void onflagClick(View view) {

    myThread = new ColorChanger();
    myThread.start();

}


public void onflagoffClick(View view) throws InterruptedException {

    myThread.interrupt();

    if(myThread.isAlive())  
    {
        try {
            myThread.join();    
        } catch(InterruptedException e){

        }

    }
    else    
    {
        mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.redColor));
    }

    mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.redColor));

}

}

【问题讨论】:

  • ima 将此作为评论使用线程发布.. 您可以转到我的个人资料并查看我的答案休息时间不到几秒

标签: android multithreading android-activity


【解决方案1】:

我同意之前的回答者,但提出不同的解决方案。

首先让我说我建议您停止使用 Runnables。一般来说,将 Runnable 发布到 Handler 的效率低于发送 Message 的效率,尽管这条规则有非常罕见的例外。

现在,如果我们发送消息,我们应该怎么做?我们基本上想做的是继续做我们正在做的事情,直到遇到一个条件。一个很好的方法是编写一个接收消息的消息处理程序,完成我们的工作(设置颜色),检查我们是否应该继续,如果是,则在未来安排一个新的消息来做更多的工作。让我们看看如何做到这一点。

假设下面的代码在一个 Activity 中。

private static final int MSG_UPDATE_COLOR = 1;
private static final int DELAY = 10; //10 millis

private final Object mLock = new Object();
private boolean mContinue = true;

Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_COLOR:
                synchronized (mLock) {
                    if (mContinue) {
                        setColor(Color.rgb(random.nextInt (255), random.nextInt (255), random.nextInt (255)));
                        mHandler.sendEmptyMessageDelayed(MSG_UPDATE_COLOR, DELAY);
                    } else {
                        setColor(Color.RED);
                    }
                }
                break;
            }
        }
    }
}

public void onflagClick(View view) {

    mHandler.sendEmptyMessage(MSG_UPDATE_COLOR);

}

public void onflagoffClick(View view) throws InterruptedException {
    synchronized (mLock) {
        mContinue = false;
    }

    // cancel any pending update
    mHandler.removeMessages(MSG_UPDATE_COLOR);
    // schedule an immediate update
    mHandler.sendEmptyMessage(MSG_UPDATE_COLOR);
}

好的,那么,这里发生了什么。我们创建了一个处理程序,它将执行所有颜色更新。当我们的开始事件发生时,我们就开始了。然后消息在十毫秒内安排一条新消息(因此颜色更新)。当停止事件发生时,我们重置消息处理程序读取的标志以确定是否应该安排新的更新。然后我们取消所有更新消息的调度,因为它可能会在未来几毫秒被调度,而是立即发送一条消息来进行最终的颜色更新。

对于奖励积分,我们消除了使用节省资源的第二个线程。仔细看,我使用了同步块,但这些实际上是不必要的,因为 一切 都发生在主线程上。我包括这些以防有人从后台线程更改mContinue。此策略的另一个优点是所有颜色更新都发生在代码中的一个位置,因此更容易理解。

【讨论】:

  • 非常感谢!我会试试这个!
【解决方案2】:

当您向Handler 发帖时,它会在未来某个特定时间运行您的Runnable。这不是立即的。它也可以在队列中工作,因此您发布到Handler 的次数越多,您将堆叠最终将按顺序执行的命令。

您正面临竞争条件,因为使用Thread.sleep(10),程序很可能会堆积很多Runnables 来执行。无论您的线程是否正在运行,它们都会运行,因为它们已排队等待在主线程上运行。 Thread.sleep(100)Thread.sleep(1000) 没有这个问题仅仅是因为你给了系统足够的时间来执行所有颜色命令。但是,如果您在正确的时间按下了关闭按钮,仍然可能会出现此问题。

【讨论】:

    【解决方案3】:

    正如 DeeV 告诉你的,Handler 将 Runnables 发送到 Looper,这基本上是一个在每个循环中处理消息或 runnables 的线程循环。您正在排队向主 Looper 发送消息,然后您正在休眠您的工作线程。例如,您可能在工作线程的每个循环之间连续发送 2 个可运行文件,但主循环器只执行了最后一个,因此您无法看到所需的每种颜色。

    如果您想要一个简单的解决方案使其工作,您可以使用ObjectCountDownLatch 将您的主要Looper 与您的工作人员Thread 同步。

    例如:就在你睡觉之前你的工人Thread你可以做下一件事myLockObject.wait()

    然后,您应该将post(Runnable) 更改为sendMessage(Message)。在handleMessage 中来自Handler 中,您可以执行myLockObject.notify()(请记住,handleMessage 将在您创建了HandlerLooper 内执行,或者您可以指定任何您想要明确的Looper )。要获取新的Message,您应该使用myHandler.obtainMessage()

    这将使您的工作人员 Thread 等待您的主要 Looper 在您等待 X 时间直到发布下一个颜色之前处理您的可运行文件。显然,您应该创建新的Object 作为Activity 的字段,例如:

    private myLockObject = new Object()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-18
      • 2011-08-04
      • 2017-08-21
      • 1970-01-01
      • 1970-01-01
      • 2014-03-10
      • 1970-01-01
      相关资源
      最近更新 更多