我希望在应用运行时(无限循环)更改应用的背景 - 然而,应用停止响应或完全空白。我认为这是由于使用Thread.sleep(1);
- 这只会让应用程序进入睡眠状态。
我目前的代码:
runOnUiThread(new Runnable(){
@SuppressWarnings("deprecation")
@Override
public void run(){
GradientDrawable gd = new GradientDrawable(Orientation.TL_BR, green);
gd.setGradientType(GradientDrawable.RADIAL_GRADIENT);
gd.setGradientCenter(0.5f, 1.25f);
gd.setCornerRadius(0f);
for(int x = 0; x < 400; x++){
Thread.sleep(20);
gd.setGradientRadius((float) 400 - x);
findViewById(R.id.ms_layout).setBackgroundDrawable(gd);
}
}
});
在for循环中,我想要更改渐变的半径,然后更新背景,但是,这不起作用:我猜测它何时睡眠整个应用程序停止然后恢复,发现它需要再次停止。
我该如何解决这个问题? 换句话说,如何在不中断应用程序主线程的情况下使用循环更新UI?
答案 0 :(得分:0)
您不应该在UI线程上调用Thread.sleep()。正如你所说,它冻结了用户界面。你应该在另一个线程中做很长的工作(比如Thread.sleep()),然后在UI线程上更新UI。
我做的一个应用程序的例子:
private void startProgressThread() {
new Thread(new Runnable() {
@Override
public void run() {
while (!isPaused) {
// Thread.sleep() is called off the UI thread
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
// The progress bar is then updated on the UI thread
progressBar.post(new Runnable() {
@Override
public void run() {
int time = service.getTimeElapsed();
progressBar.setProgress(time);
elapsedTime.setText(millisToMinutes(time));
}
});
}
}
}).start();
}
答案 1 :(得分:0)
绝对不要在主线程上使用sleep!你需要使用一个计时器,但是有一个问题,你只能从主线程修改UI,所以你需要使用Runnable,如下所述:http://www.techsono.com/consult/update-android-gui-timer/
答案 2 :(得分:0)
你需要post
Runnable
在主线程中一次又一次地执行,而不是让它睡觉。类似的东西:
GradientDrawable gd;
Handler uiHandler;
private View view;
private void start(){
// create the drawable
gd = new GradientDrawable(Orientation.TL_BR, green);
gd.setGradientType(GradientDrawable.RADIAL_GRADIENT);
gd.setGradientCenter(0.5f, 1.25f);
gd.setCornerRadius(0f);
// put it on the view
view = findViewById(R.id.ms_layout);
view.setBackgroundDrawable(gd);
// get a handler for the main thread looper and run
uiHandler = new Handler(Looper.getMainLooper());
uiHandler.post(myRun);
}
private Runnable myRun = new Runnable(){
int x = 0;
@SuppressWarnings("deprecation")
@Override
public void run(){
for(int x = 0; x < 400; x++){
// do the change
gd.setGradientRadius((float) 400 - x);
// ask system to re-draw it
gd.invalidateSelf();
// update n re-post loop
x++;
if(x < 400)
uiHandler.post(myRun);
}
}
};
ps.1:这一切都是在没有测试的情况下完成的,你必须自己调整细节。
ps.2:你也可以像postDelayed
uiHandler.postDelayed(myRun, 20);
修改强>
如果你想做一些更模块化的事情,你可以创建自己的Drawable,从GradientDrawable
扩展并使用setLevel(int)
开始动画。我一直这样做,像这样:
public class MyCustomDrawable extends GradientDrawable{
// put the same constructors GradientDrawable uses.
private int x;
protected boolean onLevelChange (int level){
x = 0;
invalidateSelf(); // this will make the thing call draw
}
public void draw (Canvas canvas){
// adjust what to draw
setGradientRadius((float) 400 - x);
// let the GradientDrawable do its normal drawing thing
super.draw(canvas);
// and then check if it needs another update
x++;
if(x < getLevel())
invalidateSelf();
}
}
将其放在视图的背景中,并在每次要动画时调用gd.setLevel(400);
。
这种方法的优点在于你可以自由调整它,例如,根据你喜欢的时间,4级将是4秒,然后你在onLevelChange
期间进行数学运算long animationEndTime = System.currentTimeMilis() + (level * 1000)
在draw
期间,您调用invalidateSelf()if(System.currentTimeMilis() < animationEndTime)