Android基础:Service

    xiaoxiao2025-08-26  54

    Service简介

    1 服务的介绍

    service是在后台运行的,没有界面的android组件之一。

    2 进程的分类

    进程分为5类,按照级别的高低依次为: 1 前台进程:Foreground Process,正在进行交互的进程,相当于activity执行了onResume()。 2 可视进程:Visible Process 可见不可交互,相当于activity执行了onPause()。 3 服务进程:Service Process 开启了startService() 4 后台进程:Background Process 相当于activity执行了onStop()。 5 空进程:Empty Process 进程中没有任何组件在运行。

    3 service的开启方式

    2种:startService() + bindService()

    3-1 startSercice()方式开启服务,其生命周期的特点

    1.方法调用顺序:开启:(Activity)startSercice()–>(Service)onCreate()–>(Service)onStartCommand(){内部调用onStart()};关闭:stopService()–>onDestroy(); 2.多次调用startSercice(),onCreate()只执行一次,但onStartCommand()+onStart()执行多次 3.服务一直会在后台运行,除非调用调用stopService或手动停止。

    3-2 bindService()方式开启服务,其生命周期的特点

    1.方法的调用顺序:bindService()–>onCreate()–>onBind();unBindService()–>onUnbind()–>onDestroy()。 2.多次调用bindService(),onCreate() + onBind()只会执行一次。 3.可以绑定多次,但解绑只有一次,若多次解绑,会报错:没有注册service。 4.service与绑定者是同生共死的关系。 5.通过bindService()开启服务,在手机设置界面是找不到的。 6.如果onBind()方法返回null,那么onServiceConnection()是不执行的。

    4 为什么引入bindService()这种方法

    为了引用service里面的方法。

    Demo验证

    验证上面的3-1

    startService(intent)方式开启service,可以多次调用startService(intent),service的onCreate()只会执行一次,但onStartCommon()和onStart()会执行多次。stopService(intent)也可以被调用多次,但onDestroy()只会执行一次。

    private void initViews() { btn1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startService(intent); } }); btn2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { stopService(intent); } }); } public class DemoService extends Service { private static final String TAG = "DemoService"; @Override public void onCreate() { Log.d(TAG, "onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onStart(Intent intent, int startId) { Log.d(TAG, "onStart"); super.onStart(intent, startId); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { return null; } }

    源码:https://git.oschina.net/ServiceDemo/StartServiceDemo

    验证上面的3-2

    bindService(intent):绑定 unBindService(intent):解绑

    bindService(intent)方式开启service,可以绑定多次,但解绑只有一次,多次解绑会报错。 多次绑定,onCreate()+onBind()只执行一次。

    private void initViews() { btn1.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { bindService(intent, conn, BIND_AUTO_CREATE); } }); btn2.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { unbindService(conn); } }); } private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { } @Override public void onServiceConnected(ComponentName name, IBinder service) { } }; public class DemoService extends Service { private static final String TAG = "DemoService"; @Override public void onCreate() { Log.d(TAG, "onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onStart(Intent intent, int startId) { Log.d(TAG, "onStart"); super.onStart(intent, startId); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind"); return null; } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnbind"); return super.onUnbind(intent); } }

    源码:https://git.oschina.net/ServiceDemo/BindServiceDemo

    怎么判断service1在不在运行中?

    /** * 判断某个服务是否正在运行的方法 * @param mContext * @param serviceName 是包名+服务的类名(例如:com.cqc.servicedemo01.Service1) * @return true代表正在运行,false代表服务没有正在运行 */ public boolean isServiceWork(Context mContext, String serviceName) { boolean isWork = false; ActivityManager myAM = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningServiceInfo> myList = myAM.getRunningServices(80); if (myList.size() <= 0) { return false; } for (int i = 0; i < myList.size(); i++) { String mName = myList.get(i).service.getClassName().toString(); if (mName.equals(serviceName)) { isWork = true; break; } } return isWork; }

    service保活

    在实际开发中,我们会遇到一些要求后台运行的service,但是现在Android手机型号太多,而且国内的系统都是各大厂商定制过得,加入了自己的一些优化设置(比如省电方面的)。造成的的问题是:当service在后台运行一段时间后,如果是比较耗电,会被系统kill,service里的逻辑操作也就停止了,对我们的业务造成困扰。那么该如何处理呢?

    主要有2种方法:手动设置和代码设置混合使用

    手动设置

    在手机设置界面中,有锁屏保护和省电管理或者手机管家中的内存优化都要进行处理。

    锁屏保护

    在360F4手机中,在设置–>电池和省电–>锁屏受保护应用:选中我们自己的app,就想选中微信一样,如果不选中微信的话,锁屏30分钟后,微信也会被kill掉。不同的手机锁屏后kill掉app的时间是不同的,有的没有这一项设置,有的是几分钟,360F4手机是30分钟。见下图:

    省电管理

    这类App一般都是系统自带的,都是品牌商自己的软件,为了时间省电优化,通常都会把后台运行的app杀死,而且权限还挺高。不过也有用于自己安装的,比如:360手机卫士、腾讯手机管家、猎豹清理大师等,各种app的优化设置不同,这里介绍几个常见的

    360手机卫士

    我–>设置–>清理加速–>内存加速优化名单–>把我们的app加入优化忽略名单中

    OPPO手机管家

    待定

    代码设置

    这也有2种方法: 1. 给serviceA在配置一个守护它的serviceB,当我们的serviceA被杀死后,我们可以serviceB再重新开启A, 2. 注册BroadcastReceiver,锁屏时获取“电源锁”,屏幕解锁是释放“电源锁”

    增加一个守护的service

    原理:在这个serviceB中开启一个Thread,每个1分钟查找正在运行的service,如果没有serviceA,那么久开启serviceA;如果有serviceA,那么就做处理。

    public class MonitorService extends Service { protected static boolean isCheck = false; protected static boolean isRunning = false; private static final String SERVICE_NAME = "com.cqc.walelock01.WakeLockService"; @Override public void onCreate() { Log.d("MonitorService2", "MonitorService onCreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("MonitorService2", "MonitorService onStartCommand"); new Thread() { @Override public void run() { while (isCheck) { try { Thread.sleep(5 * 60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); Log.d("MonitorService2", "thread sleep failed" ); } if (!isServiceWork(getApplicationContext(), SERVICE_NAME)) { Log.d("MonitorService2", "WakeLockService轨迹服务已停止,正在重启轨迹服务"); startService(new Intent(MonitorService.this, WakeLockService.class)); } else { Log.d("MonitorService2", "WakeLockService轨迹服务正在运行"); } } } }.start(); return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } /** * 判断某个服务是否正在运行的方法 * * @param mContext * @param serviceName 是包名+服务的类名(例如:com.baidu.trace.LBSTraceService) * @return true代表正在运行,false代表服务没有正在运行 */ public boolean isServiceWork(Context mContext, String serviceName) { boolean isWork = false; ActivityManager myAM = (ActivityManager) mContext .getSystemService(Context.ACTIVITY_SERVICE); List<RunningServiceInfo> myList = myAM.getRunningServices(80); if (myList.size() <= 0) { return false; } for (int i = 0; i < myList.size(); i++) { String mName = myList.get(i).service.getClassName().toString(); if (mName.equals(serviceName)) { isWork = true; break; } } return isWork; } }

    WakeLock :电源锁

    注册广播,当锁屏时获取电源锁,当屏幕解锁时释放电源锁,

    public class TrackReceiver extends BroadcastReceiver { private static final String TAG = "TrackReceiver"; @SuppressLint("Wakelock") @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (Intent.ACTION_SCREEN_OFF.equals(action)) { Log.d(TAG,"screen off,acquire wake lock!"); if (null != WakeLockService.wakeLock && !(WakeLockService.wakeLock.isHeld())) { WakeLockService.wakeLock.acquire(); } } else if (Intent.ACTION_SCREEN_ON.equals(action)) { Log.d(TAG,"screen on,release wake lock!"); if (null != WakeLockService.wakeLock && WakeLockService.wakeLock.isHeld()) { WakeLockService.wakeLock.release(); } } } }

    获取电源锁是需要权限的

    <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.DEVICE_POWER"/> 第二个权限AS会红色提示“这是系统app需要的权限”,这是提示不是报错,添加上就可以了

    BroadcastReceiver有2种注册方法:静态注册和动态注册。 我么这里采用动态注册的方法,原因是:

    receiver应该跟随serviceA的生命周期,当serviceA被销毁后,将不再获取电源锁;service开启后,再根据屏幕的变化判断是获取还是释放电源锁

    public class WakeLockService extends Service { //cpu保活 private static boolean isRegister = false; protected static PowerManager pm = null; public static PowerManager.WakeLock wakeLock = null; public static TrackReceiver trackReceiver = new TrackReceiver(); @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { //动态注册 if (!isRegister) { if (null == pm) { pm = (PowerManager) getSystemService(Context.POWER_SERVICE); } if (null == wakeLock) { wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "track upload"); } IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); registerReceiver(trackReceiver, filter); isRegister = true; } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); if (isRegister) { try {//销毁广播 unregisterReceiver(trackReceiver); isRegister = false; } catch (Exception e) { } } } }

    这个service保活是从百度鹰眼官方Demo中提取的。 网址:http://lbsyun.baidu.com/index.php?title=android-yingyan/guide/tracelive

    让service在前台运行

    把service设置成前台进程:

    Notification notification = new Notification.Builder(this).build(); startForeground(1, notification);

    把service的前台进程销毁:

    stopForeground(true);

    Android进程保活招式大全

    Android进程保活招式大全 Demo: http://git.oschina.net/ServiceDemo/WakeLock01 其他相关: Android的PowerManager和PowerManager.WakeLock用法简析 使用WakeLock使Android应用程序保持后台唤醒 Service在后台长期运行的解决方案

    Service与Activity之间的传值

    把值放在Application中用SharePreferences存取值activity中利用intent存值,在service的onStartCommand(…)中取值 intent.putExtra("orderCode", "123456"); startService(intent); @Override public int onStartCommand(Intent intent, int flags, int startId) { String orderCode = intent.getStringExtra("orderCode"); return super.onStartCommand(intent, flags, startId); }
    转载请注明原文地址: https://ju.6miu.com/read-1301999.html
    最新回复(0)