Android面经


1、Activity

1.1、请介绍activity的生命周期

为了在activity生命周期的各个阶段之间导航转换activity提供了6个核心回调onCreate()onStart()onResume()onPause()onPause()onDestroy()。当activity进入到了新的状态时系统会调用每个回调。

在这里插入图片描述
这个图是对生命周期的直观展现。
当用户离开Activity时候系统会调用方法来销毁这个Activity。在某个情况下此销毁只是部分销毁Activity仍然驻留在内存中用户切换到了另一个应用并且可以返回到前台。若用户返回到该ActivityActivity会继续从用户离开位置运行。除了极少数例子app在后台运行时会受到很多限制无法启动Activity
系统终止给定进程及其中 Activity 的可能性取决于当时 Activity 的状态

1.1.1、生命周期回调之onCreate()

开发必须实现该回调会在系统首次创建Activity时候触发。Activity会在创建之后进入已经创建 的状态。在onCreate方法中需要执行基本应用的启动逻辑这个逻辑在Activity的整个生命周期中只发生一次。例如onCreate的实现可能会把某些数据绑定到列表中让Activity和ViewModel关联并且实例化某些类作用域的变量。该方法将会接收savedInstanceState参数后者是包含Activity之前保存状态的Bundle对象。若Activity之前不存在Bundle对象数值为null。

若有一个生命周期感知型组件和Activity生命周期关联则该组件将会收到ON_CREATE事件。系统调用带有@OnLifecycleEvent注释的方法让生命周期感知型组件可以执行已经创建状态所需的任何设置代码。

onCreate方法在示例中显示执行Activity某些基本设置的一些代码例如声明界面XML布局文件中定义、定义成员变量本示例中系统通过文件资源R.layout.main_activity传递给setContentView()指定XML布局文件。

lateinit var textView: TextView

// 活动实例的某个短暂状态
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // 调用超类onCreate来完成活动的创建比如视图层次结构
    super.onCreate(savedInstanceState)

    // 恢复实例状态
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // 设置该活动的用户界面布局布局文件在项目res/layout/main_activity.xml文件中定义
    setContentView(R.layout.main_activity)

    // 初始化成员TextView以便稍后操作它
    textView = findViewById(R.id.text_view)
}

// 这个回调只在有一个之前使用onSaveInstanceState()保存的实例时被调用。
// 我们在onCreate()中恢复一些状态而我们可以选择恢复
这里的其他状态可能在onStart()完成后可用。savedInstanceState Bundle与onCreate()中使用的Bundle相同。
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// 当activity可能被临时销毁时调用在这里保存实例状态
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // 调用父类保存任何视图层次结构
    super.onSaveInstanceState(outState)
}

不仅定义了XML文件将其传递给setContentView也可以在Activity中新建View对象并且把新建的View插入到ViewGroup中构建试图层次结构。把根ViewGroup传递给setContentView使用这个布局。

Activity 并未处于“已创建”状态。onCreate() 方法完成执行后Activity 进入“已开始”状态系统会相继调用 onStart() onResume() 方法。


1.1.2、生命周期回调之onStart()

当 Activity 进入“已开始”状态时系统会调用此回调。·onStart() ·调用使 Activity 对用户可见因为应用会为 Activity 进入前台并支持互动做准备。例如app通过此方法来初始化维护界面的代码。

当 Activity 进入已开始状态时与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_START事件。

onStart() 方法会非常快速地完成并且与“已创建”状态一样Activity 不会一直处于“已开始”状态。一旦此回调结束Activity 便会进入“已恢复”状态系统将调用 onResume() 方法。


1.1.3、生命周期回调之onResume()

Activity 会在进入“已恢复”状态时来到前台然后系统调用 onResume() 回调。这是应用与用户互动的状态。应用会一直保持这种状态直到某些事件发生让焦点远离应用。此类事件包括接到来电、用户导航到另一个 Activity或设备屏幕关闭。

Activity 进入已恢复状态时与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_RESUME事件。这时生命周期组件可以启用在组件可见且位于前台时需要运行的任何功能例如启动相机预览。

当发生中断事件时Activity 进入“已暂停”状态系统调用 onPause() 回调。

如果 Activity 从“已暂停”状态返回“已恢复”状态系统将再次调用 onResume() 方法。因此您应实现 onResume()以初始化在 onPause() 期间释放的组件并执行每次 Activity 进入“已恢复”状态时必须完成的任何其他初始化操作。
给出如下生命周期感知型组建的示例该组件在收到ON_RESUME事件访问相机

