1 Service简介
服务(Service) 是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要 和用户交互而且还要求长期运行的任务。服务的运行不依赖于任何用户界面,即使程序被切换到 后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。
服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在 的应用程序进程。当某个应用程序进程被杀掉时,所有依赖于该进程的服务也会停止运行。
服务并不会自动幵启线程,所有的代码都是 默认运行在主线程当中的。我们需要在服务的内部手动创建子线程,并在这里执行具 体的任务,否则就有可能出现主线程被阻塞住的情况。
2 Service的两种启动方式
1 使用Context 的startService(Intent)方法启动Service
- 步骤
- 定义一个类继承Service
- 在Manifest.xml文件中配置该Service
- 使用Context的startService(Intent)方法启动该Service
- 不再使用时,调用stopService(Intent)或者stopSelf()方法停止该服务
- 生命周期
onCreate()--->onStartCommand()(onStart()方法已过时)---> onDestory()
- 特点
- 如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStartCommand()。服务停止的时候调用 onDestory()。服务只会被停止一次。
2. 一旦服务开启跟调用者(开启者)就没有任何关系了。开启者退出了,开启者挂了,服务还在后台长期的运行。开启者不能调用服务里面的方法。
- 代码示例
Actiivity 中代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startService = findViewById(R.id.start_service);
Button stopService = findViewById(R.id.stop_services);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.start_service:
Intent startIntent=new Intent(this,MyService.class);
//开启服务
startService(startIntent);
break;
case R.id.stop_services:
Intent stopIntent=new Intent(this,MyService.class);
//结束服务
stopService(stopIntent);
break;
default:
break;
}
}
}
xml 中代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/start_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Service"/>
<Button
android:layout_marginTop="10dp"
android:id="@+id/stop_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Service"/>
</LinearLayout>
Service 中代码
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
/**
* @param intent
* @return
* Services中唯一一个抽象方法
*/
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
}
第一次点击启动服务
E/MyService: onCreate()
E/MyService: onStartCommand()
再次点击启动服务(注意多次调用startService(Intent)也只会存在一个服务实例)
E/MyService: onCreate()
E/MyService: onStartCommand()
E/MyService: onStartCommand()
停止服务
E/MyService: onCreate()
E/MyService: onStartCommand()
E/MyService: onStartCommand()
E/MyService: onDestroy()
2 使用Context 的bindService(Intent, ServiceConnection, int)方法启动Service
- 步骤
- 定义一个类继承Service
- 在Manifest.xml文件中配置该Service
- 使用Context的bindService(Intent, ServiceConnection, int)方法启动该Service
- 不再使用时,调用unbindService(ServiceConnection)方法停止该服务
- 生命周期
onCreate()--->onBind()---> onUnbind()---> onDestory()
- 特点
- 绑定服务不会调用onStart()或者onStartCommand()。
2. 用bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。绑定者可以调用服务里面的方法。
- 代码示例
Service 代码
public class MyService extends Service {
private static final String TAG = "MyService";
private MyBinder myBinder=new MyBinder();
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate()");
}
/**
* @param intent
* @return
* Services中唯一一个抽象方法
*/
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind()");
return myBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind()");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy()");
}
class MyBinder extends Binder implements IMyBinder{
@Override
public void proMethodInMyService() {
methodInMyService();
}
}
private void methodInMyService() {
Log.e(TAG, "服务里的方法执行了");
}
}
IMyBinder 接口代码
/**
* 用于保护服务中不想让外界访问的方法。
*/
public interface IMyBinder {
void proMethodInMyService();
}
MainActivity 代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private IMyBinder myBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bindService = findViewById(R.id.bind_service);
Button serviceMethod = findViewById(R.id.service_method);
Button unbindService = findViewById(R.id.unbind_service);
bindService.setOnClickListener(this);
serviceMethod.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.bind_service:
//绑定服务
Intent bindIntent=new Intent(this,MyService.class);
// 第一个参数是intent对象,表面开启的服务。
// 第二个参数是绑定服务的监听器
// 第三个参数一般为BIND_AUTO_CREATE常量,表示自动创建bind
bindService(bindIntent,connection,BIND_AUTO_CREATE);
break;
case R.id.service_method:
//调用服务中方法
myBinder.proMethodInMyService();
break;
case R.id.unbind_service:
//解绑服务
unbindService(connection);
break;
default:
break;
}
}
/**
* connection
* ServiceConnection 匿名类
*/
private ServiceConnection connection=new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//iBinder为服务里面onBind()方法返回的对象
myBinder = (IMyBinder) iBinder;
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
}
xml 代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/bind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Bind Service"/>
<Button
android:layout_marginTop="10dp"
android:id="@+id/service_method"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Service method"/>
<Button
android:layout_marginTop="10dp"
android:id="@+id/unbind_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Unbind Service"/>
</LinearLayout>
点击绑定服务
E/MyService: onCreate()
E/MyService: onBind()
点击调用方法
E/MyService: onCreate()
E/MyService: onBind()
E/MyService: 服务里的方法执行了
点击解绑服务
E/MyService: onCreate()
E/MyService: onBind()
E/MyService: 服务里的方法执行了
E/MyService: onUnbind()
E/MyService: onDestroy()
3 前台服务
服务的系统优先级比较低,当系统出现内存不足的情况时,就有可能会回收掉正在后台运行的服务。如果希望服务可以一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台服务。前台服务和普通服务最大的区别就在于,它会一直有一个正在运行的图标在系统的 状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。
- 代码示例
public class MyService extends Service {
private static final String TAG = "MyService";
private MyBinder myBinder=new MyBinder();
public MyService() {
}
/**
*
*/
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate()");
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();
// 第一个参数是通知的id
// 第二个参数是构建出的Notification对象
startForeground(1,notification);
}
/**
* @param intent
* @return
* Services中唯一一个抽象方法
*/
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind()");
return myBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind()");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy()");
}
class MyBinder extends Binder implements IMyBinder{
@Override
public void proMethodInMyService() {
methodInMyService();
}
}
private void methodInMyService() {
Log.e(TAG, "服务里的方法执行了");
}
}
4 IntentService
服务中的代码都是默认运行在主线程当中 的,如果直接在服务里去处理一些耗时的逻辑,就很容易出现ANR ( Application Not Responding ) 的情况。
1、 普通Service和Android 多线程结合
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
/**
* @param intent
* @return
* Services中唯一一个抽象方法
*/
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
new Thread(new Runnable() {
@Override
public void run() {
//处理具体逻辑
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
}
2 、使用IntentService
IntentService代码
public class MyIntentService extends IntentService {
private static final String TAG = "MyIntentService";
public MyIntentService() {
//调用父类的有参构造函数
super("MyIntentService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//打印当前线程id
Log.e(TAG, "Thread id is"+Thread.currentThread().getId());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy()");
}
}
MainActivity 代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startIntentService = findViewById(R.id.start_intent_service);
startIntentService.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.start_intent_service:
//开启服务
Log.e(TAG, "Thread id is"+Thread.currentThread().getId() );
Intent intentService =new Intent(this,MyIntentService.class);
startService(intentService);
break;
default:
break;
}
}
}
xml 代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_marginTop="10dp"
android:id="@+id/start_intent_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start IntentService"/>
</LinearLayout>
启动IntentService 打印结果
E/MainActivity: Thread id is1
E/MyIntentService: Thread id is4110
E/MyIntentService: onDestroy()
注:参考内容:1 https://www.jianshu.com/p/2fb6eb14fdec
2 郭霖《第一行代码》(第二版)