服务是什么
服务是无需UI在后台运行的代码,所以会用到多线程。android服务并不是独立运行的,而是在app的进程中。
android多线程编程
android中,定义一个线程直接继承Thread即可。
class MyThread extends Thread{
@Override
public void run(){
//业务逻辑
}
}
new MyThread().start();
也可以直接实现Runnable接口来定义一个线程
class MyThread implements Runable{
@Override
public void run(){
//业务逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start()
也可以通过匿名类来创建:
new Thread(new Runnable(){
@Override
public void run(){
//业务逻辑
}
}).start();
异步消息处理机制
需要注意的是,android中,ui的更新处理不能放在子线程中。那么如果我们需要在子线程里执行一些业务然后更新UI怎么办?这时候就可以使用异步消息来处理。
异步消息有Message Handler MessageQueue Looper四部分组成。
1.Message
是线程直接传递一些简单的消息类。what字段、arg1、arg2传递整形数字。obj传递Object对象。
2、Handler
用于发送及处理消息。sendMessage()是发送,handleMessge()是接收。
3、MessageQueue
是消息队列。handler发来的消息都会在MessageQueue中存储。每个线程中会有一个队列。
4、Looper
Looper是线程中管理MessageQueue的类,通过Looper.loop()方法,会进入无线循环,每当发现MesageQueue存在一条消息,loop就会将她取出,并传递给handler的handleMessage()方法中。
通过四个对象可见,handler负责发送及接受消息。所以handler需要定义在线程外部,根据handleMessage里的消息进行做出响应的操作。
下面举个简单根据线程执行情况更新UI的例子:
public class ThreadActivity extends AppCompatActivity {
//线程通信及消息处理
Handler handler= new Handler(){
//接收消息进行处理
@Override
public void handleMessage(@NonNull Message msg) {
if(msg.what==1){
EditText et=findViewById(R.id.thread_text);
et.setText("我收到线程的来写:"+msg.what);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thread);
//点击激活线程更新
Button btn = findViewById(R.id.thread_btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//线程更新文本
MyThread thread = new MyThread();
thread.start();
}
});
}
class MyThread extends Thread{
@Override
public void run() {
//要发送的消息
Message msg = new Message();
msg.what=1;
handler.sendMessage(msg);
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ThreadActivity">
<com.google.android.material.button.MaterialButton
android:id="@+id/thread_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击线程运行"
tools:ignore="InvalidId" />
<EditText
android:id="@+id/thread_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="等线程执行完更新本文字!!"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
服务
服务通常用来处理比较耗时的业务,这时会阻塞主进程的运行,导致UI假卡死,这时可以就用到线程了。
服务本身有分为前台后服务和后台服务。前台服务是指app没有处于激活状态,也会运行,会在android的消息栏的列表中看到。
后台服务是指当app不处于激活状态,有可能就不会运行了。如果没有外部干涉,服务都会一直运行的。所以服务需要启动和停止来管理服务。
另外服务需要在androidMainfest.xml声明,以及包括权限的声明。
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
//初始化要执行的
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//启动时要执行的
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
//销毁时要执行的
super.onDestroy();
}
}
在action中调用:
Intent rx1 = new Intent(this,MyService.class);
startService(rx1);//启动
Intent rx2 = new Intent(this,MyService.class);
stopService(rx2);//停止
需要注意的是,服务可以创建实例启动,也可以创建个实例停止。
active和服务的通信
上面的例子,服务在activity中实例化后就没有其他交互了。实际上,服务完成的进度如何,activity还是需要知道的。
这个时候,服务内部首先需要有个内部类实现IBinder()接口的类,这个类获取服务的相关进度,然后通过onBinder()返回这个类。
然后activity在通过ServiceConnetion对象的onServiceConnected()和onServiceDisconnected来实例化服务后,就可以直接调用内部类的相关方法。
首先改写一些服务,在里面增加一个实现Binder的监控内部情况的监督类,该类通过服务的onBind()返回:
public class MyService extends Service {
//服务监督的内部类,通过onBind返回
private MyIBinder myIBinder = new MyIBinder();
public MyService() {
}
//返回监督类
@Override
public IBinder onBind(Intent intent) {
return myIBinder;
}
@Override
public void onCreate() {
//初始化要执行的
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//启动时要执行的
Log.v(this.getClass().getName(),"服务启动执行业务");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
//销毁时要执行的
super.onDestroy();
}
//服务监控类
class MyIBinder extends Binder {
//假设返回服务的执行状态
public String getServiceStatus(){
return "ok";
}
}
}
然后回到activity中,创建ServiceConnetion,在里面访问服务的内部类方法,获取服务的情况。
//服务
MyService.MyIBinder myIBinder;
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//连接中
//初始化内部类,调用七方法访问服务
myIBinder=(MyService.MyIBinder)service;
String status=myIBinder.getServiceStatus();
Button test =findViewById(R.id.finish_button);
test.setText(status);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//绑定服务
Intent it = new Intent(MainActivity.this, MyService.class);
bindService(it, connection, this.BIND_AUTO_CREATE);
//解绑
unbindService(connection);
}
前台服务
上面说了后台服务在后台不是活动状态是,可能会被回收。而前台服务不会。所以后台服务可以修改一下改成前台服务。所谓前台服务就是通知。在通知中可以看到执行的服务。
将服务的onCreate方法改成如下即可:
@Override
public void onCreate() {
//初始化要执行的
super.onCreate();
//前台服务
NotificationManager manager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channl;
String id="";
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
channl=new NotificationChannel("我的","我的消息",NotificationManager.IMPORTANCE_DEFAULT);
id=channl.getId();
manager.createNotificationChannel(channl);
}
//前台通知代码
Intent intent = new Intent(this,MainActivity.class);
PendingIntent pi= PendingIntent.getActivity(this,0,intent,0);
Notification notification = new NotificationCompat.Builder(this,id)
.setContentTitle("我是服务啊")
.setContentText("服务内容的描述")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pi).build();
startForeground(1,notification);
}
服务使用线程
重写服务的onStartCommand方法即可:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//启动时要执行的
new Thread(new Runnable() {
@Override
public void run() {
//具体的业务逻辑
//运行完停止,不然服务一直会在执行中
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
另外也可以继承IntendService服务。在onHandleIntent()方法中执行相关业务逻辑。
IntendService启动方式与与Service相同。
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
//业务逻辑
Log.v("MyIntentService","打印当前线程ID"+Thread.currentThread().getName());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("MyIntentService","服务线程执行完结速时,我会执行");
}
}