Как не дать холодному запуску Android приложения отпугнуть пользователей
Мобильные разработчики при создании приложения нацелены на то, чтобы создать быстрый и качественный продукт. От этого зависит впечатление пользователя, который пробует ваше приложение. Если запуск приложения будет медленным и неприятным, то пользователи будут разочарованы еще до того, как попробуют ваше приложение.
Какие виды запуска приложения существуют
Запуск приложения может происходить в одном из трех состояний: холодный запуск, теплый запуск или горячий запуск. Разница заключается в том, сколько времени требуется, чтобы ваше приложение стало видимым для пользователя. При холодном старте ваше приложение запускается с нуля. В других состояниях система должна вывести запущенное приложение из фона на передний план.
Холодный старт
Холодный запуск – это запуск приложения с нуля: процесс системы до этого запуска не создавал процесс приложения. Холодные запуски происходят в таких случаях, как запуск приложения в первый раз с момента загрузки устройства или после того, как система убила приложение. Этот тип запуска представляет собой самую большую проблему с точки зрения минимизации времени запуска, потому что система и приложение имеют больше работы, чем в других состояниях запуска, и поэтому пользователь может какое-то время видеть белый экран перед тем, как откроются экраны приложения.
Когда пользователь нажимает значок приложения,
событие click
переводится в startActivity(intent)
и направляется в ActivityManagerService
через Binder IPC, а ActivityManagerService
выполняет несколько шагов:
- Первым шагом является сбор информации о цели объекта намерения. Это делается с помощью метода
resolveIntent()
для объектаPackageManager
. ФлагиPackageManager.MATCH_DEFAULT_ONLY
иPackageManager.GET_SHARED_LIBRARY_FILES
используются по умолчанию. - Целевая информация сохраняется обратно в объект
intent
, чтобы избежать повторного выполнения этого шага. - Следующий важный шаг – проверить, достаточно ли у пользователя привилегий для вызова целевого компонента intent. Это делается путем вызова метода
grantUriPermissionLocked()
. - Если у пользователя достаточно разрешений,
ActivityManagerService
проверяет, требуется ли целевое действие для запуска в новой задаче. Создание задачи зависит от intent флагов, таких какFLAG_ACTIVITY_NEW_TASK
иFLAG_ACTIVITY_CLEAR_TOP
. - Теперь пришло время проверить, существует ли уже запись процесса для этого процесса. Если
ProcessRecord
имеет значениеnull
,ActivityManager
должен создать новый процесс для создания экземпляра целевого компонента.
Горячий старт
Горячий старт – это когда действия вашего приложения находятся в памяти и процесс вашего приложения уже работает в фоновом режиме. При горячем запуске все, что нужно сделать системе, – это вывести активность вашего приложения на передний план. Это делает его намного более быстрым, потому что системе не нужно повторять инициализацию, поэтому накладные расходы намного меньше.
Если пользователь возвращает действие с экрана «Недавние» вместо нажатия значка средства запуска, то процесс вызывает TaskSnapshotSurface.create()
для создания начального окна, в котором отображается сохраненный снимок действия.
Однако если некоторая память была очищена в ответ на события обрезки памяти, такие как onTrimMemory()
, то эти объекты необходимо будет воссоздать в ответ на событие горячего запуска.
При горячем запуске на экране отображается то же поведение, что и при холодном запуске: системный процесс отображает пустой экран до тех пор, пока приложение не завершит визуализацию действия.
Как сделать холодный запуск более приятным и не допустить плохой юзер экспириенс?
Каждый пользователь при взаимодействии с приложением ожидает как можно скорее иметь доступ к контенту, и этот “стартовый” контент можно отобразить с заполнителем или же добавить логотип приложения.
Итак , для того чтобы создать свой заполнитель , необходимо создать xml
файл в папке drawable
и добавить нужные цвета:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="45"
android:endColor="#87CEEB"
android:centerColor="#768087"
android:startColor="#000"
android:type="linear" />
</shape>
Далее заполнитель необходимо задать в теме приложения (values >themes.xml section) :
<item name="android:windowBackground">@drawable/bg_splash</item>
Также в качестве входной точки для приложения можно добавить экран SplashActivity
, во время отображения которого можно выполнить ряд задач с загрузкой ресурсов или данных. Это поможет образовать плавный переход в экран взаимодействия, чтобы пользователь не заметил особой разницы:
<activity android:name=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
В качестве контента можно передать логотип приложения и заполнитель, который добавляли для стартового окна:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_splash"
tools:context=".SplashActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/rokkitt_bold"
android:text="@string/example_app"
android:textColor="@android:color/white"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
В самом активити необходимо обернуть Intent
в Handler
, который по истечении заданного времени открывает экран взаимодействия:
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
Handler(Looper.getMainLooper()).postDelayed({
/* Create an Intent that will start the MainActivity. */
val mainIntent = Intent(this, MainActivity::class.java)
startActivity(mainIntent)
finish()
}, 800)
И наконец, не забудьте в контент экрана взаимодействия добавить цвет, так как иначе он будет отображать заполнитель, который вы задали в теме:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Теперь можно запустить проект и увидеть результат:
Надеюсь вам было полезно и интересно!)
Посмотрите пример проекта на GitHub.