【发布时间】:2018-11-07 13:25:40
【问题描述】:
我正在做一些实验,以在 Windows 10 Pro x64 上使用 Android Studio 最新版本来体验 Android 开发中的线程和任务。我编写了一个带有两个按钮的非常简单的应用程序的两个版本,以说明使用分离的线程来处理非常繁重的工作是多么重要,这样应用程序就不会挂起:使用一个按钮我可以更改布局背景颜色,使用另一个按钮我启动一个从 0 计数到 10000000 的计数器,显示操作栏上的增量值。此计数器可以将应用程序的响应性卡住几秒钟,因此当它启动时,直到它结束时,都无法更改背景颜色。在这种情况下,为这项繁重的工作创建一个单独的任务是个好主意。
这两个版本的应用程序不同,因为第一个版本没有单独的计数器任务(因此可以体验到应用程序在计数期间没有响应),而第二个版本有。
这是第一个版本的源代码:
package com.example.testasync;
import android.graphics.Color;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
ActionBar actionBar;
int flagBackgroundColor = 0;
LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
actionBar = getSupportActionBar();
actionBar.setTitle("Counter: 0");
linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
Button btnStartCounter = new Button(this);
Button btnChangeBackgroundColor = new Button(this);
btnStartCounter.setText("Start counter");
btnChangeBackgroundColor.setText("Change background color");
btnChangeBackgroundColor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (flagBackgroundColor) {
case 0:
linearLayout.setBackgroundColor(Color.BLACK);
flagBackgroundColor++;
break;
case 1:
linearLayout.setBackgroundColor(Color.RED);
flagBackgroundColor++;
break;
case 2:
linearLayout.setBackgroundColor(Color.GREEN);
flagBackgroundColor++;
break;
case 3:
linearLayout.setBackgroundColor(Color.GRAY);
flagBackgroundColor++;
break;
case 4:
linearLayout.setBackgroundColor(Color.WHITE);
flagBackgroundColor = 0;
break;
}
}
});
btnStartCounter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int i;
actionBar.setTitle("Counter: 0");
for(i=0; i<10_000_000; i++) {
actionBar.setTitle("Counter: " + i);
}
}
});
linearLayout.addView(btnStartCounter);
linearLayout.addView(btnChangeBackgroundColor);
setContentView(linearLayout);
}
}
我对增量 for 循环使用单独任务的第二个源代码是这样的:
package com.example.testasync;
import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends AppCompatActivity {
ActionBar actionBar;
int flagBackgroundColor = 0;
LinearLayout linearLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
actionBar = getSupportActionBar();
actionBar.setTitle("Counter: 0");
linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
Button btnStartCounter = new Button(this);
Button btnChangeBackgroundColor = new Button(this);
btnStartCounter.setText("Start counter");
btnChangeBackgroundColor.setText("Change background color");
btnChangeBackgroundColor.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (flagBackgroundColor) {
case 0:
linearLayout.setBackgroundColor(Color.BLACK);
flagBackgroundColor++;
break;
case 1:
linearLayout.setBackgroundColor(Color.RED);
flagBackgroundColor++;
break;
case 2:
linearLayout.setBackgroundColor(Color.GREEN);
flagBackgroundColor++;
break;
case 3:
linearLayout.setBackgroundColor(Color.GRAY);
flagBackgroundColor++;
break;
case 4:
linearLayout.setBackgroundColor(Color.WHITE);
flagBackgroundColor = 0;
break;
}
}
});
btnStartCounter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyTask myTask = new MyTask();
myTask.execute();
}
});
linearLayout.addView(btnStartCounter);
linearLayout.addView(btnChangeBackgroundColor);
setContentView(linearLayout);
}
class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
int i;
actionBar.setTitle("Counter: 0");
for(i=0; i<10_000_000; i++) {
actionBar.setTitle("Counter: " + i);
}
return null;
}
}
}
当我单击启动计数器的按钮时,出现以下错误:
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
在互联网上搜索我发现对于这样的问题,解决方案是使用 runOnUiThread() 但这样做我得到了与第一个源代码相同的结果:应用程序卡住等待计数器结束。 如何在不冻结 UI 的情况下在操作栏上显示计数器的增量值?有没有办法从另一个线程访问和修改操作栏内容?还有另一种我不知道的方法吗?
【问题讨论】:
-
你为什么不使用处理程序? developer.android.com/reference/android/os/Handler
-
感谢您的快速回复。我是 Andoird 开发的新手,我在网上关注一些视频教程,当谈到任务和线程时,他们都没有谈到 Handler。现在我要看看你的链接。再见。
标签: java android multithreading task