Android 面试题 应用程序结构 九

news/2024/5/17 11:09:59

🔥 核心应用程序  Activity五个状态🔥

Starting-> running-> paused-> stopped-> killed

  • 启动状态(Starting):Activity的启动状态很短暂,当Activity启动后便会进入运行状态(Running)。
  • 运行状态(Running):Activity在此状态时处于屏幕最前端,它是可见、有焦点的,可以与用户进行交互。如单击、长按等事件。即使出现内存不足的情况,Android也会先销毁栈底的Activity,来确保当前的Activity正常运行。
  • 暂停状态(Paused):在某些情况下,Activity对用户来说仍然可见,但它无法获取焦点,用户对它操作没有没有响应,此时它处于暂停状态。
  • 停止状态(Stopped):当Activity完全不可见时,它处于停止状态,但仍然保留着当前的状态和成员信息。如系统内存不足,那么这种状态下的Activity很容易被销毁。
  • 销毁状态(Destroyed):当Activity处于销毁状态时,将被清理出内存。
  • 还有一种情况由于系统内存不足可能在Paused状态中直接被系统杀死达到killed状态。

🔥 核心应用程序   五个状态生命周期图  🔥

🔥 核心应用程序  activity的生命周期  🔥

oncreate()->onstart()->onResume()->onRestart()->onPouse()->onStop()->onDestory()

在这里插入图片描述

 🔥 核心应用程序 Activity横竖屏生命周期 🔥

横竖屏切换涉及到的是Activity的android:configChanges属性;
android:configChanges可以设置的属性值有:

1、orientation:消除横竖屏的影响

2、keyboardHidden:消除键盘的影响

3、screenSize:消除屏幕大小的影响

public class MainActivity extends AppCompatActivity {
public static final String TAG=“MainActivity”;@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.i(TAG,"onCreate");setContentView(R.layout.activity_main);
}@Override
protected void onStart() {super.onStart();Log.i(TAG,"onStart");
}@Override
protected void onResume() {super.onResume();Log.i(TAG,"onResume.........");
}@Override
protected void onPause() {super.onPause();Log.i(TAG,"onPause");
}@Override
protected void onStop() {super.onStop();Log.i(TAG,"onStop");
}@Override
protected void onDestroy() {super.onDestroy();Log.i(TAG,"onDestroy");
}

运行Activity,生命周期如下:

onCreate -> onStart -> onResume

切换横屏,生命周期如下:

onPause -> onStop -> onSaveInstanceState -> onDestroy  

onCreate -> onStart -> onRestoreInstanceState -> onResume

再切回竖屏,生命周期如下:

onPause -> onStop -> onSaveInstanceState -> onDestory 

onCreate -> onStart -> onRestoreInstanceState -> onResume

修改AndroidManifest.xml,添加android:configChanges="orientation"并切换横屏,生命周期如下:

onPause -> onStop -> onSaveInstanceState -> onDestory 

onCreate -> onStart -> onRestoreInstanceState -> onResume

再切换竖屏,生命周期如下:

onPause -> onStop -> onSaveInstanceState -> onDestory 

onCreate -> onStart -> onRestoreInstanceState -> onResume

修改AndroidManifest.xml,属性改为android:configChanges=“orientation|keyboardHidden|screenSize”,切换横屏,生命周期如下:

执行函数  onConfigurationChanged()

再切换回竖屏 , 生命周期如下:

执行函数  onConfigurationChanged()

结论 : 

设置Activity的android:configChanges属性为orientation或者orientation|keyboardHidden或者不设置这个属性的时候,横竖屏切换会重新调用各个生命周期方法,切横屏时会执行1次,切竖屏时会执行1次;
设置Activity的属性为android:configChanges="orientation|keyboardHidden|screenSize"时,横竖屏切换不会重新调用各个生命周期方法,只会执行onConfigurationChanged方法;

 🔥 Activity的管理方式 🔥

Android系统可以运行多个app , App也可以包含多个Activity , Activity 是用任务栈的方式进行管理的。

任务栈是与用户交互的页面顺序,但与 App 不是 一对一的关系,Android 根据 Activity 的 launchMode 和 taskAffinity 等属性,管理 Acticity 的栈归属

 任务栈内 Activity 的顺序不可更改,遵循入栈弹栈(先进后出)的管理原则

 🔥 启动模式 Standard 🔥

