一.概述
从今天开始,我们介绍一下线程中的一些知识点,我会通过具体的一些案例来告诉大家如何在实际开发中使用多线程。先看一张效果图
二.实现
我们先看看布局文件,这里只讲一下进度条以及两个控制按钮的样式是如何实现的
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="15dp"
android:progressDrawable="@drawable/progressbar_selector"/>
这里我们用了一个android:progressDrawable属性,这是重点,我们看看
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<gradient
android:endColor="#EEEEEE"
android:startColor="#EEEEEE"/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<gradient
android:endColor="#ff5555"
android:startColor="#ff5555"/>
</shape>
</clip>
</item>
</layer-list>
这里使用了layer-list标签,layer-list通常用在要显示层叠样式的布局文件中,我们这里的进度条刚好有两层,下面是背景,上面是进度,注意,下面这个item我们使用了clip标签,代表的意思是进行裁剪,如果不写的话是不会出来进度条变化的效果。
下面给出完整代码:
public class MainActivity extends AppCompatActivity {
private CheckBox cbCancel;
private ProgressBar progressBar;
private TextView tv_info1;
private TextView tv_info2;
private TextView tvCancel;
private TextView tvStart;
private int num;
private FutureTask futureTask;
private final int TYPE_MSG_RUN = 1001;
private final int TYPE_MSG_DONE = 1002;
private android.os.Handler handler = new android.os.Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case TYPE_MSG_RUN:
progressBar.setProgress(msg.arg1);//设置进度显示
tv_info1.setText("线程计数:"+msg.arg1);
break;
case TYPE_MSG_DONE:
tv_info1.setText("计数完成");
showStatus();
break;
}
}
};
private Thread thread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
addListener();
}
public void initView(){
cbCancel = (CheckBox) findViewById(R.id.cb_cancel);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
tv_info1 = (TextView) findViewById(R.id.tv_info1);
tv_info2 = (TextView) findViewById(R.id.tv_info2);
tvCancel = (TextView) findViewById(R.id.tv_cancel);
tvStart = (TextView) findViewById(R.id.tv_start);
}
public void initData(){
progressBar.setProgress(0);
progressBar.setMax(100);
}
public void addListener(){
cbCancel.setOnClickListener(onClickListener);
tvStart.setOnClickListener(onClickListener);
tvCancel.setOnClickListener(onClickListener);
}
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_start:
if(thread == null||futureTask == null||futureTask.isDone()){
//达到最大进度后重新开始
if(progressBar.getProgress() == progressBar.getMax()){
num = 0;
}
startThread();//当调用cancle(false)时,当前任务并不会中断,如果再次点击启动线程,将会加速任务执行速度
showStatus();
}
break;
case R.id.tv_cancel:
if(futureTask!=null){
//试图取消对此任务的执行。如果任务已完成、或已取消,或者由于某些其他原因而无法取消,
// 则此尝试将失败。当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。
// 如果任务已经启动,则 mayInterruptIfRunning 参数,true,取消任务,中断线程,任务停止,
false,取消任务,不中断线程,也就是说当此参数设置为false时,即使点击了取消按钮,进度条还是会走
// 执行此任务的线程。此方法返回后,对 isDone() 的后续调用将始终返回 true。
// 如果此方法返回 true,则对 isCancelled() 的后续调用将始终返回 true。
futureTask.cancel(cbCancel.isChecked());//只能取消一次
showStatus();
}
break;
}
}
};
public void sendMsg(int num,int what){
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = num;
handler.sendMessage(msg);
}
public void startThread(){
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
while (num<100) {
num++;
sendMsg(num,TYPE_MSG_RUN);
Thread.sleep(100);
}
sendMsg(num,TYPE_MSG_DONE);//完成
return "Done" ;
}
};
futureTask = new FutureTask(callable);
thread = new Thread(futureTask);
thread.start();
}
public void showStatus(){
if(thread == null|| futureTask == null){
return ;
}
StringBuilder sb = new StringBuilder();
sb.append("状态: ");
sb.append("\nFutureTask isCancelled(): " + futureTask.isCancelled());
sb.append("\nFutureTask isDone(): " + futureTask.isDone());//当调用cancell方法后,isDone始终返回true
sb.append("\n\nThread isAlive(): " + thread.isAlive());
sb.append("\nThread isInterrupted(): " + thread.isInterrupted());
tv_info2.setText(sb.toString());
}
@Override
protected void onDestroy() {
super.onDestroy();
if (futureTask != null && !futureTask.isDone()) {
futureTask.cancel(true);
}
}
}