读书笔记-Android服务
什么是服务?
- 服务是Android中实现程序后台运行的解决方案,比较适合去用来执行不需要交互,而默默在后台运行的程序,相比于linux的系统中比较像守护进程。
- 但是他不是真正的独立进程,而是依赖于产生服务的应用进程,这样我们就可以很清楚的知道他们之间的生命周期关系。
1.服务的两种启动方式之间的区别
服务有两种启动的方式:
(1).start方式:
- 特点:
- 使用步骤:
1.定义一个类继承Service
2.在Manifest.xml文件中配置该Service
3.使用Context的startService(Intent)方法启动该Service
4.不再使用时,调用stopService(Intent)方法停止该服务
- 生命周期:
onCreate()—>onStartCommand()(onStart()方法已过时) —> onDestory()
- 说明:
如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()。服务停止的时候调用onDestory()。服务只会被停止一次(一个实例)。
(2).bind方式:
- 特点:
bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
绑定者可以调用服务里面的方法。
- 使用步骤:
1.定义一个类继承Service
2.在Manifest.xml文件中配置该Service
3.使用Context的bindService(Intent, ServiceConnection, int)方法启动该Service
4.不再使用时,调用unbindService(ServiceConnection)方法停止该服务
- 生命周期:
onCreate() —>onBind()—>onunbind()—>onDestory()onCreate() —>onBind()—>onunbind()—>onDestory()
2.比较Service与IntentService的异同:
(1).Service
Service 是长期运行在后台的应用程序组件。
Service 不是一个单独的进程,它和应用程序在同一个进程中,Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果直接把耗时操作放在 Service 的 onStartCommand() 中,很容易引起 ANR .如果有耗时操作就必须开启一个单独的线程来处理
**
(2).IntentService
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。
而且,所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。 那么,用 IntentService 有什么好处呢?首先,我们省去了在 Service 中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止 Service
总结来说就是,IntentService帮助我们开线程的麻烦,以及帮助我们停止线程。
3.Activity与Service之间如何进行通信,请编程进行说明:
我将通过编程实例来进行演示如何活动和服务之间进行通信:
我这个项目是比较全的,囊括了start,bind,以及IntentService,不过还是重点说明如何实现通讯的吧:
(1).再服务类MuService中创建一个DownloadBinder类,继承于Binder,然后在里面写两个方法(用来模拟进程对后台的访问),然后再创建一个DownloadBInder的实例,再onBind()这个方法这种返回这个实例:
package com.ncu.servicetest;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.core.app.NotificationCompat;
public class MyService extends Service {
public MyService() {
}
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("MyService", "startDownload executed");
}
public int getProgress() {
Log.d("MyService", "getProgress executed");
return 0;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService", "onCreate executed");
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("This is content title")
.setContentText("This is content text")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentIntent(pi)
.build();
startForeground(1, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "onStartCommand executed");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyService", "onDestroy executed");
}
}
(2).在布局文件activity_main.xml中放两个链接模拟活动于服务链接的按钮以及断开连接的按钮:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/start_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Service" />
<Button
android:id="@+id/stop_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Service" />
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Bind Service" />
<Button
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Unbind Service" />
<Button
android:id="@+id/start_intent_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start IntentService" />
</LinearLayout>
(3).编写MainActivity.java文件:
这里面写一个ServiceConnection的匿名类,在里面重写OnSeviceConnected()方法以及OnServiceDisconnected()方法,这两个方法我们可以得到DownloadBinder实例。
这样可以使用DownloadBinder来调用我们服务中的方法了。
最后需要使用biindService()方法来进行绑定。
unbindService()来接触绑定。
package com.ncu.servicetest;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private MyService.DownloadBinder downloadBinder;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startService = (Button) findViewById(R.id.start_service);
Button stopService = (Button) findViewById(R.id.stop_service);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
Button bindService = (Button) findViewById(R.id.bind_service);
Button unbindService = (Button) findViewById(R.id.unbind_service);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
Button startIntentService = (Button) findViewById(R.id.start_intent_service);
startIntentService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent); // 启动服务
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent); // 停止服务
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
break;
case R.id.unbind_service:
unbindService(connection); // 解绑服务
break;
case R.id.start_intent_service:
// 打印主线程的id
Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
break;
default:
break;
}
}
}
最后我们来看下我们模拟绑定以及接触绑定的效果:
我们看下点击绑定以及接触绑定会触发函数事件:
第一行是我们创建连接绑定,第二行和第三行就是活动访问服务的触发结果,最后一行表示解除绑定。
4.远程服务(或称跨进程服务)有何实际作用?请以Android Studio开发环境为例,说明远程服务的使用过程
远程服务与本地服务最大的区别是:远程Service与调用者不在同一个进程里(即远程Service是运行在另外一个进程);而本地服务则是与调用者运行在同一个进程里。
简单的来说就是本服务可以被非本进程调用,这样可以方便其他的应用或者进程来使用自己的服务,或者自己进程使用其他的服务,实现一个服务多个进程可以共享,节约了资源和空间。
下面以案例来说明远程的服务使用过程:
1.创建一个aidl:
并且里面加入一个函数(外部访问的):
2.创建服务,然后在里面的实现这个函数:
3.然后不断的输出data。
这样就完成了服务器端。
然后我们开始客户端:
获得到IAppServiceRemoteBinder的binder来调用函数setData,并且传值进去,这样就会修改服务器中的值了。
对了两个的都要有android提供的远程dial的文件,而且路径要保持一致:
这样就可以实现一个程序去调用另外一个程序的服务,通过dial。