考虑这样一个简单的代码:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInastanceState){
super.onCreate(savedInastanceState);
setContentView(R.layout.main);
final ProgressDialog pdUpdate = new ProgressDialog(this);
final Button btn = (Button)findViewById(R.id.btnUpdate);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
btn.setText(Calendar.getInstance().getTime().toString());
int i=0;
while (i<100){
i++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("test","i = " + i);
}
}
});
}
}
点击btn
应该发生两件事:更改按钮的文本并将i
计数到100,延迟为100毫秒(这只是模拟读取文件等繁重过程的一个示例,下载等)。
我知道实现这些代码的正确方法是使用AsyncTask
但我的问题是关于如何编译这些代码。它是一个单线程应用程序。所以编译器首先读取btn.setText(Calendar.getInstance().getTime().toString());
并在执行此行之后转到下一行代码(如果我错了,请纠正我),但这不会发生。为什么?
在C#
中有Refresh()
方法可以解决此问题(只需在应用UI更改和更改后调用它)。在java中有任何类似的方法吗?
我感谢任何帮助。
编辑1
问题是关于以下过程的顺序:
过程1:
btn.setText(Calendar.getInstance().getTime().toString());
流程2:
i++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("test","i = " + i);
}
无论首先出现哪一个(我的意思是btn.onClick(){process1;process2;}
或btn.onClick(){process2;process1;}
),总是先执行第二个过程。我的意思是首先我在Logcat中看到i
的计数,然后看到按钮文本的更改。
答案 0 :(得分:3)
在这种情况下,您无需调用任何等效的refresh()
。但是Button.setText()
不会自动重绘视图层次结构。相反,它会向视图层次结构传递文本更改的信息以及需要重绘的信息。最终,此信息到达视图层次结构的根,进而通知Choreographer
。 Choreographer
为下一帧安排绘图。这又会存储在UI线程的消息队列中。
因此,当您将UI线程置于休眠状态时,布局不会重新绘制,而是计划重新绘制。一旦您的线程空闲,消息队列中的消息就会开始执行。在某些时候,使用重绘消息调用Choreographer
并命令视图层次结构重绘自己。
同时考虑Handler.post(Runnable)
,View.post(Runnable)
及其postDelayed
对应方法可以作为AsyncTask
的替代方案,如果不需要进行大量计算,而是安排一些操作(例如视图更新)以供日后使用。它们使用与上述相同的机制 - 将Runnable
放入线程的消息队列中,然后在线程空闲时将其拾取并执行。
答案 1 :(得分:0)
nonono,只有你的方法运行完成它才能工作(exp:只需在没有while循环的情况下睡眠100 msc)。你可以在google中找到java方法的工作方式。(我的英语很差)
答案 2 :(得分:0)
正如许多人在评论中指出的那样,由于你在while
内进行了onClickListener
循环,因此UI线程永远不会有机会invalidate
你的按钮,因此重绘说按钮。
我想如果你想解决这个问题,你可以简单地让另一个与重绘过程完成相关的监听器。请参阅此answer:
中的以下内容public class DrawListenerView extends View{
private Callback callback;
public DrawListenerView(Callback callback){
this.callback = callback;
}
@Override
protected void onDraw (Canvas canvas){
super.onDraw(canvas);
//add your method here you want to call
//Or use a Callback-pattern
callback.finish();
}
}
public interface Callback(){
public void finish();
}
一旦按钮的绘制完成,你就可以进行循环睡眠。这将为您提供新的文字,然后再睡觉。
我不确定这个应用程序会是什么,但是如果您不希望用户在任何时间内再次点击它,您可能会考虑在按下该按钮一段时间后禁用该按钮。 / p>
答案 3 :(得分:-1)
Android正在管理自己的绘图周期。但是你正在与它共享主线程。您可以在视图上调用invalidate()
,该视图正在计划重新绘制视图。但是你必须在Android的主线程上腾出一些时间才能刷新UI(setText()
可能会调用invalidate()
)。