Standard 启动模式是 App 默认的启动模式。在 AndroidManifest.xml 文件中,不对 activity 的 launchMode 参数进行设置,这个 activity 就会以 standard 模式启动。

 在 Android 中,点击桌面图标,首次启动 App,创建应用的 LaunchActivity A,然后点击一个按钮,跳到另一个 Activity B,这时候,Activity A 的状态会被保留,且压入任务栈中,Activity B 会被创建,并且显示在任务栈顶。

如果 app 中有 activity A、B、C,且都是以 standard 模式启动,那么,多次页面跳转后,它的堆栈可能变成:

A - B - C - B - B - C - C - A - C

只要开启新 Activity 就会创建,进栈。然后触发页面返回操作时,按顺序一一回退页面。 

🔥 singleTop 启动模式  🔥 

在 App 中,详情页中可能存在其他物品的详情页链接,用户大概率会点击进入下一个详情链接,然后详情链接内又有详情链接,当浏览了十来个物品后,想回到最初的列表页,需要疯狂点击返回按钮。避免这种情况,则可以使用 singleTop 的启动模式 —— 当栈顶已经是详情页时,再次打开一个详情页,不会重新创建页面,只会回调当前页面的 onPause ->onNewIntent 传递新的 Intent -> onResume

class SingleTopActivity : AppCompatActivity() {private val idKey = "id"private lateinit var textView: TextViewoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_launch)initViews()updateIntent()}override fun onNewIntent(intent: Intent?) {super.onNewIntent(intent)// 更新 intentsetIntent(intent)// 重新设置页面内容updateIntent()}private fun initViews() {textView = findViewById(R.id.tv_title)textView.setOnClickListener {startActivity(Intent(this, SingleTopActivity::class.java).apply {putExtra(idKey, intent.getIntExtra(idKey, 0) + 1)})}}private fun updateIntent() {val id = intent.getIntExtra(idKey, 0)textView.setText("get id: $id")}
}

如果 app 中有 activity A、B、C,其中 B 的模式启动为 singleTop, A、C 为 standard,那么,页面跳转情况如下:

启动 A: A
启动 B: A - B
启动 C: A - B - C
启动 C: A - B - C - C
启动 B: A - B - C -C - B
启动 B: A - B - C -C - B*

表示没有重新创建页面实例,但调用了 newIntent 进行更新

只有当 singleTop 模式的 Activity 存在于栈顶时,Activity 的表现与 standard 不同

🔥 启动模式 singleInstancePerTask 🔥 

最适合作为 MainActivity 的启动模式

App 主页的需求为:

  1. App 的第一个页面

  2. 后续页面不需要启动新的主页,只需回退到主页

这意味着:

  1. 该 Activity 处于栈底

  2. 栈中只会存在一个该 Activity 实例

因而 singleInstancePerTask 最适合作为 MainActivity 的启动模式

在 standard 和 singleTop 的启动模式下,activity 可以存在多个实例,位于栈中的任何地方。但 singleInstancePerTask 在一个栈中,只会有一个实例。即:

如果 app 中有 activity A、B 、C,其中 B 的模式启动为 singleInstancePerTask,A、C 为 standard,那么,页面跳转情况如下:

启动 A: A
启动 B: A -> 切换栈 -> B
启动 C: A | B - C
启动 A: A | B - C- A
启动 B: A | B*
返回:A

在实际应用中,A - SplashActivity、LaunchActivity; B - MainActivity;C - 普通页面

如果 没有主动将 Activity A finish ,在 Activity B 中返回上一个页面,会切换回 Activity A;或者在处于 Activity B 任务栈时,回到桌面,系统会自动关闭 Activity A 所在的隐藏栈。

在 Android 12 以下版本,设置后无效,等同于 standard 模式

🔥 启动模式 SingleTask 🔥 

singleTask 与 singleInstancePerTask 的区别

