<持续更新中>:更新目录
- 声网后台保活策略和IntentService使用回调监听,解决Android 临时后台任务问题
声网类似问题,就是直播中关于声网退到后台无法发出声音,类似声网保活问题。从而引发创建后台,startForegroundService的问题如下:
Android 8.0以上如果使用service就会报“ Context.startForegroundService() did not then call Service.startForeground()”这个错,是因为Google限制了在调用了startForegroundService方法以后,5s内一定要调用startForeground方法,但是这个其实很难杜绝,因为每台设备情况不一样,如果手机卡一点,很可能就卡过这5s了,所以我们只能尽量减少。
1.不要在fragment里启动service,建议在mainActivity里启动,并且要成对的start和stop,在onDestroy()里stop。
2.在onCreate和onStartCommand都startForeground(),并且id不要用0。
网上的几点意见都用了但是还是在华为手机,出现偶发崩溃,因为华为强制杀死后台的系统机制,让人还是挺头大的。给出我的方案,但是很多问题
1. 由于Serveice不稳定,而且开启后台杀死困难,所以选择用IntentService替代
/**
* 后台服务,用于保持语音房,在后台服务不被回收
*/
class KeepAppLifeService : IntentService("KeepAppLifeService") {
override fun onHandleIntent(intent: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 注意notification也要适配Android 8 哦
startForeground(1, getNotification())
}
// 静音
FSAudioManager.getInstance()
.sound(SPUtils.getInstance().getBoolean(SPUtils.SwitchRef.IS_OPEN_SOUND, false))
//麦位静音处理
val user = AudioRoomManager.getInstance().userStates
user.entries.forEach {
if (it.value.isShut) {
FSAudioManager.getInstance().soundOne(it.key.toInt(), true)
}
}
}
private var notificationManager: NotificationManager? = null
private val notificationId = "keep_app_live"
private val notificationName = "keep_app_live_channel"
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
//创建NotificationChannel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
notificationId,
notificationName,
NotificationManager.IMPORTANCE_HIGH
)
//不震动
channel.enableVibration(false)
//静音
channel.setSound(null, null)
notificationManager?.createNotificationChannel(channel)
startForeground(1, getNotification())
}
}
/**
* 获取通知(Android8.0后需要)
*/
private fun getNotification(): Notification? {
val builder: Notification.Builder = Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentIntent(getIntent())
.setContentText(getString(R.string.text_on_keep_live))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId(notificationId)
}
return builder.build()
}
/**
* 点击后,直接打开app(之前的页面),不跳转特定activity
*/
@SuppressLint("UnspecifiedImmutableFlag")
private fun getIntent(): PendingIntent? {
val msgIntent =
applicationContext.packageManager.getLaunchIntentForPackage(packageName) //获取启动Activity
return PendingIntent.getActivity(
applicationContext,
1,
msgIntent,
PendingIntent.FLAG_UPDATE_CURRENT
)
}
}
2. 启动和关闭时机
通常我们需要一个这样的Activity管理和Application回掉
/**
* -----------
* Activity生命周期监听管理
* 在Application进行注册
* 包括功能:Activity活动列表管理,退出App
*/
public class ActivityLifecycleCallback implements Application.ActivityLifecycleCallbacks
根据这个我们就可以做计数,判断在前台还是后台操作
/**
* 根据getAppStatus,判断app状态
*/
public void getAppStatus(Activity activity) {
if (isForget == 0) {
//App进入后台或者APP锁屏了
//开启服务
LogUtils.i("KeepAppLifeService:开启服务");
//当前房间id
long roomId = AudioRoomManager.getInstance().getRoomId();
//如果当前在房间中 并且房间id != -1 开启服务
if(roomId != -1 && AudioRoomManager.getInstance() != null && AudioRoomManager.getInstance().isInRoom()){
if(App.getInstance() != null) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
App.getInstance().startForegroundService(new Intent(activity, KeepAppLifeService.class));
}else{
App.getInstance().startService(new Intent(activity, KeepAppLifeService.class));
}
}
}
} else {
//App进入前台
//结束服务
//停止Service
try {
LogUtils.i("KeepAppLifeService:结束服务");
Intent intentFour = new Intent(activity, KeepAppLifeService.class);
activity.stopService(intentFour);
} catch (Exception e) {
e.printStackTrace();
}
}
}
网友评论