Thread
三种方式
连接服务器的功能,是属于耗时任务,所以必须放在子线程
如果子线程已经执行了耗时操作,那么就不能修改视图的属性了;视图的属性只能在UI线程去修改
方法1(继承Thread)
class MyThread extends Thread{
@Override
public void run() {
super.run();
try {
sleep(3000);
Log.i("123", "123");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
MyThread myThead = new MyThread();
myThread.start();
方法2(实现Runnable接口)
class MyRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(3000);
String result = "runnable 345345";
Log.i("runnable", result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
方法三(匿名 Runnable)
new Thread(new Runnable() {
@Override
public void run() {
// 耗时任务
try {
Thread.sleep(3000);
String result = "匿名线程";
Log.i("匿名线程",result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Handler
定义
子线程中是没有办法修改页面,这个时候需瑶借助Handler给主线程传递消息
主线程接收到Hander消息后,开始执行修改UI
案例
public class MainActivity2 extends AppCompatActivity {
// 声明容器
private TextView tv1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
// 根据ID获取页面控件
tv1 = findViewById(R.id.tv1);
new Thread(new Runnable() {
@Override
public void run()
//模拟一个链接服务器的耗时操作
try {
Thread.sleep(300);
String name = "炸炸";
Message message = new Message();
message.what = 1;
message.obj = name;
handler.handleMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//判断子线程传输的线程
if (msg.what == 1) {
//修改UI线程(进行页面修改)
String result = (String) msg.obj;
tv1.setText(result);
}
}
};
}
进度条案例
public class MainActivity3 extends AppCompatActivity {
//设置容器
private ProgressBar progressBar;
int status = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
//根据ID获取页面控件
progressBar = findViewById(R.id.progressBar);
//(匿名 Runnable)使用
new Thread(new Runnable() {
@Override
public void run() {
// 循环对status进行值得修改
while (status != 100) {
try {
Thread.sleep(100);
status++;
handler.sendEmptyMessage(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
private Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what ==2) {
progressBar.setProgress(status);
}
}
};
}
通过使用Service和 IntentService解决ANR
Service和IntentService的区别
IntentService
IntentService是Service的子类,比普通的Service增加了额外的功能。先看Service本身存在两个问题:
Service不会专门启动一条单独的进程,Service与它所在应用位于同一个进程中;
Service也不是专门一条新线程,因此不应该在Service中直接处理耗时的任务;
IntentService特征:
会创建独立的worker线程来处理所有的Intent请求;
会创建独立的worker线程来处理onHandleIntent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service;
为Service的onBind()提供默认实现,返回null;
为Service的onStartCommand提供默认实现,将请求Intent添加到队列
会自动开启线程,也不会自动停止线程所以需要我们手动创建和关闭
怎么创建IntentService
1.新建一个Class文件
2.继承IntentService
3.实现onHandleIntent 和 构造方法
- 在AndroidManifest.xml中注册,注册时发现报错,报错的原因是没有无参的构造方法,解决办法:创建无参的构造方法
也可以通过下面的步骤新建
但是需要删除一些没用的内容 跟 手动创建一样也需要自己手动再添加一个无参的构造方法
System.currentTimeMillis() //获取当前系统时间
案例
//使用Service
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//跳转到Service
Intent intent = new Intent(MainActivity.this,MyService.class);
startService(intent);
}
});
//使用IntentService
bt_intentService =findViewById(R.id.bt_intentService);
bt_intentService.setOnClickListener(new View.OnClickListener() {
//跳转到IntentService
@Override
public void onClick(View view) {
Intent intent =new Intent(MainActivity.this,MyIntentService.class);
startService(intent);
}
});
Service
package com.example.myapplicationsirwz;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
Log.i("Service","Service创建");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("Service","Service已开启");
new Thread(new Runnable() {
@Override
public void run() {
//获取当前系统时间加上20秒
long sum = System.currentTimeMillis() + 20*1000;
//判断当前系统时间小于定义时间就进行延时操作
while (System.currentTimeMillis() < sum){
synchronized (this){
try {
wait(sum-System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i("Service","Service被销毁");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
IntentService
package com.example.myapplicationsirwz;
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.util.Log;
import androidx.annotation.Nullable;
public class MyIntentService extends IntentService {
/**
* @param name
* @deprecated
*/
//有参构造方法
public MyIntentService(String name) {
super(name);
}
//无参构造
public MyIntentService() {
super("MyIntentService");
}
//模拟进行延时操作
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("IntentService","IntentService已开启");
long sum = System.currentTimeMillis() + 20*1000;
while (System.currentTimeMillis() < sum) {
synchronized (this) {
try {
wait(sum - System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
return super.onStartCommand(intent, flags, startId);
}
//在 onDestroy 查看IntentService的线程是否存在
@Override
public void onDestroy() {
super.onDestroy();
Log.i("IntentService","已被销毁");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
}
}
总结
在Activity进行 耗时操作
需要使用 Thread 构建子线程 子线程不能修改UI线程
这个同时需要借助 handler 来修改UI页面内容
通过使用Service IntentService来进行处理延时操作的话
Service Service不会自动开启线程,也不会自动停止线程
IntentService 自动开启线程,并在执行完毕后,关闭线程
super.onDestroy();
Log.i(“IntentService”,“已被销毁”);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
}
}
## 总结
在Activity进行 耗时操作
需要使用 Thread 构建子线程 子线程不能修改UI线程
这个同时需要借助 handler 来修改UI页面内容
通过使用Service IntentService来进行处理延时操作的话
Service Service不会自动开启线程,也不会自动停止线程
IntentService 自动开启线程,并在执行完毕后,关闭线程