Java 在Android中持续更新UI线程的最有效方法
我正在通过创建秒表来尝试Android开发中的线程。我目前有一个非常基本的执行,它在模拟器上似乎运行得很好,但在我的手机上运行时却没有效率(非常新的Nexus6,所以手机很好)。我的问题是,作为秒表,持续更新UI线程最有效的方法是什么 我目前正在一个更新UI onProgressUpdate的异步任务中运行它。我想AsyncTask并不是最好的选择,但我也在自己的Runnable中尝试过,结果更糟。我读过关于Handler类的文章,但对如何使用它(或者知道它是否是答案)没有信心。下面是我创建和执行AsyncTask以及AsyncTask本身的地方。我应该注意到这是一个片段Java 在Android中持续更新UI线程的最有效方法,java,android,multithreading,android-asynctask,Java,Android,Multithreading,Android Asynctask,我正在通过创建秒表来尝试Android开发中的线程。我目前有一个非常基本的执行,它在模拟器上似乎运行得很好,但在我的手机上运行时却没有效率(非常新的Nexus6,所以手机很好)。我的问题是,作为秒表,持续更新UI线程最有效的方法是什么 我目前正在一个更新UI onProgressUpdate的异步任务中运行它。我想AsyncTask并不是最好的选择,但我也在自己的Runnable中尝试过,结果更糟。我读过关于Handler类的文章,但对如何使用它(或者知道它是否是答案)没有信心。下面是我创建和执
// Where the thread kicks off on click
private class StartTimer implements View.OnClickListener{
@Override
public void onClick(View v) {
// passes the stopWacth object and the view to update
clockThread = new HiitClock(clockTv, stopWatch);
clockThread.execute();
}
}
然后,这是我扩展AsyncTask的类
public class HiitClock extends AsyncTask<String, Void, String> {
private final String LOG_TAG = HiitClock.class.getSimpleName();
private TextView clock;
private StopWatch stopWatch;
public HiitClock(TextView clock, StopWatch sw){
this.clock = clock;
this.clockSegment = clockSegment;
this.roundSegment = roundSegment;
this.stopWatch = sw;
}
@Override
protected String doInBackground(String... params) {
stopWatch.start();
while(stopWatch.getState() == 1 || stopWatch.getState() == 2){
publishProgress();
}
return "done";
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
clock.setText(convertTime());
}
@Override
protected void onPostExecute(String result) {
// end of timer
clock.setText(result);
}
/*
* helper method for converting the time
* */
private String convertTime(){
long milli = stopWatch.getTime();
long sec = milli / 1000 ;
long min = sec / 60;
sec = sec % 60;
milli = milli % 100;
return String.format("%02d:%02d:%02d", min, sec, milli);
}
}
公共类HiitClock扩展异步任务{
私有最终字符串LOG_TAG=HiitClock.class.getSimpleName();
专用文本视图时钟;
私人秒表;
公共HiitClock(文本视图时钟、秒表开关){
这个时钟=时钟;
this.clockSegment=clockSegment;
this.roundSegment=roundSegment;
这个。秒表=sw;
}
@凌驾
受保护的字符串doInBackground(字符串…参数){
秒表。开始();
while(stopWatch.getState()==1 | | stopWatch.getState()==2){
出版进度();
}
返回“完成”;
}
@凌驾
受保护的void onProgressUpdate(void…值){
super.onProgressUpdate(值);
clock.setText(convertTime());
}
@凌驾
受保护的void onPostExecute(字符串结果){
//计时器结束
clock.setText(结果);
}
/*
*转换时间的辅助方法
* */
私有字符串转换时间(){
long milli=秒表。getTime();
长秒=毫/千;
长最小值=秒/60;
秒=秒%60;
毫=毫%100;
返回字符串。格式(“%02d:%02d:%02d”,分钟,秒,毫秒);
}
}
-------更新---------
我感谢各位的答复。我尝试了所有的建议,但在真正的设备上性能仍然很差。我在下面创建了一个简单的示例。也许这个简单的版本可以帮助人们了解我在做什么,阻止UI线程高效地更新。它循环100000次,并使用处理程序尝试和更新UI线程。谢谢
public class MainActivity extends Activity {
private RelativeLayout wrapper;
private TextView clockTv;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
wrapper = (RelativeLayout) findViewById(R.id.hitt_cardio_layout);
clockTv = (TextView) wrapper.findViewById(R.id.clock_text_view);
Button start = new Button(this);
start.setText("Start");
wrapper.addView(start);
start.setOnClickListener(new StartTimer());
}
private class StartTimer implements View.OnClickListener {
@Override
public void onClick(View v) {
new Thread(new Runner()).start();
}
}
private class Runner implements Runnable{
int i;
@Override
public void run() {
for(i = 0; i < 100000; i++){
handler.post(new Runnable() {
@Override
public void run() {
clockTv.setText("index: " + i);
}
});
}
}
}
}
公共类MainActivity扩展活动{
私有相对论包装;
私人文本视图时钟电视;
私人经办人;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler=新的handler();
wrapper=(相对)findViewById(R.id.hitt\u cardio\u布局);
clockTv=(TextView)wrapper.findviewbyd(R.id.clock\u text\u view);
按钮启动=新按钮(此按钮);
start.setText(“开始”);
wrapper.addView(开始);
setOnClickListener(newstarttimer());
}
私有类StartTimer实现View.OnClickListener{
@凌驾
公共void onClick(视图v){
新线程(新流道()).start();
}
}
私有类运行器实现可运行{
int i;
@凌驾
公开募捐{
对于(i=0;i<100000;i++){
handler.post(新的Runnable(){
@凌驾
公开募捐{
clockTv.setText(“索引:+i”);
}
});
}
}
}
}
您可以使用onProgressUpdate()更新UI。除此之外,还有两种方法:
Activity.runOnUiThread(new Runnable() {
@Override
public void run() {
//update your UI
}
});
Handler h = new Handler(){
@Override
public void handleMessage(Message msg){
if(msg.what == 0){
updateUI();
}else{
showErrorDialog();
}
}
};
您可以在更新视图的线程上发布runnable:
clock.post(new Runnable() {
@Override public void run() {
clock.setText(convertTime());
// 50 millis to give the ui thread time to breath. Adjust according to your own experience
clock.postDelayed(this, 50);
}
});
(为了保持示例简短,我省略了停止逻辑。将其放回去是一个测试问题,而不是重新发布runnable)。您正在使用onProgressUpdate更新UI线程,对吗?这有什么问题?或者,您也可以使用runOnUIThread方法。异步任务的优先级非常低,因此可能会暂停以将处理器时间分配给另一个线程。由于您根本不需要后台线程,因此自动重新输入
runOnUiThread
效率更高,我非常感谢您的回复。不幸的是,一切似乎都不起作用。我在上面添加了一个更简单的版本,可能有助于确定问题是什么。谢谢,经过更多的测试和研究,我发现你的答案就是我的解决方案。特别是postdayed()方法。最后,我使用了一个Handler对象和postDelayed,并且尽可能地平滑。