2014-10-16 48 views
0

我有一个简单的活动,两个按钮“开”和“关”。我想开始改变背景的颜色,并用“On”按钮循环,并用“Off”按钮停止。此外,我需要点击“关”按钮才能看到红色。我写了简单的程序,一切都很好,但我不明白一件事。为什么最后一个颜色不总是红色?如果我在主线程循环使用代码如何返回主线程Android

Thread.sleep(100); 

Thread.sleep(1000); 

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

Thread.sleep(10); 

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

谢谢!

我有这样的代码:

公共类MyActivity延伸活动{

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

} 

}

+0

ima发表评论使用线程..你可以去我的个人资料,并查看我的答案我回答了关于背景和用户界面工作的问题..据我所知,它的1000是1秒,其余的都不到秒 – Elltz 2014-10-16 19:20:11

回答

1

当你邮寄到Handler,它会运行Runnable在未来的某个给定的时间。这不是直接的。它也在一个队列中工作,所以你发布到Handler的次数越多,你将要堆积的命令将最终被全部执行。

由于Thread.sleep(10)这个程序很可能会堆积很多Runnables来执行,因此您正面临竞争状况。无论您的线程是否正在运行,它们都将运行,因为它们已经排队等待在主线程上运行。 Thread.sleep(100)Thread.sleep(1000)只是因为您给系统足够的时间来执行所有颜色命令而没有此问题。但是,如果您在恰当的时间按下关闭按钮,则仍有可能出现此问题。

0

DeeV告诉你,Handler发送Runnables到Looper,它基本上是一个线程循环,处理消息或每个循环中的可运行内部。你正在排队消息到主Looper,然后你正在睡你的工作线程。它有可能是你在工作线程的每个循环之间发送了一行连续的2个runnables,但是主循环只执行了最后一个循环,所以你不能看到你想要的每种颜色。

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

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

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

这将使您的工作人员Thread等待您的主Looper在您等待X时间之前处理您的runnable,直到您发布下一种颜色。很显然,你应该创建新Object为您Activity的领域,例如:

private myLockObject = new Object()

2

我以前的答案-ERS同意,但提出了不同的解决方案。

首先让我说,我建议你停止使用Runnables。一般而言,将Runnable发布到处理程序的效率不如发送消息,尽管此规则非常罕见。

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

假设下面的代码在一个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。这个策略的另一个重点是所有的颜色更新都在代码中的一个地方发生,因此它更易于理解。

+0

非常感谢!我会试试这个! – 2014-10-18 14:03:04