在没有 singleInstancePerTask 模式之前,singleTask 是 MainActivity 启动模式首选,二者的区别在于:

  • singleTask 可以处在栈中的任意位置,而 singleInstancePerTask 只能处于栈底

  • singleTask 在 Android 中,只会有一个实例(startActivity 时,没有则创建,有则调起所在的栈,并回退到该 activity,同时回调 onNewIntent ),而 singleInstancePerTask 可以搭配 flag,在多个栈中有不同实例(可以有两个栈同时以该 Activity 为栈底)

  • singleInstancePerTask 会在系统已存在没有该实例的同 taskAffinity 任务栈时,重新开启一个栈,而 singleTask 则会直接在该栈顶创建 Activity

 如果 app 中有 activity A、B 、C,其中 B 的模式启动为 singleTask,A、C 为 standard,那么,页面跳转情况如下:

启动 A: A
启动 B: A - B
启动 C: A - B - C
启动 A: A - B - C- A
启动 B: A - B*

A - SplashActivity、LaunchActivity; B - MainActivity;C - 普通页面。在 Android 12 之前的实际应用中,需要通过代码来控制 Activity A 的自动跳转和关闭:

override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 判断是否处于栈底(首次启动)if (isTaskRoot) {// 跳转到真正的启动页面startActivity(Intent(this, MainActivity::class.java))}finish()
}

 从桌面点击 icon 唤醒后台 App 时,如果 MainActivity 为 singleTask 模式,会创建 SplashActivity,置于原本栈顶,然后回调到 onCreate 中,finish SplashActivity,显示原本任务栈。而如果 MainActivity 为 singleInstancePerTask 启动模式,则不会有创建 SplashActivity 的流程,直接将已存在的 MainActivity 为根的任务栈唤醒到前台。

当将 MainActivty 作为 LanchActivity ,且启动模式为 SingleTask 时,可能存在 bug

 🔥 singleInstance 启动模式 🔥

singleInstance 在 Android 中,也不会存在第二个实例,且 singleInstance 的栈中,有且只有这一个 Activity( 不会继续叠加新的 )

如果 app 中有 activity A、B 、C,其中 B 的模式启动为 singleTask,A、C 为 standard,那么,页面跳转情况如下:

启动 A: A
启动 B: A -> 切换栈 -> B(前台栈)
返回:B(onDestroy 销毁) -> 切换栈 -> A
启动 B: A -> 切换栈 -> B(前台栈)
启动 C: B (后台栈)| A - C(前台栈,显示 C)
返回 : B (后台栈) | A(前台栈,显示 A)
返回 : B(显示 B)

 当启动 singleInstance 的 Activity 时,会切换到新的任务栈,在 singleInstance 中启动 Activity 时,如果原本任务栈还存在,会回到原本任务栈,否则启动新任务栈;当回到原本任务栈时,原本的任务栈会变成前台任务栈,只有前台任务栈全部退出时,才会显示 singleInstance 所在的任务栈(即 singleInstance 的 Activity 会在最后显示)

如果此间插入 回桌面 的操作,那么两个任务栈的联系会被取消,singleInstance 的任务栈处于后台状态,不会再次返回前台,下次启动该 Activity 时,没有创建新的 Activity,只会回调 onNewIntent(如果后台任务栈没有被系统销毁)

启动 A: A
启动 B: A -> 切换栈 -> B(前台栈)
启动 C: B -> 切换栈 -> (A - )C(前台栈)
回桌面:B(后台栈);A - C (后台栈)
点击桌面图标:A - C
返回 : A
返回 : 桌面
点击桌面图标,启动 A:A
启动 B: A -> 切换栈 -> B*(前台栈,调用 onNewIntent)

🔥 App 间的相互跳转 🔥 

Android 的桌面(Launcher),实质上是一个 App。点击桌面图标启动 App,就是从一个 App 跳转到另一个 App 的过程

 当点击 launcher 中的图标时,会调用 startActivity 启动对应 APP 的 AndroidManifest 中注册的 LaunchActivity,且设置了 flag: Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS (api 28)。不同android 版本设置的 flag 不同,但本质上,都是启动对应 App 的 LaunchActivity,或者将 LaunchActivity 所在的任务栈调回前台。

 此时,如果 LaunchActivity 的 launchMode 被设置为 singleTask,在 LaunchActivity 所在任务栈回调到前台的同时,任务栈会回退到 LaunchActivity,并回调 onNewIntent。即,每次从桌面点击图标回到 App 页面,都相当于重启 App。因而,不建议将 MainActivity 作为 LaunchActivity 的同时,还将其 launchMode 设置为 singleTask(或者singleInstancePerTask) ,而是通过添加一个 SplashActivity 作为 LaunchActivity 的方式,区分 App 启动页和 App 主页。

