Android应用保活实践(1)

mediaPlayer?.start()
}
}

private inner class MyBilder : GuardAidl.Stub() {

@Throws(RemoteException::class)
override fun wakeUp(title: String, discription: String, iconRes: Int) {

}
}

private val connection = object : ServiceConnection {

override fun onServiceDisconnected(name: ComponentName) {
val remoteService = Intent(this@LocalService,
RemoteService::class.java)
this@LocalService.startService(remoteService)
val intent = Intent(this@LocalService, RemoteService::class.java)
this@LocalService.bindService(intent, this,
Context.BIND_ABOVE_CLIENT)
}

override fun onServiceConnected(name: ComponentName, service: IBinder) {
try {
if (mBilder != null && KeepLive.foregroundNotification != null) {
val guardAidl = GuardAidl.Stub.asInterface(service)
guardAidl.wakeUp(KeepLive.foregroundNotification?.getTitle(), KeepLive.foregroundNotification?.getDescription(), KeepLive.foregroundNotification!!.getIconRes())
}
} catch (e: RemoteException) {
e.printStackTrace()
}

}
}

override fun onDestroy() {
super.onDestroy()
unbindService(connection)
if (KeepLive.keepLiveService != null) {
KeepLive.keepLiveService?.onStop()
}
}
}

定义一个远程服务,绑定本地服务。

class RemoteService : Service() {

private var mBilder: MyBilder? = null

override fun onCreate() {
super.onCreate()
if (mBilder == null) {
mBilder = MyBilder()
}
}

override fun onBind(intent: Intent): IBinder? {
return mBilder
}

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
try {
this.bindService(Intent(this@RemoteService, LocalService::class.java),
connection, Context.BIND_ABOVE_CLIENT)
} catch (e: Exception) {
}
return Service.START_STICKY
}

override fun onDestroy() {
super.onDestroy()
unbindService(connection)
}

private inner class MyBilder : GuardAidl.Stub() {
@Throws(RemoteException::class)
override fun wakeUp(title: String, discription: String, iconRes: Int) {
if (Build.VERSION.SDK_INT < 25) {
val intent = Intent(applicationContext, NotificationClickReceiver::class.java)
intent.action = NotificationClickReceiver.CLICK_NOTIFICATION
val notification = NotificationUtils.createNotification(this@RemoteService, title, discription, iconRes, intent)
this@RemoteService.startForeground(13691, notification)
}
}
}

private val connection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName) {
val remoteService = Intent(this@RemoteService,
LocalService::class.java)
this@RemoteService.startService(remoteService)
this@RemoteService.bindService(Intent(this@RemoteService,
LocalService::class.java), this, Context.BIND_ABOVE_CLIENT)
}

override fun onServiceConnected(name: ComponentName, service: IBinder) {}
}

}

/**

  • 通知栏点击广播接受者
    */
    class NotificationClickReceiver : BroadcastReceiver() {

companion object {
const val CLICK_NOTIFICATION = “CLICK_NOTIFICATION”
}

override fun onReceive(context: Context, intent: Intent) {
if (intent.action == NotificationClickReceiver.CLICK_NOTIFICATION) {
if (KeepLive.foregroundNotification != null) {
if (KeepLive.foregroundNotification!!.getForegroundNotificationClickListener() != null) {
KeepLive.foregroundNotification!!.getForegroundNotificationClickListener()?.foregroundNotificationClick(context, intent)
}
}
}
}
}

#####3.JobScheduler
JobScheduler和JobService是安卓在api 21中增加的接口,用于在某些指定条件下执行后台任务。

定义一个JobService,开启本地服务和远程服务

@SuppressWarnings(value = [“unchecked”, “deprecation”])
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class JobHandlerService : JobService() {

private var mJobScheduler: JobScheduler? = null

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
var startId = startId
startService(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mJobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val builder = JobInfo.Builder(startId++,
ComponentName(packageName, JobHandlerService::class.java.name))
if (Build.VERSION.SDK_INT >= 24) {
builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS) //执行的最小延迟时间
builder.setOverrideDeadline(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS) //执行的最长延时时间
builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS)
builder.setBackoffCriteria(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS, JobInfo.BACKOFF_POLICY_LINEAR)//线性重试方案
} else {
builder.setPeriodic(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS)
}
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
builder.setRequiresCharging(true) // 当插入充电器,执行该任务
mJobScheduler?.schedule(builder.build())
}
return Service.START_STICKY
}

