前面的一篇博客就已经讲了几个定时任务,这些定时任务的实现都是依赖于子线程来实现的。
涉及到子线程我们就要知道线程之间的通信机制。实现子线程将数据发送给主线程,并且在主线程里面更新UI。
再重申一下,耗时操作一定要放在子线程里面实现,比如说网络访问,读取文件的操作等。
1 线程实现定时任务
还是使用安卓里面的定时任务 这个博客里面的方式一创建一个定时任务,在控制台打印数据
- 创建一个类里面写一个定时方法 ```java public class TimeMethods {
public static void getRandom(){
new Thread(new Runnable() {
@Override
public void run() {
//开始一个死循环
while (true){
//这里是一个子线程,在这里创建一个方法
Random random = new Random();
int i = random.nextInt(100);
Log.i("random", "随机数是 :"+Integer.toString(i));
try {
//运行之后睡眠两秒,其实意思就是每两秒执行一次这个程序
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
- [x] 主活动里面开启定时任务
```java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TimeMethods.getRandom();
}
}
- 效果
可以看到这个数据是在子线程里面打印出来的,没有给到主线程。我们现在开始实现将产生的随机数给到主线程,然后让主线程在屏幕上toast出来,并且使用textview展示。
1.2 数据给到主线程
这里我们使用handler机制将数据给到主线程,然后在主线程里面进行处理
[x] 子线程发送数据 ```java public class TimeMethods {
public static void getRandom(Handler handler){
new Thread(new Runnable() {
@Override
public void run() {
//开始一个死循环
while (true){
//这里是一个子线程,在这里创建一个方法
Random random = new Random();
int i = random.nextInt(100);
//这里产生了一个随机数 我们吧这个随机数给到 主线程 使用message发送过去
//消息体对象
Message msg = new Message();
//给消息体设置个代号
msg.what = 22 ;
//设置消息体的内容
msg.obj = Integer.toString(i);
//使用handler发送数据
handler.sendMessage(msg);
Log.i("random", "随机数是 :"+Integer.toString(i));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
注意我们在发送的数据需要用到Handler对象,所以我们就在方法的形参里面传入了一个handler对象。
传递消息主要就是这几句话,我们可以分析一下这几代码
```java
//这里产生了一个随机数 我们吧这个随机数给到 主线程 使用message发送过去
//消息体对象,将要发送的数据添加到这个对象里面
Message msg = new Message();
//给消息体设置个代号,我们在主线程里面通过代号找到子线程发送的数据
msg.what = 22 ;
//设置消息体的内容 ,一般是字符串类型
msg.obj = Integer.toString(i);
//使用handler发送数据
handler.sendMessage(msg);
- 主线程在Handler里面,Handler可以拿到所有线程的数据,里面的handlerMessage方法可以实现对数据的处理
public class MainActivity extends AppCompatActivity {
private String REC ;
//这里创建一个handler方法 来处理子线程方送过来的数据 不写Looper.myLooper()的话就会一直出现阴影
private Handler handler =new Handler(Looper.myLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
//super.handleMessage(msg);
//通过msg.what 找到是哪一个子线程发送过来的数据
switch (msg.what){
case 22 :
String rec = (String)msg.obj ; //需要对收到的数据进行强制类型转换, msg.obj 是一个Object类型,要转为string
REC = rec ;
//这是给textview
TextView textView = findViewById(R.id.ShowRec);
textView.setText(rec);
Toast.makeText(MainActivity.this,rec, Toast.LENGTH_SHORT).show();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用我们自己创建的方法,方法里面开启子线程,子线程里面有死循环,所以子线程一直都在运行。
TimeMethods.getRandom(handler);
//显示到textView里面
// TextView textView = findViewById(R.id.ShowRec);
// textView.setText(REC); //REC这里还是拿不到handler里面的rec数据
// Log.i("random",REC); 因为REC拿不到数据,所以就会报空指针直接闪退
}
}
需要注意的是这个handler里面的数据是没有办法拿到MainActivity这个类里面成为全局变量的,说以我们就只能在handler里面对子线程传递过来的数据进行操作了。
2 案例:时间刷新
通过一里面的方法我们创建一个子线程每隔一秒钟得到一次当前时间的字符串,然后传递给主线程,让主线程显示到TextView里面去。
- 我自己定义的方法类 ```java public class TimeMethods {
public static void getRandom(Handler handler){
new Thread(new Runnable() {
@Override
public void run() {
//开始一个死循环
while (true){
//这里是一个子线程,在这里创建一个方法
Random random = new Random();
int i = random.nextInt(100);
//这里产生了一个随机数 我们吧这个随机数给到 主线程 使用message发送过去
//消息体对象
Message msg = new Message();
//给消息体设置个代号
msg.what = 22 ;
//设置消息体的内容
msg.obj = Integer.toString(i);
//使用handler发送数据
handler.sendMessage(msg);
Log.i("random", "随机数是 :"+Integer.toString(i));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
/**
* 每隔一秒得到一下当前时间的字符串
*/
public static void getCurrTime(Handler handler){
new Thread(new Runnable() {
@Override
public void run() {
while (true){
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeString = simpleDateFormat.format(date);
//开始发送数据
Message message = new Message();
message.what = 44 ;
message.obj = timeString;
handler.sendMessage(message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
- [x] 主活动里面的代码
```java
public class MainActivity extends AppCompatActivity {
private String REC ;
//这里创建一个handler方法 来处理子线程方送过来的数据 不写Looper.myLooper()的话就会一直出现阴影
private Handler handler =new Handler(Looper.myLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
//super.handleMessage(msg);
//通过msg.what 找到是哪一个子线程发送过来的数据
switch (msg.what){
case 22 :
String rec = (String)msg.obj ; //需要对收到的数据进行强制类型转换, msg.obj 是一个Object类型,要转为string
REC = rec ;
//弹出来
Toast.makeText(MainActivity.this,rec, Toast.LENGTH_SHORT).show();
break;
case 44: //这个是得到时间得线程发送过来的数据
String time = (String)msg.obj ; //需要对收到的数据进行强制类型转换, msg.obj 是一个Object类型,要转为string
//这是给textview
TextView textView2 = findViewById(R.id.ShowRec);
textView2.setText(time);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//调用我们自己创建的方法,方法里面开启子线程,子线程里面有死循环,所以子线程一直都在运行。
TimeMethods.getRandom(handler);
//开启刷新事件的线程
TimeMethods.getCurrTime(handler);
//显示到textView里面
// TextView textView = findViewById(R.id.ShowRec);
// textView.setText(REC); //REC这里还是拿不到handler里面的rec数据
// Log.i("random",REC); 因为REC拿不到数据,所以就会报空指针直接闪退
}
}
- 效果展示