处于启动优化考虑,让用户无感知跳转启动页面,可将 SplashActivity 和 MainActivity 的 window 背景设置为相同的启动页。 

 如果一定要将 MainActivity 设置为 LaunchActivity,请移除 singleTask 的 launchMode 设置,并通过跳转时设置 intentFlag,来实现回到首页功能。

val startMain = Intent(this, MainActivity::class.java)
startMain.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(startMain)

如果将 MainActivity 设置为 LaunchActivity,launchMode 为 standard,在正常系统调用时,没有问题。但如果其他应用,只是简单地 将暴露出去的 launchActivity 作为 intent 启动了,那么 App 的所有 Activity,都会被加载入调起此 App 的原始 App 的堆栈

 🔥 任务栈 和 App 对应关系 🔥

任务栈 和 App 不是一一对应的关系 , 一个 App,可以有多个任务栈

上文提到,只有 singleInstance 会启动独立任务栈。这个任务栈,在任务管理器中,是隐形状态,但在任务管理器中看不到 task,不意味着不存在。这个隐形栈内的 Activity,如果被用户切出之后(开启新的 Activity),除了完全退出当前任务栈,无法返回;且如果回到桌面在通过任务栈或者桌面图标调起应用,完全无法回到该 Activity。但在内存不吃紧时,这个隐形栈依旧存在于内存中,下次启用该 Activity 时,直接回调 onNewIntent。

 任务管理器显示 task,主要根据是 AndroidManifest 中一个重要属性 taskAffinity 。没有明确设置时,这个值默认为包名。所以当各种会开启新任务栈的 launchMode 被设置后,而 taskAffinity 又冲突了,那么,处于后台的 task 会被隐藏。

 设置了 taskAffinity 后,可以对 App 的不同 Activity 进行 task 分组。但是,只有会发生 任务栈切换的 task,此配置才有效,即,standard 模式的 activity,设置了 taskAffinity 之后,依旧只会在当前 task 叠加和删除。

 如果 singleInstance 启动模式的 taskAffinity 和其他 taskAffinity 设置为一样的,应用行为没有设置时的冲突状态一致。

 一个任务栈内,可以显示多 App 的 Activity

前面说到 standard 模式下,不会发生切栈效果,即便是开启了其他 app 的 Activity。

1、新建一个 APP A, manifest 中配置:

<!-- exported 必须为 true-->
<activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><intent-filter><!-- 配置 action 为 view, category 为 DEFAULT, 将 activity 暴露给其他 APP 调用 --><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /></intent-filter>
</activity>

2、在设备中,运行 APP A。

3、新建 APP B,启用上方定义的 MainActivity:

findViewById<Button>(R.id.btn_action).setOnClickListener {// 会弹出设备中所有暴露出了 action 为 view 的 Activity 的 应用列表,选中之前的 APP A// 也可通过添加 scheme 的方式指定到当前 app,可自行了解val intent = Intent(Intent.ACTION_VIEW)startActivity(intent)// 也可通过 componentName 直接指定打开的 activity,但 activity 不存在的话会崩溃// val componentName = ComponentName("app.package.name", "app.package.name.ActivityA")// startActivity(Intent().apply { setComponent(componentName) })
}

4、打开任务管理器,会发现在 APP B 的任务堆栈中,存在 APP A 的 Activity:

 

 因而,暴露出去给其他 App 唤醒的 Activity,如可能被推广页调起的详情,或者启动页面,如果不想被加载进其他 App 的栈,需 将暴露出去,可能被其他 App 调起的 Activity 设置为 singleTask 启动模式(固定在自身 app 任务栈上显示)

如果需要 启动其他 App 暴露的 Activity,且不希望将 Activity 加载在自身栈内,在 intent 中添加 flag:FLAG_ACTIVITY_NEW_TASK

 🔥 Service简介 🔥