private fun startService(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (KeepLive.foregroundNotification != null) {
val intent = Intent(applicationContext, NotificationClickReceiver::class.java)
intent.action = NotificationClickReceiver.CLICK_NOTIFICATION
val notification = NotificationUtils.createNotification(this, KeepLive.foregroundNotification!!.getTitle(), KeepLive.foregroundNotification!!.getDescription(), KeepLive.foregroundNotification!!.getIconRes(), intent)
startForeground(13691, notification)
}
}
//启动本地服务
val localIntent = Intent(context, LocalService::class.java)
//启动守护进程
val guardIntent = Intent(context, RemoteService::class.java)
startService(localIntent)
startService(guardIntent)
}

override fun onStartJob(jobParameters: JobParameters): Boolean {
if (!isServiceRunning(applicationContext, “com.xiyang51.keeplive.service.LocalService”) || !isServiceRunning(applicationContext, “$packageName:remote”)) {
startService(this)
}
return false
}

override fun onStopJob(jobParameters: JobParameters): Boolean {
if (!isServiceRunning(applicationContext, “com.xiyang51.keeplive.service.LocalService”) || !isServiceRunning(applicationContext, “$packageName:remote”)) {
startService(this)
}
return false
}

private fun isServiceRunning(ctx: Context, className: String): Boolean {
var isRunning = false
val activityManager = ctx
.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val servicesList = activityManager
.getRunningServices(Integer.MAX_VALUE)
val l = servicesList.iterator()
while (l.hasNext()) {
val si = l.next()
if (className == si.service.className) {
isRunning = true
}
}
return isRunning
}
}

#####4.播放无声音乐
这里使用的是有声的mp3文件,只是在代码中把声音设置成了0;如果使用真正的无声的音乐文件,在oppo手机上按下返回键会被立刻杀死,并且在三星手机,华为nova2s强制杀死也会被杀死,所有使用了有声的文件。

#####5.提高Service优先级
onStartCommand()方法中开启一个通知,提高进程的优先级。注意:从Android 8.0(API级别26)开始,所有通知必须要分配一个渠道,对于每个渠道,可以单独设置视觉和听觉行为。然后用户可以在设置中修改这些设置,根据应用程序来决定哪些通知可以显示或者隐藏。

定义一个通知工具类,兼容8.0

class NotificationUtils(context: Context) : ContextWrapper(context) {

private var manager: NotificationManager? = null
private var id: String = context.packageName + “51”
private var name: String = context.packageName
private var context: Context = context
private var channel: NotificationChannel? = null

companion object {
@SuppressLint(“StaticFieldLeak”)
private var notificationUtils: NotificationUtils? = null

fun createNotification(context: Context, title: String, content: String, icon: Int, intent: Intent): Notification? {
if (notificationUtils == null) {
notificationUtils = NotificationUtils(context)
}
var notification: Notification? = null
notification = if (Build.VERSION.SDK_INT >= 26) {
notificationUtils?.createNotificationChannel()
notificationUtils?.getChannelNotification(title, content, icon, intent)?.build()
} else {
notificationUtils?.getNotification_25(title, content, icon, intent)?.build()
}
return notification
}
}

@RequiresApi(api = Build.VERSION_CODES.O)
fun createNotificationChannel() {
if (channel == null) {
channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_MIN)
channel?.enableLights(false)
channel?.enableVibration(false)
channel?.vibrationPattern = longArrayOf(0)
channel?.setSound(null, null)
getManager().createNotificationChannel(channel)
}
}

private fun getManager(): NotificationManager {
if (manager == null) {
manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
return manager!!
}

@RequiresApi(api = Build.VERSION_CODES.O)
fun getChannelNotification(title: String, content: String, icon: Int, intent: Intent): Notification.Builder {
//PendingIntent.FLAG_UPDATE_CURRENT 这个类型才能传值
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return Notification.Builder(context, id)
.setContentTitle(title)
.setContentText(content)
.setSmallIcon(icon)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
}

fun getNotification_25(title: String, content: String, icon: Int, intent: Intent): NotificationCompat.Builder {
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
return NotificationCompat.Builder(context, id)
.setContentTitle(title)
.setContentText(content)
.setSmallIcon(icon)
.setAutoCancel(true)
.setVibrate(longArrayOf(0))
.setSound(null)
.setLights(0, 0, 0)
.setContentIntent(pendingIntent)
}
}

###使用
将保活的功能封装成了一个单独的库,依赖该库即可。

app中使用:

KeepLive.startWork(this, KeepLive.RunMode.ROGUE, ForegroundNotification(“Title”, “message”,
R.mipmap.ic_launcher, object : ForegroundNotificationClickListener {
override fun foregroundNotificationClick(context: Context, intent: Intent) {
//点击通知回调

}
}), object : KeepLiveService {
override fun onStop() {
//可能调用多次,跟onWorking匹配调用
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司21年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

1年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

[外链图片转存中…(img-8RpiCnZv-1712556130693)]

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值