文章目录
服务是什么
服务是Android中实现程序后台运行解决方案,非常适合去执行那些不需要和用户交互而且还要长期运行的任务。
Android多线程编程
线程的基本用法
Android多线程和java多线程基本都使用相同的语法,下面展示两种写法
class MyThread extends Thread{
public void run(){
//具体的操作逻辑
}
}
new MyThread().start();
class MyRunable implements Runnable{
@Override
public void run() {
}
}
new Thread(new MyRunable()).start();
在子线程中更新UI
Android中UI是线程不安全的,如果要更新应用程序里的UI元素,必须在主线程中进行
异步消息处理机制:完美的解决了子线程中进行UI操作的问题
- 原理: 由4部分组成
方法 | 解析 |
---|---|
Message | 用于线程之间传递信息,在不同的线程间交换数据 |
handler | 处理者的意思,用于发送和处理信息 |
MessageQueue | 消息队列,用于存放所有通过Handler发送的信息,每个线程中只有一个MessageQueue对象 |
Looper | 每个线程中MessageQueue的管家,调用Looper的loop()方法之后,就会进入到一个无限循环中,每当发现MessageQueue中存在一条消息,就会将他取出,并传递到Handler的handleMessage() |
流程:当创建一个Message对象,并通过header将这条消息发送出去时,这条消息就会被添加到消息队列中等待被处理,而looper则会一直尝试从MessageQueue中取出待处理的信息,最后分发回Header的handleMessage()方法中。由于Hander是在主线程创建的,所以此时的handerMessage()方法在主线程运行
- 应用
runOnUIThread():他是一个异步消息处理机制的接口封装。
runOnUiThread(new Runnable() {
@Override
public void run() {
这里可用于更新UI
}
});
AsyncTask()
android提供的方便在子线程中对UI操作的工具,原理也是基于异步消息处理机制。
他是一个抽象类,想要使用他就要创建一个子类去继承他。有三个参数
参数名 | 作用 |
---|---|
Params | 在执行AsyncTask时需要传入的参数,可用于在后台任务中使用 |
Progress | 后台任务执行时,如果需要显示进度,使用这里指定的泛型作为进度单位 |
Result | 当任务执行完毕后,如果需要对结果返回,实用这里的泛型作为返回类型 |
TextView textView;
ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView)findViewById(R.id.text);
new MyAskncTask().execute(); //调用
}
class MyAskncTask extends AsyncTask<Void,Integer,Boolean> {
private int downloadPercent;
@Override
protected void onPreExecute() {
//后台任务执行之前调用,进行一些界面的初始化操作
super.onPreExecute();
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.show();
}
@Override
protected Boolean doInBackground(Void... voids) {
//这个方法所有的代码都在子线程中运行,在这里处理费时操作
while (true){
downloadPercent+=1;
publishProgress(downloadPercent);
if(downloadPercent>=10000)
break;
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
//当后台任务中调用了publishProgress(Progress...)方法之后,该方法很快被调用,可进行一些UI操作
progressDialog.setTitle("123");
progressDialog.setMessage(values[0]+"%");
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Boolean aBoolean) {
//当后台任务执行完毕并通过return语句返回时,这个方法很快被调用,返回的数据会传入到这个方法中
super.onPostExecute(aBoolean);
}
}
服务的基本用法
定义一个服务
可用Android stdio的快捷创建方式,右击com.example.app->new->Service->Service。
也可自定义服务
- 创建一个类继承自Service类,重写onBind()方法,这个是用于和活动通信的。
public class ServiceTest extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
- 在AndroidMAnifest.xml文件中注册
<service
android:name=".MyService"
android:enabled="true" //是否启用这个服务
android:exported="true"> //是否允许除了当前程序之外的其他程序访问这个服务
</service>
服务的生命周期
onCreate() 首次创建时调用
onStartCommand() 启动服务的时候调用,调用startService方法或者startForegroundService方法,回调此方法,如果这个服务还没有被创建过,onCreate()方法会先于这个方法调用
onBind() 在使用bindService()与服务绑定后回调此方法
onDestroy() 服务销毁时调用,比如调用了stopService(),stopSelf(),unbindService()方法
创建前台服务
- 权限申请
面向Android 9(API级别28)或更高版本并使用前台服务的应用必须请求 FOREGROUND_SERVICE 权限
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
- 启动前台服务
要请求您的服务在前台运行,使用startForeground()。此方法有两个参数:一个用于在状态栏中唯一标识通知的正整数和 Notification对象本身。通知的优先级必须为PRIORITY_LOW或更高。
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("1","1",NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(MyService.this,"1")
.setChannelId("1")
.setContentTitle("this is Title")
.setContentText("this is text")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.build();
startForeground(1,notification);
- 从前台删除服务
要从前台删除服务,使用 stopForeground()。此方法采用一个布尔值,该布尔值指示是否也要删除状态栏通知。请注意该服务继续运行。
如果在前台运行该服务时停止该服务,则其通知将被删除。
启动服务,停止服务
启动服务:
Android 8.0 有一项复杂功能;系统不允许后台应用创建后台服务。 因此,Android 8.0 引入了一种全新的方法,即 Context.startForegroundService(),以在前台启动新服务。
在系统创建服务后,应用有5秒的时间来调用该服务的 startForeground() 方法以显示新服务的用户可见通知。如果应用在此时间限制内未调用 startForeground(),则系统将停止服务并声明此应用为 ANR。
所以我们在启动服务时要用startForegroundService()启动服务,并在service的onCreate方法中调用startForeground()。
Intent intent = new Intent(MainActivity.this,MyService.class);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
startForegroundService(intent);
}else
startService(intent);
public void onCreate() {
super.onCreate();
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel("1","1",NotificationManager.IMPORTANCE_DEFAULT);
manager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(MyService.this,"1")
.setChannelId("1")
.setContentTitle("this is Title")
.setContentText("this is text")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.build();
startForeground(1,notification);
}
停止服务:
Intent intent1 = new Intent(MainActivity.this,MyService.class);
stopService(intent1);
活动与服务间的通信
主要借助Binder()方法。
Sevice里的逻辑:
private download d = new download();
// 获取Binder子类对象
class download extends Binder{
public void start(){
Log.d("MtService","start");
}
public int getProgress(){
Log.d("MtService","success");
return 0;
}
}
public IBinder onBind(Intent intent) {
return d; //返回该子类对象的实例
}
Activity的逻辑:
private MyService.download download;
private int progress;
// 创建ServiceConnection实例
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//与服务成功绑定时调用
// 可通过向下转型得到服务中Binder的子类实例
download = (MyService.download)service;
download.start();
progress = download.getProgress();
}
//与服务断开连接时调用
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent2 = new Intent(MainActivity.this,MyService.class);
bindService(intent2,connection,BIND_AUTO_CREATE); //绑定服务
bindService方法接收三个参数,第一个是刚创建的Intent对象,第二个是ServiceConnected实例,第三个是一个标志位,这里传入BIND_AUTO_CREATE表示在活动和服务进行绑定时自动创建服务。
原理:当调用bindService()方法后,就会回调服务中的onBind()方法,在ServiceConnected实例的onServiceConnected()方法中会接收到onBind()返回的IBinder对象,就可得到服务中Binder自类对象的实例,调用他里面的方法。
使用IntentService
可以简单的创建一个异步的,会自动停止的服务。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
//注意这里是提供无参构造器,在内部调用父类的有参构造器
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//这个方法是在子线程运行的
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService","onStop..........");
}
}
注册:
<service android:name=".MyIntentService"/>
调用:
Intent intent3 = new Intent(MainActivity.this,MyIntentService.class);
startService(intent3);