Android如何启动service
Posted 半夏茶白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android如何启动service相关的知识,希望对你有一定的参考价值。
启动service的两种方式
1. 通过StartService启动Service
通过startService启动后,service会一直无限期运行下去,
- 当外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁
- 当系统资源不足时, 会回收一些不重要的service,service被系统回收也会停止运行并被销毁
生命周期
-
onCreate()
1.如果service没被创建过,调用startService()后会执行onCreate()回调;
2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
此方法适合完成一些初始化工作。 -
onStartCommand()
如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。 -
onBind()
Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。 -
onDestory()
在销毁的时候会执行Service该方法。
代码实例
MyActivity.java
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动service
Intent mIntent=new Intent(MainActivity.this,MyService.class) ;
startService(mIntent);
MyServvice.java
public class MyService extends Service
private static final String TAG = "MyService";
private NotificationManager notificationManager;
private String notificationId = "channel_Id";
private String notificationName = "channel_Name";
public MyService()
@Override
public IBinder onBind(Intent intent)
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
@Override
public void 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()
Log.d(TAG, "onDestroy: ....");
super.onDestroy();
androidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iauto.demo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MainActivity ">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
></service>
<activity
android:name=".MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2. 通过bindService启动Service
bindService启动服务特点:
- bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
- client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
- bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁
生命周期
-
onCreate()
当服务通过onStartCommand()和onBind()被第一次创建的时候,系统调用该方法。该调用要求执行一次性安装。 -
onBind()
当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。 -
onUnbind()
当客户中断所有服务发布的特殊接口时,系统调用该方法。 -
onRebind()
当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。 -
onDestroy()
当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。
代码实例
MainAcivity.java
public class MainAcivity extends Activity
private Myservice = null;
private boolean isBind = false;
private ServiceConnection conn = new ServiceConnection()
@Override
public void onServiceConnected(ComponentName name, IBinder binder)
isBind = true;
TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder;
service = myBinder.getService();
int num = service.getRandomNumber();
@Override
public void onServiceDisconnected(ComponentName name)
isBind = false;
;
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
Intent intent = new Intent(this, TestTwoService.class);
intent.putExtra("from", "MainAcivity");
bindService(intent, conn, BIND_AUTO_CREATE);
@Override
protected void onDestroy()
super.onDestroy();
unbindService(conn);
MyService.java
public class MyService extends Service
//client 可以通过Binder获取Service实例
public class MyBinder extends Binder
public MyService getService()
return MyService .this;
//通过binder实现调用者client与Service之间的通信
private MyBinder binder = new MyBinder();
@Override
public void onCreate()
super.onCreate();
@Override
public int onStartCommand(Intent intent, int flags, int startId)
return START_NOT_STICKY;
@Nullable
@Override
public IBinder onBind(Intent intent)
return binder;
@Override
public boolean onUnbind(Intent intent)
return false;
@Override
public void onDestroy()
super.onDestroy();
//getRandomNumber是Service暴露出去供client调用的公共方法
public int getRandomNumber()
return generator.nextInt();
如何保证service不被杀死
之前说过:当系统资源不足时, 会回收一些不重要的service,service被系统回收也会停止运行并被销毁,那么如何保证service不被杀死呢
1. onStartCommand方式中,返回START_STICKY
表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY
2. 提高Service的优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低
*: 但是我在service中设置intent-filter,设置优先级build报错,有兴趣的可以另行查证
3. 提升Service进程的优先级
前台进程foreground_app优先级相对较高,可以将service设置为前台进程
代码实例:
MainActivity.java
package com.iauto.helloword;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 启动service
Intent mIntent=new Intent(MainActivity.this,MyService.class) ;
Log.d("activity", "onCreate: to start service");
startForegroundService(mIntent);
Log.d("activity", "onCreate: start service end");
finish();
MyService.java
package com.iauto.helloword;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.core.app.NotificationCompat;
public class MyService extends Service
private static final String TAG = "MyService";
private NotificationManager notificationManager;
private String notificationId = "channel_Id";
private String notificationName = "channel_Name";
public MyService()
@Override
public IBinder onBind(Intent intent)
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
@Override
public void onCreate()
Log.d(TAG, "onCreate: ...");
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
//创建NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
// 必须创建notifychannel, 不然会抛异常Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service
notificationManager.createNotificationChannel(channel);
startForeground(1, getNotification());
@Override
public int onStartCommand(Intent intent, int flags, int startId)
Log.d(TAG, "onStartCommand: ...");
return START_STICKY;
@Override
public void onDestroy()
Log.d(TAG, "onDestroy: ....");
super.onDestroy();
private Notification getNotification()
Notification.Builder builder = new Notification.Builder(this)
.setContentTitle("ScenarioEngineLite正在后台运行")
.setContentText("");
//设置Notification的ChannelID,否则不能正常显示
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
builder.setChannelId(notificationId);
Notification notification = builder.build();
return notification;
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iauto.helloword">
<!-- 必须设置以下权限,否则会抛异常RemoteException-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MainActivity"
android:persistent="true">
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
<!-- <intent-filter android:priority = "1000"/>-->
</service>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
4.在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。
5.系统广播监听Service状态
6.将APK安装到/system/app,变身为系统级应用
如何防止android应用中的service被系统回收
永不被kill是不可能的,android系统应用都有可能会被kill,不要说用户应用了,只能说被kill以后还能重新启动。Android中,当Service被kill后,如果重启需要使用BroadcastReceiver来实现,即广播接收者,例如利用BroadcastReceiver注册网络广播或者开关机广播,当接收到广播后直接启动service,这样就可以保证service被kill后,自动启动。
实现代码:
1.在配置文件AndroidManifest.xml中向系统注册BroadcastReceiver
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
2.需要添加相应权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
3.在Receiver中就可以添加开机,或者网络状态改变后需要进行的操作
public class BootCompletedReceiver extends BroadcastReceiver
@Override
public void onReceive(Context context, Intent intent)
4.执行操作,Intent intent = new Intent(context,Service.class); context.startService(intent); 这样即可开机,或者网络状态改变后启动Service了。 参考技术A 在service中重写下面的方法,这个方法有三个返回值, START_STICKY是service被kill掉后自动重写创建
@Override
public int onStartCommand(Intent intent, int flags, int startId)
// TODO Auto-generated method stub
Log.v("TrafficService","startCommand");
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
如何实现一个不会被杀死的进程
看Android的文档知道,当进程长期不活动,或系统需要资源时,会自动清理门户,杀死一些Service,和不可见的Activity等所在的进程。
但是如果某个进程不想被杀死(如数据缓存进程,或状态监控进程,或远程服务进程),应该怎么做,才能使进程不被杀死。
add android:persistent="true" into the <application> section in your AndroidManifest.xml
切记,这个不可滥用,系统中用这个的service,app一多,整个系统就完蛋了。
目前系统中有phone等非常有限的,必须一直活着的应用在试用。
如何防止Android应用中的Service被系统回收?
很多朋友都在问,如何防止Android应用中的Service被系统回收?下面简单解答一下。
对于Service被系统回收,一般做法是通过提高优先级可以解决,在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时实用于广播,推荐大家如果你的应用很重要,可以考虑通过系统常用intent action来触发。
以上是关于Android如何启动service的主要内容,如果未能解决你的问题,请参考以下文章