Service 是一个可以在后台执行长时间运行操作而不提供用户界面的应用组件。服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。

    Service是一个可以在后台执行长时间操作而不使用用户界面的应用组件。那么问题来了,既然它不使用用户界面,那么它怎么知道应该什么时候开始执行什么操作呢?答案是——它可以与其他的引用组件形成一些联系,从而可以根据其传来的信息在合适的时候执行合适的操作。

🔥 Service的启动方式 🔥 

Service的启动方式主要有两种,分别是startService和bindService。其中,startService使用的是同一个Service,因此onStart()会执行多次,onCreate()只执行一次,onStartCommand()也会执行多次。使用bindService启动时,onCreate()与onBind()都只会调用一次。

使用startService启动时是单独开一个服务,与Activity没有任何关系,而bindService方式启动时,Service会和Activity进行绑定,当对应的activity销毁时,对应的Service也会销毁。

🔥 Service的生命周期 🔥 

 

startService 

onCreate():如果service没被创建过,调用startService()后会执行onCreate()回调;如果service已处于运行中,调用startService()不会执行onCreate()方法。

onStartCommand():多次执行了Context的startService()方法,那么Service的

onStartCommand()方法也会相应的多次调用。

onBind():Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。

onDestory():在销毁Service的时候该方法。

bindService 

启动的服务和调用者之间是典型的Client-Server模式。调用者是client,Service则是Server端。Service只有一个,但绑定到Service上面的Client可以有一个或很多个。bindService启动服务的生命周期与其绑定的client息息相关。

1)首先,在Service的onBind()方法中返回IBinder类型的实例。

2)onBInd()方法返回的IBinder的实例需要能够返回Service实例本身

3、.Service 的 onStartCommand 方法返回值所代表的含义

1)START_NOT_STICKY

在执行完 onStartCommand 后,服务被异常 kill 掉,系统不会自动重启该服务。

2)START_STICKY

重传 Intent。使用这个返回值时,如果在执行完 onStartCommand 后,服务被异 常 kill 掉,系统会自动重启该服务 ,并且onStartCommand方法会执行,onStartCommand方法中的intent值为null。适用于媒体播放器或类似服务。

3)START_REDELIVER_INTEN

使用这个返回值时,服务被异 常 kill 掉,系统会自动重启该服务,并将 Intent 的值传入。适用于主动执行应该立即恢复的作业(例如下载文件)的服务。

 🔥 IntentService 🔥

1、IntentService 是 Service 的子类

默认开启了一个工作线程HandlerThread,使用这个工作线程逐一处理所有启动请求,在任务执行完毕后会自动停止服务。只要实现一个方法 onHandleIntent,该方法会接收每个启动请求的 Intent,能够执行后台工作和耗时操作。可以启动IntentService 多次,而每一个耗时操作会以队列的方式在 IntentService 的 onHandlerIntent回调方法中执行,并且,每一次只会执行一个工作线程,执行完第一个再执行第二个。并且等待所有消息都执行完后才终止服务。

 2、IntentService原理

1)创建一个名叫 ServiceHandler 的内部 Handler

2)把内部Handler与HandlerThread所对应的子线程进行绑定

3)HandlerThread开启线程 创建自己的looper

4)通过 onStartCommand() intent,依次插入到工作队列中,并发送给 onHandleIntent()逐个处理可以用作后台下载任务 静默上传

3、与Service的区别

IntentService会创建独立的worker线程来处理所有的Intent请求 Service主线程不能处理耗时操作,IntentService不会阻塞UI线程,而普通Serveice会导致ANR异常。为Service的onBind()提供默认实现,返回null;onStartCommand提供默认实现,将请求Intent添加到队列中。所有请求处理完成后,IntentService会自动停止,无需调用stopSelf()方法停止Service。

 🔥 Service两种启动方式的区别 🔥

第一个不同:
        通过start()直接启动服务:
        服务一旦开启,就与调用者没有任何关系,调用者的activity即使退出,也不会影响后台服务的运行。

        通过bindService()绑定服务,启动的服务:
        通过绑定方式开启的服务,服务跟调用者不求同生但求同死。如果调用者的activity退出了,那她绑定的服务也会跟着退出。
        注意:如果一个程序的activity绑定了服务,那么这个activity退出时,会报异常,说是服务没有被释放。
        那么我们可以重写activity的onDestory方法,方法内调用unbindService(),去显示的解除与服务的绑定。

