欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Android 8.0以上系統(tǒng)應(yīng)用如何保活

 更新時間:2019年08月26日 15:18:48   作者:xiangzhihong8  
這篇文章主要介紹了詳解Android 8.0以上系統(tǒng)應(yīng)用如何?;?,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

最近在做一個埋點的sdk,由于埋點是分批上傳的,不是每次都上傳,所以會有個進(jìn)程?;畹臋C(jī)制,這也是自研推送的實現(xiàn)技術(shù)之一:如何保證Android進(jìn)程的存活。

對于Android來說,保活主要有以下一些方法:

  • 開啟前臺Service(效果好,推薦)
  • Service中循環(huán)播放一段無聲音頻(效果較好,但耗電量高,謹(jǐn)慎使用)
  • 雙進(jìn)程守護(hù)(Android 5.0前有效)
  • JobScheduler(Android 5.0后引入,8.0后失效)
  • 1 像素activity?;罘桨福ú煌扑])
  • 廣播鎖屏、自定義鎖屏(不推薦)
  • 第三方推送SDK喚醒(效果好,缺點是第三方接入)

下面是具體的實現(xiàn)方案:

1.監(jiān)聽鎖屏廣播,開啟1個像素的Activity

最早見到這種方案的時候是2015年,有個FM的app為了向投資人展示月活,在Android應(yīng)用中開啟一個1像素的Activity。

由于Activity的級別是比較高的,所以開啟1個像素的Activity的方式就可以保證進(jìn)程是不容易被殺掉的。

具體來說,定義一個1像素的Activity,在該Activity中動態(tài)注冊自定義的廣播。

class OnePixelActivity : AppCompatActivity() {

  private lateinit var br: BroadcastReceiver

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //設(shè)定一像素的activity
    val window = window
    window.setGravity(Gravity.LEFT or Gravity.TOP)
    val params = window.attributes
    params.x = 0
    params.y = 0
    params.height = 1
    params.width = 1
    window.attributes = params
    //在一像素activity里注冊廣播接受者  接受到廣播結(jié)束掉一像素
    br = object : BroadcastReceiver() {
      override fun onReceive(context: Context, intent: Intent) {
        finish()
      }
    }
    registerReceiver(br, IntentFilter("finish activity"))
    checkScreenOn()
  }

  override fun onResume() {
    super.onResume()
    checkScreenOn()
  }

  override fun onDestroy() {
    try {
      //銷毀的時候解鎖廣播
      unregisterReceiver(br)
    } catch (e: IllegalArgumentException) {
    }
    super.onDestroy()
  }

  /**
   * 檢查屏幕是否點亮
   */
  private fun checkScreenOn() {
    val pm = this@OnePixelActivity.getSystemService(Context.POWER_SERVICE) as PowerManager
    val isScreenOn = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
      pm.isInteractive
    } else {
      pm.isScreenOn
    }
    if (isScreenOn) {
      finish()
    }
  }
}

2, 雙進(jìn)程守護(hù)

雙進(jìn)程守護(hù),在Android 5.0前是有效的,5.0之后就不行了。首先,我們定義定義一個本地服務(wù),在該服務(wù)中播放無聲音樂,并綁定遠(yuǎn)程服務(wù)

class LocalService : Service() {
  private var mediaPlayer: MediaPlayer? = null
  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 {
    //播放無聲音樂
    if (mediaPlayer == null) {
      mediaPlayer = MediaPlayer.create(this, R.raw.novioce)
      //聲音設(shè)置為0
      mediaPlayer?.setVolume(0f, 0f)
      mediaPlayer?.isLooping = true//循環(huán)播放
      play()
    }
    //啟用前臺服務(wù),提升優(yōu)先級
    if (KeepLive.foregroundNotification != null) {
      val intent2 = Intent(applicationContext, NotificationClickReceiver::class.java)
      intent2.action = NotificationClickReceiver.CLICK_NOTIFICATION
      val notification = NotificationUtils.createNotification(this, KeepLive.foregroundNotification!!.getTitle(), KeepLive.foregroundNotification!!.getDescription(), KeepLive.foregroundNotification!!.getIconRes(), intent2)
      startForeground(13691, notification)
    }
    //綁定守護(hù)進(jìn)程
    try {
      val intent3 = Intent(this, RemoteService::class.java)
      this.bindService(intent3, connection, Context.BIND_ABOVE_CLIENT)
    } catch (e: Exception) {
    }

    //隱藏服務(wù)通知
    try {
      if (Build.VERSION.SDK_INT < 25) {
        startService(Intent(this, HideForegroundService::class.java))
      }
    } catch (e: Exception) {
    }

    if (KeepLive.keepLiveService != null) {
      KeepLive.keepLiveService!!.onWorking()
    }
    return Service.START_STICKY
  }

  private fun play() {
    if (mediaPlayer != null &amp;&amp; !mediaPlayer!!.isPlaying) {
      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 &amp;&amp; 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()
    }
  }
}

然后再定義一個遠(yuǎn)程服務(wù),綁定本地服務(wù)。

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是Android從5.0增加的支持一種特殊的任務(wù)調(diào)度機(jī)制,可以用它來實現(xiàn)進(jìn)程?;?,不過在Android8.0系統(tǒng)中,此種方法也失效。

首先,我們定義一個JobService,開啟本地服務(wù)和遠(yuǎn)程服務(wù)。