class CameraComponent : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
}

LifecycleObserver 收到 ON_RESUME 事件后上述代码便会初始化相机。然而在多窗口模式下即使处于“已暂停”状态Activity 也可能完全可见。例如当用户处于多窗口模式并点按另一个不包含 Activity 的窗口时 Activity 将进入“已暂停”状态。

  • 若希望相机仅在应用处于“已恢复”可见且在前台运行状态时可用请在收到上述 ON_RESUME 事件后初始化相机。
  • 若希望在 Activity 处于“已暂停”状态但可见时例如在多窗口模式下保持相机可用应在收到 ON_START 事件后初始化相机。

但请注意若要让相机在 Activity 处于“已暂停”状态时可用可能会导致系统在多窗口模式下拒绝其他处于“已恢复”状态的应用访问相机。
有时可能有必要让相机在 Activity 处于“已暂停”状态时保持可用但这样做实际可能会降低整体用户体验

无论正选择哪个构建事件中执行初始化操作请务必使用相应的生命周期事件来释放资源。若收到ON_START事件后初始化某些内容务必在收到ON_STOP事件后释放或者终止对应的内容。

注意上述代码段把相机初始化放置在生命周期感知型组件之中也可以直接把代码放入Activity生命周期回调例如onStartonStop但通常不建议这么做一般来说该逻辑应该添加到独立的组件中可以对多个Activity重复使用无需复制代码。


1.1.4、生命周期回调之onPause()

系统调用此方法视为用户将要离开Activity的第一个标记尽管这并不总以为着Activity会被销毁此方法表示Activity不再位于前台尽管用户处于多窗口模式时Activity仍然可见。使用 onPause() 方法暂停或调整当 Activity 处于“已暂停”状态时不应继续或应有节制地继续的操作。Activity 进入此状态的原因有很多。例如

  • 例如上述onResume所述某个事件会中断app执行。
  • 在 Android 7.0API 级别 24或更高版本中有多个应用在多窗口模式下运行。无论何时都只有一个应用窗口可以拥有焦点因此系统会暂停所有其他应用。
  • 有新的半透明 Activity例如对话框处于开启状态。只要 Activity 仍然部分可见但并未处于焦点之中它便会一直暂停。

当 Activity 进入已暂停状态时与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_PAUSE 事件。这时生命周期组件可以停止在组件未位于前台时无需运行的任何功能例如停止相机预览。

响应 ON_PAUSE 事件的以下 LifecycleObserver示例与上述 ON_RESUME 事件示例相对应会释放在收到 ON_RESUME 事件后初始化的相机

class CameraComponent : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
}

请注意上述代码段在 LifecycleObserver 收到 ON_PAUSE 事件后放置相机释放代码。

onPause() 执行非常简单而且不一定要有足够的时间来执行保存操作。因此不应使用 onPause()保存应用或用户数据、进行网络调用或执行数据库事务。因为在该方法完成之前此类工作可能无法完成。相反应在onStop()期间执行高负载的关闭操作。

onPause() 方法的完成并不意味着 Activity 离开“已暂停”状态。相反Activity 会保持此状态直到其恢复或变成对用户完全不可见。如果 Activity 恢复系统将再次调用onResume()回调。如果 Activity 从“已暂停”状态返回“已恢复”状态系统会让 Activity 实例继续驻留在内存中并会在系统调用 onResume() 时重新调用该实例。在这种情况下您无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。如果 Activity 变为完全不可见系统会调用 onStop()


1.1.5、生命周期回调之onStop()

如果Activity 不再对用户可见说明其已进入“已停止”状态因此系统将调用 onStop() 回调。例如当新启动的 Activity 覆盖整个屏幕时可能会发生这种情况。如果 Activity 已结束运行并即将终止系统还可以调用 onStop()

当 Activity 进入已停止状态时与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_STOP 事件。这时生命周期组件可以停止在组件未显示在屏幕上时无需运行的任何功能。

onStop()方法中应用应释放或调整在应用对用户不可见时的无用资源。例如应用可以暂停动画效果或从精确位置更新切换到粗略位置更新。使用 onStop() 而非onPause()可确保与界面相关的工作继续进行即使用户在多窗口模式下查看您的 Activity 也能如此。

可以使用 onStop() 执行 CPU 相对密集的关闭操作。例如若无法找到更合适的时机来将信息保存到数据库可以在 onStop() 期间执行此操作。以下示例展示了 onStop() 的实现它将草稿笔记内容保存到持久性存储空间中