第二个不同点:
         Start直接启动服务的方法,调用者不能调用服务内部的方法。

         绑定服务启动服务的方法,调用者可以调用服务内部的方法;
         利用serviceConnection接口获取服务onbind返回的ibinder对象,
         这个对象同时实现了自定义的接口,这个接口内定义了服务中的方法。

 🔥 保证Service不被杀死 🔥

使用startForeground()方法,将Service设置为前台Service,这样系统就不会将其杀死;

使用AlarmManager定时唤醒Service,保证Service不会被杀死; 

使用JobScheduler来定时执行任务,保证Service不会被杀死; 

在AndroidManifest.xml中添加android:persistent="true"属性,让Service在系统重启后仍然存在;

在AndroidManifest.xml中添加android:stopWithTask="false"属性,让Service在用户退出应用时仍然存在;

在华为平板上使用华为的自启动管理器,让Service在系统重启后仍然存在; 

使用第三方推送服务,如果Service被杀死,可以通过推送服务来重新启动Service; 

 🔥 Service和IntentService 区别 🔥

Service服务是长期运行在后台;

它不是单独的进程,因为它和应用程序在同一个进程;

也不是单独的线程,它跟线程没有任何关系,所以不能进行耗时操作;

如果直接把耗时操作放在Service中的onStartCommand()中,可能发生ANR,如果有耗时操作,就必须开启一个单独的线程来处理;

启动方式和Service一样,都是startService();

继承于Service,包含Service所有特性,包括生命周期,是处理异步请求的一个类;

一般自定义一个InitializeService继承Service,然后复写onHandleIntent()方法,在这个方法中初始化这些第三方的,来执行耗时操作;

可以启动多次IntentService,每一个耗时操作以工作队列在onHandleIntent()方法中执行,执行完第一个再去执行第二个,以此类推;

所有的请求都在单线程中,不会阻塞主线程,同一个时间只处理同一个请求;

不需要像在Service中一样,手动开启线程,任务执行完成后不需要手动调用stopSelf()方法来停止服务,系统会自动关闭服务;

IntentService使用

一般用于App启动时在BaseApplication中初始化一些第三方的东西,比如腾讯Bugly、腾讯X5WebView、OkhttpUtils等,目的就是为了防止BaseApplication中加载东西过多,导致App启动速度过慢,所以就自定义一个 InitializeService,继承Service,然后重写 onHandleIntent()方法,在这个方法中初始化这些第三方的;

BaseApplication代码如下:

public class BaseApplication extends Application {@Overridepublic void onCreate() {super.onCreate();//initLeakCanary();                //Square公司内存泄漏检测工具//在子线程中初始化InitializeService.start(this);}
}