@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) //執(zhí)行的最小延遲時間
        builder.setOverrideDeadline(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS) //執(zhí)行的最長延時時間
        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) // 當(dāng)插入充電器,執(zhí)行該任務(wù)
      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)
      }
    }
    //啟動本地服務(wù)
    val localIntent = Intent(context, LocalService::class.java)
    //啟動守護(hù)進(jìn)程
    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,提高Service優(yōu)先級

在onStartCommand()方法中開啟一個通知,提高進(jìn)程的優(yōu)先級。注意:從Android 8.0(API級別26)開始,所有通知必須要分配一個渠道,對于每個渠道,可以單獨設(shè)置視覺和聽覺行為。然后用戶可以在設(shè)置中修改這些設(shè)置,根據(jù)應(yīng)用程序來決定哪些通知可以顯示或者隱藏。

首先,定義一個通知工具類,此工具欄兼容Android 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)
  }
}

5,Workmanager方式

Workmanager是Android JetPac中的一個API,借助Workmanager,我們可以用它來實現(xiàn)應(yīng)用餓?;?。使用前,我們需要依賴Workmanager庫,如下:

implementation "android.arch.work:work-runtime:1.0.0-alpha06"

Worker是一個抽象類,用來指定需要執(zhí)行的具體任務(wù)。

public class KeepLiveWork extends Worker {
  private static final String TAG = "KeepLiveWork";

  @NonNull
  @Override
  public WorkerResult doWork() {
    Log.d(TAG, "keep-> doWork: startKeepService");
    //啟動job服務(wù)
    startJobService();
    //啟動相互綁定的服務(wù)
    startKeepService();
    return WorkerResult.SUCCESS;
  }
}

然后,啟動keepWork方法,

  public void startKeepWork() {
    WorkManager.getInstance().cancelAllWorkByTag(TAG_KEEP_WORK);
    Log.d(TAG, "keep-> dowork startKeepWork");
    OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(KeepLiveWork.class)
        .setBackoffCriteria(BackoffPolicy.LINEAR, 5, TimeUnit.SECONDS)
        .addTag(TAG_KEEP_WORK)
        .build();
    WorkManager.getInstance().enqueue(oneTimeWorkRequest);

  }

關(guān)于WorkManager,可以通過下面的文章來詳細(xì)了解:WorkManager淺談

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Anroid ListView分組和懸浮Header實現(xiàn)方法

    Anroid ListView分組和懸浮Header實現(xiàn)方法

    這篇文章主要介紹了Anroid ListView分組和懸浮Header實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2016-11-11
  • Android優(yōu)化之啟動頁去黑屏實現(xiàn)秒啟動

    Android優(yōu)化之啟動頁去黑屏實現(xiàn)秒啟動

    本文的內(nèi)容主要是講Android啟動頁優(yōu)化,去黑屏實現(xiàn)秒啟動的功能,有需要的小伙伴們可以參考學(xué)習(xí)。
    2016-08-08
  • 詳解Android壁紙服務(wù)的啟動過程

    詳解Android壁紙服務(wù)的啟動過程

    你有設(shè)置過手機(jī)的壁紙嗎,你知道壁紙是什么樣的程序它是怎么在后臺運行的嗎?這篇文章主要介紹了詳解Android系統(tǒng)壁紙服務(wù)的啟動過程
    2021-08-08
  • Android仿qq消息拖拽效果

    Android仿qq消息拖拽效果

    這篇文章主要為大家詳細(xì)介紹了Android仿qq消息拖拽效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • android尺子的自定義view——RulerView詳解

    android尺子的自定義view——RulerView詳解

    這篇文章主要介紹了android尺子的自定義view——RulerView詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • Android 中Volley二次封裝并實現(xiàn)網(wǎng)絡(luò)請求緩存

    Android 中Volley二次封裝并實現(xiàn)網(wǎng)絡(luò)請求緩存

    這篇文章主要介紹了Android 中Volley二次封裝并實現(xiàn)網(wǎng)絡(luò)請求緩存的相關(guān)資料,希望通過本文能幫助到大家,徹底會使用Volley,需要的朋友可以參考下
    2017-09-09
  • Android 使用 RxJava2 實現(xiàn)倒計時功能的示例代碼

    Android 使用 RxJava2 實現(xiàn)倒計時功能的示例代碼

    本篇文章主要介紹了Android 使用 RxJava2 實現(xiàn)倒計時功能的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • 如何從外部瀏覽開啟Android App

    如何從外部瀏覽開啟Android App

    從瀏覽器中點擊某個按鈕,如果手機(jī)上裝有相應(yīng)的app,則直接開啟app,并且到相對的頁面。如果沒有裝該app,則會到相應(yīng)的下載app的界面。這樣的功能怎么實現(xiàn)呢,本文帶著大家來看看如何實現(xiàn)。
    2021-06-06
  • Android使用Gallery實現(xiàn)照片拖動的特效

    Android使用Gallery實現(xiàn)照片拖動的特效

    這篇文章主要介紹了Android如何使用Gallery實現(xiàn)照片拖動的特效,幫助大家更好的理解和利用Android進(jìn)行開發(fā),感興趣的朋友可以了解下
    2021-01-01
  • Flutter實現(xiàn)PopupMenu彈出式菜單按鈕詳解

    Flutter實現(xiàn)PopupMenu彈出式菜單按鈕詳解

    這篇文章主要介紹了Flutter實現(xiàn)PopupMenu彈出式菜單按鈕,PopupMenuButton是一個用于創(chuàng)建彈出菜單的小部件,當(dāng)用戶點擊觸發(fā)按鈕時,PopupMenuButton會在屏幕上方或下方彈出一個菜單,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05

最新評論