override fun onStop() {
    // 首先调用超类方法
    super.onStop()

    // 保存笔记的当前草稿因为活动正在停止我们希望确保当前笔记的进度不会丢失。
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // 这个更新在后台的AsyncQueryHandler
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

注意上述代码示例直接使用了Sqlite数据库不过应该修改为ROOM这是一个通过SQLITE提供抽象层的持久性库。

当 Activity 进入“已停止”状态时Activity 对象会继续驻留在内存中该对象将维护所有状态和成员信息但不会附加到窗口管理器。Activity 恢复后Activity 会重新调用这些信息。无需重新初始化在任何回调方法导致 Activity 进入“已恢复”状态期间创建的组件。系统还会追踪布局中每个 View 对象的当前状态如果用户在 EditText 微件中输入文本系统将保留文本内容因此无需保存和恢复文本。

注意Activity 停止后如果系统需要恢复内存可能会销毁包含该 Activity 的进程。即使系统在 Activity 停止后销毁相应进程系统仍会保留 Bundle键值对的 blob中 View 对象例如 EditText 微件中的文本的状态并在用户返回 Activity 时恢复这些对象。

进入“已停止”状态后Activity 要么返回与用户互动要么结束运行并消失。如果 Activity 返回系统将调用 onRestart()。如果 Activity 结束运行系统将调用 onDestroy()


1.1.6、生命周期回调之onDestroy()

销毁Activity之前系统会调用onDestroy()系统调用该回调的原因如下

  • Activity即将结束了由于用户彻底关闭了Activity或者由于系统Activity调用了finish或者配置变更例如设备旋转或者多窗口模式系统暂时销毁Activity。

当 Activity 进入已销毁状态时与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_DESTROY 事件。这时生命周期组件可以在 Activity 被销毁之前清理所需的任何数据。

使用 ViewModel 对象来包含 Activity 的相关视图数据而不是在 Activity 中加入逻辑来确定 Activity 被销毁的原因。如果因配置变更而重新创建 ActivityViewModel 不必执行任何操作因为系统将保留 ViewModel 并将其提供给下一个 Activity 实例。如果不重新创建ActivityViewModel 将调用 onCleared() 方法以便在 Activity 被销毁前清除所需的任何数据。

也可以使用 isFinishing() 方法区分这两种情况。

如果 Activity 即将结束onDestroy() 是 Activity 收到的最后一个生命周期回调。如果由于配置变更而调用 onDestroy()系统会立即新建 Activity 实例然后在新配置中为新实例调用 onCreate()。
onDestroy() 回调应释放先前的回调例如 onStop()尚未释放的所有资源。


1.2、请介绍Activity四种启动模式及应用场景

基本描述

  • standard标准模式若在mainfest中不设置默认standardstandard就是创建一个Activity在栈中创建该Activity的实例。
  • singleTop栈顶复用模式和standard相比栈顶复用可以有效减少Activity重复创建对资源的消耗根据具体情况而定。
  • singleTask栈内单例模式栈内只有一个activity实例栈内已存activity实例在其他activity中start这个activityAndroid直接把这个实例上面其他activity实例踢出栈GC掉。
  • singleInstance 堆内单例整个手机操作系统里面只有一个实例存在就是内存单例。

1.2.1、四种启动模式的实际应用场景

这四种启动模式中的Standard模式是最普遍的一种没有什么特别注意。singleInstance模式是整个系统的单例模式应用中一般不会用到。

  • singleTask模式运用场景例如保持app开启之后仅仅只有一个activity实例展示Home主页假定用户在主页跳转到其他页面运行多次操作返回主页若不借助singleTask模式则点击返回过程中会多次看到主页设计不合理。
  • singleTop模式的运用场景设定当前activity中启动同类型的Activity那么建议把该类型的Activity的启动模式设定为SingleTop能够降低Activity创建的资源消耗
@Override
protected void onNewIntent(Intent intent) {
	super.onNewIntent(intent);
	setIntent(intent);
	initData();
	initView();
}

当前singleTop模式的Activity正处于栈顶时跳转该Activity会调用onNewintent方法且不会重新创建该Activity实例只会重新调用该实例生命周期为onPause->onNewIntent->onResume


1.3、请说下切换横竖屏时 Activity的生命周期变化

新建一个能打印生命周期的Activity并且运行

onCreate:
onStart:
onResume:

切换横屏

onConfigurationChanged: // 当Activity可能被销毁时回调供app暂存数据
onPause: 
onSaveInstanceState: 
onStop: 
onDestroy: 
onCreate: 
onStart: 
onRestoreInstanceState: // Activity被销毁后重新运行时回调
onResume:

切换竖屏

onConfigurationChanged: 
onPause: 
onSaveInstanceState: 
onStop: 
onDestroy: 
onCreate: 
onStart: 
onRestoreInstanceState: 
onResume: 
// 基于Android 7.0并没有见到传说中的调用两遍

为Activity添加属性android:configChanges=“orientation|screenSize”切换横屏

onConfigurationChanged:

现在只有一行**onConfigurationChanged:**了。
再切换竖屏

onConfigurationChanged:

总结

  • 不设置 Activity 的android:configChanges时切屏会重新调用各个生命周期切横屏时会执行一次切竖屏时会执行两次。
  • 设置 Activity 的 android:configChanges=“orientation|screenSize” 时切屏不会重新调用各个生命周期只会执行 onConfigurationChanged 方法。

android:configChanges 属性

VALUE                   DESCRIPTION  

"mcc"                   国际移动用户识别码所属国家代号是改变了
"mnc"                   国际移动用户识别码的移动网号码是改变了
"locale"                地址改变了-----用户选择了一个新的语言会显示出来
"touchscreen"           触摸屏是改变了------通常是不会发生的
"keyboard"              键盘发生了改变----例如用户用了外部的键盘
"keyboardHidden"        键盘的可用性发生了改变
"navigation"            导航发生了变化-----通常也不会发生
"screenLayout"          屏幕的显示发生了变化------不同的显示被激活
**加粗样式**"fontScale"             字体比例发生了变化----选择了不同的全局字体 
"uiMode"                用户的模式发生了变化
"orientation"           屏幕方向改变了
"screenSize"            屏幕大小改变了
"smallestScreenSize"    屏幕的物理大小改变了如连接到一个外部的屏幕上

以上是 android:configChanges 属性的所有值。当我们希望一种或者多种配置改变时避免重新启动 activity。就可以通过在 AndroidManifest 中设置 android:configChanges 属性来实现。如下所示

<activity
    android:name=".XXXActivity"
    android:configChanges="XXX|XXX"/>

我们可以在这里声明 activity 可以处理的任何配置改变当这些配置改变时不会重新启动activity而会调用 onConfigurationChanged() 方法。如果改变的配置中包含了你所无法处理的配置在android:configChanges并未声明activity 仍然要被重新启动。


1.3.1、onSaveInstanceState() 和 onRestoreInstanceState() 方法

基本作用

注意Activity的 onSaveInstanceState() onRestoreInstanceState() 并不是生命周期方法它们不同于 onCreate()、onPause()等生命周期方法并不一定会被触发。

若app遇到了意外情况例如内存不足、按下了Home返回键由系统去销毁一个Activity时onSaveInstanceState会被调用但是当用户主动去销毁一个Activity时例如app中按下了返回键则该方法不会被调用。通常onSaveInstanceState() 只适合用于保存一些临时性的状态而onPause()适合用于数据的持久化保存。

具体到应用中当我们想切换横竖屏时候保存视频的播放进度可以在Activity中重写onSaveInstanceState(Bundle outState) 方法调用 outState.putXXX()来保存数据紧接着在Activity重新被创建的时候onCreate(Bundle savedInstanceState) onRestoreInstanceState(Bundle savedInstanceState) 中 调用 savedInstanceState.getXXX() 来获取数据。

  • onRestoreInstanceState()什么时候调用
    onRestoreInstanceState() 被调用的前提是activity A “确实” 被系统销毁了且 activity A 被重新创建。当 activity A 未被重新创建时该方法不会被调用。例如当正在显示 activity A 的时候用户按下 HOME 键回到主界面然后用户紧接着又返回到 activity A这种情况下 activity A 一般不会因为内存的原因被系统销毁故 onRestoreInstanceState() 方法不会被执行, 这也证明这两个方法不一定会成对被使用。
    onRestoreInstanceState() 在 onStart() 和 onResume() 之间调用。

  • 是否需要重写onSaveInstanceState()方法
    如果我们没有覆写 onSaveInstanceState() 方法 此方法的默认实现会自动保存 activity 中的某些状态数据,比如 activity 中各种 UI 控件的状态.。android 应用框架中定义的几乎所有 UI 控件都恰当的实现了onSaveInstanceState() 方法因此当 activity 被摧毁和重建时这些 UI 控件会自动保存和恢复状态数据.比如 EditText 控件会自动保存和恢复输入的数据。而 CheckBox 控件会自动保存和恢复选中状态。开发者只需要为这些控件指定一个唯一的 ID (通过设置 android:id 属性即可)剩余的事情就可以自动完成了.如果没有为控件指定 ID 则这个控件就不会进行自动的数据保存和恢复操作。


2、Service

service中文名称是服务服务是Android中实现程序后台运行的解决方案它非常适合去执行那些不需要和用户交互而且还要长期运行的任务。

2.1、请介绍Service的启动方式启动方式的区别

service有两种启动方式一种是通过 startService() 来启动的另一种是通过 bindService() 来启动的。

通过startService启动方式的生命周期如下图

在这里插入图片描述

使用service如下

  • 定义一个类继承Service
  • 在AndroidMainfest中配置该service
  • 使用Context的startService方法启动Service
  • 不适用这个服务时调用了stopService方法停止Service。

注意若服务已经开启则不会重复执行onCreate而是调用onStart或者onStartCommand而服务停止的时候调用onDestroy()

特点

  • 一旦服务开始就跟启动者没关系了。
  • 开启者推出之后服务还是可以在后台保持长期的运行前提是没有调用stopService(Intent)
  • 开启者不能够调用服务里面的方法。

通过bindService来启动

通过bindService启动方式的生命周期如下
在这里插入图片描述

使用Service的步骤如下

  • 定义一个类并继承 Service
  • AndroidManifest.xml 中配置此 Service
  • 使用 Context 的 bindService(Intent, ServiceConnection, int) 方法来启动此 Service
  • 不使用该服务时调用 unbindService(ServiceConnection) 方法停止此 Service。

绑定服务 不会调用onStart或者onStartCommand方法。

特点

  • bind方式开启服务绑定服务若调用者挂了服务service也会挂掉。
  • 绑定者可以调用服务里面的方法。

下面通过具体的代码来展示Activity如何管理service其生命周期具体的变化

启动服务startService

23:42:02.003 1173-1173/? I/MyService: onCreate
23:42:02.003 1173-1173/? I/MyService: onStartCommand

注意多次调用startService方法onCreate就只会调用一次但是onStartCommand会调用多次。

停止服务stopService

23:45:17.443 1292-1292/com.yirong.androidpractice I/MyService: onDestroy

注意在调用bindService之后就算再次调用stopService也无法停止服务了必须首先解绑才可以。

绑定服务bindService

bindService(intent,this, Context.BIND_AUTO_CREATE)
stopService(intent)
00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onCreate
00:09:38.653 1361-1361/com.yirong.androidpractice I/MyService: onBind

注意bindService不会调用·onStart·方法。

解绑服务unbindService

00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onUnbind
00:10:40.882 1411-1411/com.yirong.androidpractice I/MyService: onDestroy

2.2、Activity、Service、intent之间的联系

首先从通俗易懂的角度来解释

  • 他们都是 Android 开发中使用频率最高的类。其中 Activity 和 Service 都是 Android 四大组件之一。他俩都是Context 类的子类 ContextWrapper 的子类因此他俩可以算是兄弟关系吧。不过兄弟俩各有各自的本领Activity负责用户界面的显示和交互Service 负责后台任务的处理。Activity 和 Service 之间可以通过 Intent 传递数据因此可以把 Intent 看作是通信使者。

2.2.1、概述Android Service和Activity之间通信的几种方式

在Android整体系统中Activity主要负责前台页面的展示Service主要负责需要长期运行的任务一般在Activity中启动后台Service并且通过Intent来启动intent可以传递数据给Service

  • Intent意图主要是解决Android中各个组件之间的通讯问题负责对app中一次操作的动作、动作涉及到数据、附加数据的描述Android根据Intent的描述负责找到对应的组件把Intent传递给调用的组件完成组件的调用。

Activity之间常见的跳转代码

Intent intent = new Intent(MainActivity.this,DemoActivity.class);
startActivity(intent);
//startActivity(new Intent(MainActivity.this,DemoActivity.class));

上面的代码实现了MainActivity和DemoActivity之间的跳转其中一个就是startActivity(Intent intent)使用方式就是传入一个Intent对象封装好意图之后通过如图所示流程
在这里插入图片描述


3、在Activity和Service中创建Thread的区别

  • 首先默认情况下Service运行在主线程中若要执行复杂的耗时操作则必须在Service中创建一个thread来执行任务。

  • Service 优先级高于后台挂起的Acitivity并且高于Acitivity创建的thread所以系统在内存不足的时候会优先杀死后台Activity或者Thread而不会轻易杀死Service组件即使被迫杀死Service也会在资源可用时重启被杀死的Service 其实Service和Thread根本就不是一个级别的东西Service是系统的四大组件之一Thread只是一个用来执行后台任 务的工具类它可以在Activity中被创建也可以在Service中被创建。因此我们其实不应该讨论该使用Service还是 Thread而是应该讨论在什么地方创建Thread

    • 在Activitiy中创建这种情况下一般在onCreate时创建在onDestroy()中销毁否则Activity销毁后Thread是会依然在后台运行着。这种情况下Thread的生命周期即为整个Activity的生命周期。所以在Activity中创建的Thread只适合完成一些依赖 Activity本身有关的任务比如定时更新一下Activity的控件状态等。
    • 核心特点该Thread的就是为这个Activity服务的完成这个特定的Activity交代的任务主动通知该Activity一些消息和 事件Activity销毁后该Thread也没有存活的意义了。
  • 在Application中被创建 这种情况下一般自定义Application类重载onCreat方法并在其中创建Thread当然也会在onTerminate()方法 中销毁Thread否则如果Thread没有退出的话即使整个Application退出了线程依然会在后台运行着。这种情况下Thread的生命周期即为整个Application的生命周期。所以在Application中创建的Thread可以执行一 些整个应用级别的任务比如定时检查一下网络连接状态等等。

    • 核心特点该Thread的终极目标是为这个APP的各个Activity服务的包括完成某个Activity交代的任务主动通知某个 Activity一些消息和事件等APP退出之后该Thread也没有存活的意义了。以上这两种情况下Thread的生命周期都不应该超出整个应用程序的生命周期也就是整个APP退出之后Thread都应该完全退出这样才不会出现内存泄漏或者僵尸线程。那么如果你希望整个APP都退出之后依然能运行该Thread 那么就应该把Thread放到Service中去创建和启动了。

4、android进程的优先级以及如何保证Service不被杀死

service服务是Android系统中非常重要的组件。Service可以脱离app运行也就是说app只是负责启动Service。

一旦Service启动就算app关闭其依旧可以在后台运行Android的Service主要有两个作用后台运行跨进程通讯
若想要app可以跨进程通讯就需要使用AIDL服务全称就是Android Interface Definition Language也就是说AIDL实际上是一种Android接口定义语言通过这种语言定义的接口Android studio会在编译后生成相应的Java代码。

4.1、在onStartCommand方法中返回START_STICKY

StartCommand中几个常量

  • START_STICKY 系统重新创建服务并且调用onStartCommand()方法但并不会传递最后一次传递的intent只是传递一个空的intent。除非存在将要传递来的intent那么就会传递这些intent。这个适合播放器一类的服务不需要执行命令只需要独自运行等待任务。
  • START_REDELIVER_INTENT 系统重新创建服务并且调用onStartCommand()方法传递最后一次传递的intent。其余存在的需要传递的intent会按顺序传递进来。这适合像下载一样的服务立即恢复积极执行。

4.2、通过前台服务来提升Service的优先级

前台服务是被认为用于已知的正在运行的服务当系统需要释放内存时不会优先杀掉该进程。前台进程必须发一个notification在状态栏中显示知道进程被杀死。因为前台服务一直消耗一部分资源但不像一般服务那样会在需要的时候被杀掉所以为了节约资源保护电池寿命一定要在建前台服务的时候发送notification提示用户。当然系统提供的方法就必须有notification参数的所以不要想着怎么把notification隐藏掉。

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onCreate() {
    super.onCreate();
    Log.d(TAG, "onCreate: 已执行");
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    Notification notification = new Notification.Builder(this)
            .setContentTitle("这是内容标题")
            .setContentText("这是内容正文")
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
            .setContentIntent(pendingIntent)
            .build();
    startForeground(1, notification);   //前台服务
}

4.3、在onDestroy中发送广播让广播来开启自己

服务+广播方式 就是当service调用到onDestroy的时候发送一个自定义的广播当收到广播的时候重新启动service

    <receiver
        android:name=".MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.peterli.localservicetest.destroy"/>
        </intent-filter>
    </receiver>

在service中onDestroy的时候

@Override
public void onDestroy() {
    Log.d(TAG, "onDestroy: ");
    stopForeground(true);  //有前台服务的时候把这句话加上
    Intent intent = new Intent("com.peterli.localservicetest.destroy");
    sendBroadcast(intent);
    super.onDestroy();
}
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android