 InitializeService代码如下:

/*** Email: 2185134304@qq.com* Created by JackChen 2018/4/12 15:35* Version 1.0* Params:* Description:
*/
public class InitializeService extends IntentService {private static final String ACTION_INIT = "initApplication";public static void start(Context context) {Intent intent = new Intent(context, InitializeService.class);intent.setAction(ACTION_INIT);context.startService(intent);}public InitializeService(){super("InitializeService");}@Overrideprotected void onHandleIntent(Intent intent) {if (intent != null) {final String action = intent.getAction();if (ACTION_INIT.equals(action)) {initApplication();}}}private void initApplication() {initBugly();                                    //初始化腾讯bug管理平台
//        BaseConfig.INSTANCE.initConfig();               //初始化配置信息LogUtils.logDebug = true;                       //开启日志}/*** 初始化腾讯bug管理平台*/private void initBugly() {/* Bugly SDK初始化* 参数1:上下文对象* 参数2:APPID,平台注册时得到,注意替换成你的appId* 参数3:是否开启调试模式,调试模式下会输出'CrashReport'tag的日志* 注意:如果您之前使用过Bugly SDK,请将以下这句注释掉。*/CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(getApplicationContext());strategy.setAppVersion(AppUtils.getAppVersionName());strategy.setAppPackageName(AppUtils.getAppPackageName());strategy.setAppReportDelay(20000);                          //Bugly会在启动20s后联网同步数据/*  第三个参数为SDK调试模式开关,调试模式的行为特性如下:输出详细的Bugly SDK的Log;每一条Crash都会被立即上报;自定义日志将会在Logcat中输出。建议在测试阶段建议设置成true,发布时设置为false。*/CrashReport.initCrashReport(getApplicationContext(), "126dde5e58", true ,strategy);Log.e("TAG" , "初始化bugly111") ;}
}

http://www.mrgr.cn/p/72141272

相关文章

HTTP协议+GET/POST区别

1. web开发流程 &#xff08;1&#xff09; HTML、CSS、JS、图片等资源通过浏览器进行整合&#xff0c;最终渲染出所需画面。 &#xff08;2&#xff09;浏览器对Web服务器进行资源请求 浏览器通过url请求资源。【HTTP协议、URL&#xff1a;确定唯一的一个资源】 浏览器请求…

【Linux】进程轻松入门

目录 一&#xff0c; 冯* 诺依曼体系结构 1&#xff0c;存储结构 ​编辑 二&#xff0c; 操作系统 1&#xff0c;概念 2&#xff0c;设计OS的目的 3&#xff0c;定位 4&#xff0c;如何理解 "管理" 5&#xff0c; 总结 三&#xff0c;进程 1. 概念 那么…

保姆级秋招教程之简历篇

大家好&#xff0c;我是千寻哥&#xff0c;个人简历在程序员求职过程中扮演着至关重要的角色。 今天我将详细给大家介绍一下写简历的必备要素和布局&#xff0c;同时强调应避免的“坑”&#xff01; 希望能通过这些技巧&#xff0c;能帮助程序员打造一份出色的简历&#xff0c;…

Java代码连接RabbitMQ服务器

目录 1.添加依赖 2.生产者代码 3.消费者代码 4.效果 1.发送消息 2.消费消息 5.注意 1.添加依赖 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.12.0</version></dependenc…

Rust 数据类型 之 结构体(Struct)

目录 结构体&#xff08;Struct&#xff09; 定义与声明 结构体定义 结构体实例 结构体分类 单元结构体&#xff08;Unit Struct&#xff09; 元组结构体&#xff08;Tuple Struct&#xff09; 具名结构体&#xff08;Named Struct&#xff09; 结构体嵌套 结构体方法…

ChatGPT+MidJourney 3分钟生成你的动画故事

chatgpt是真的火了&#xff0c;chatgpt产生了一个划时代的意义——自chatgpt起&#xff0c;AI是真的要落地了。 chatgpt能做的事情太多了&#xff0c;多到最初开发模型的程序员自己&#xff0c;也没法说得清楚chatgpt都能做啥&#xff0c;似乎只要你能想得到&#xff0c;它都有…

SSM整合

文章目录 Spring Spring MVCMyBatis整合目录结构引入Maven包web.xml文件导入spring_mvc.xml**spring_mvc.xml****中添加**json**返回编码**UTF-8**导入spring_config.xml文件导入mybatis.xml文件创建pojo对象创建Mapper.xml创建Service创建Controller Spring Spring MVCMyBatis…

Linux系统使用(超详细)

目录 Linux操作系统简介 Linux和windows区别 Linux常见命令 Linux目录结构 Linux命令提示符 常用命令 ls cd pwd touch cat echo mkdir rm cp mv vim vim的基本使用 grep netstat Linux面试题 Linux操作系统简介 Linux操作系统是和windows操作系统是并列…

【论文笔记】KDD2019 | KGAT: Knowledge Graph Attention Network for Recommendation

Abstract 为了更好的推荐&#xff0c;不仅要对user-item交互进行建模&#xff0c;还要将关系信息考虑进来 传统方法因子分解机将每个交互都当作一个独立的实例&#xff0c;但是忽略了item之间的关系&#xff08;eg&#xff1a;一部电影的导演也是另一部电影的演员&#xff09…

【数据结构与算法】斐波那契查找(黄金分割法)

斐波那契查找&#xff08;黄金分割法&#xff09; 黄金分割点是指把一条线段分割成两部分&#xff0c;使其中一部分与全长之比等于另一部分与这部分之比。取其前三位数字的近似值是 0.618。由于按此比例设计的造型十分美丽&#xff0c;因此称为黄金分割&#xff0c;也称为中外比…

人工智能安全-2-非平衡数据处理

0 提纲 现象与原因非平衡数据处理方法概览数据预处理层面特征层算法层面1 现象与原因 非平衡数据分类问题:在网络信息安全问题中,诸如恶意软件检测、SQL注入、不良信息检测等许多问题都可以归结为机器学习分类问题。这类机器学习应用问题中,普遍存在非平衡数据的现象。 产…

Spring MVC拦截器和跨域请求

一、拦截器简介 SpringMVC的拦截器&#xff08;Interceptor&#xff09;也是AOP思想的一种实现方式。它与Servlet的过滤器&#xff08;Filter&#xff09;功能类似&#xff0c;主要用于拦截用户的请求并做相应的处理&#xff0c;通常应用在权限验证、记录请求信息的日志、判断用…

618技术揭秘 - 大促弹窗搭投实践 | 京东云技术团队

背景 618 大促来了&#xff0c;对于业务团队来说&#xff0c;最重要的事情莫过于各种大促营销。如会场、直播带货、频道内营销等等。而弹窗作为一个极其重要的强触达营销工具&#xff0c;通常用来渲染大促氛围、引流主会场、以及通过频道活动来提升频道复访等。因此&#xff0…

管理ceph集群

文章目录 ceph的常用命令查看集群状态查看pg的状态查看mon节点状态查看osd的通用命令查看osd的容量查看osd池写入文件测试查看池的属性查看文件映射过程 添加磁盘删除磁盘 ceph的常用命令 查看集群状态 ceph osd pool application enable pool-name rbd #将池启用rbd功能 ceph…

华为数通HCIA-网络模型

TCP 网络通信模式 作用&#xff1a;指导网络设备的通信&#xff1b; OSI七层模型&#xff1a; 7.应用层&#xff1a;由应用层协议&#xff08;http、FTP、Telnet.&#xff09;为应用程序产生对应的数据&#xff1b; 6.表示层&#xff1a;将应用层产生的数据转换成网络设备看…

实战:Docker+Jenkins+Gitee构建CICD流水线

文章目录 前言Jenkins部署创建Jenkins docker-compose配置maven源启动Jenkins容器安装插件Gitee ssh公匙配置与测试项目提交 Jenkins创建流水线写在最后 前言 持续集成和持续交付一直是当下流行的开发运维方式&#xff0c;CICD省去了大量的运维时间&#xff0c;也能够提高开发…

【Linux】关于Bad magic number in super-block 当尝试打开/dev/sda1 时找不到有效的文件系统超级块

每个区段与 superblock 的信息都可以使用 dumpe2fs 这个指令来查询的&#xff01; 不过可惜的是&#xff0c;我们的 CentOS 7 现在是以 xfs 为默认文件系统&#xff0c; 所以目前你的系统应该无法使用 dumpe2fs 去查询任何文件系统的。 因为目前两个版本系统的根目录使用的文…

redis基础总结(数据类型)

Redis十大数据类型 String String 是redis最基本数据类型,一个key对应一个value. String类型是二进制安全的,意思是Redis的string类型可以包含任何数据,比如jpg图片或者序列化的对象; String类型是最基本的数据类型,一个redis中字符串value最多是512M; String类型在redis底层…

力扣天天练--week3-LeetCode75

topic75-9-t443:压缩字符串 题目描述&#xff1a; 给你一个字符数组 chars &#xff0c;请使用下述算法压缩&#xff1a; 从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 &#xff1a; 如果这一组长度为 1 &#xff0c;则将字符追加到 s 中。 否则&#xff0c;需…

企业知识文档管理+群晖nas安全云存储

企业知识管理系统&#xff0c;利用软件系统或其他工具的企业管理方法&#xff0c;利用软件系统或其他工具&#xff0c;对组织中大量的有价值的方案、策划、成果、经验等知识进行分类存储和管理&#xff0c;积累知识资产避免流失&#xff0c;促进知识的学习、共享、培训、再利用…