Как мне применить приложение onCreate после закрытия приложения и запуска службы в bg? - PullRequest
4 голосов
/ 21 июня 2020

В основном у меня есть приложение, которое запускает службу переднего плана. Когда я запускаю приложение, мне нужно выполнить инициализацию c сеанса в методе onCreate приложения.

Когда я закрываю приложение, служба продолжает работать (желаемое поведение), однако, когда я снова открываю app из панели запуска / из моего уведомления, приложение onCreate больше не вызывается.

Мой вопрос:

  1. Как мне принудительно применить приложение onCreate be звонили снова, хотя там работает служба? (Служба, вероятно, хранит ссылку на объект приложения, верно?)
  2. Есть ли способ получить указание внутри класса Application, что приложение было запущено снова, но из службы?
  3. Какие еще решения вы можете придумать?

MyService в AndroidManifest.xml:

<service android:name=".MyService"
    android:exported="false"/>

Мои услуги onStartCommand:

    createNotificationChannel();
    Intent notificationIntent = new Intent(this, MyActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("My Service")
            .setContentText("Service")
            .setSmallIcon(R.drawable.ic_android)
            .setContentIntent(pendingIntent)
            .build();
    startForeground(1, notification);

Ответы [ 5 ]

1 голос
/ 30 июня 2020

Вы можете создать ProcessLifeCycleOwner внутри Application и прослушивать события жизненного цикла. Вам также может потребоваться установить флаг для класса и получить это значение из метода, чтобы проверить, вернулся ли пользователь после нажатия кнопки «Домой» или запуска приложения с помощью уведомления

class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()

        ProcessLifecycleOwner
            .get()
            .lifecycle
            .addObserver(ApplicationObserver())
    }

    inner class ApplicationObserver : LifecycleObserver {

        @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
        fun onStop() {
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_START)
        fun onStart() {

        }

        @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
        fun onCreate() {

        }


        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        fun onDestroy() {

        }
    }
}
0 голосов
/ 30 июня 2020

Найдите способ узнать, что приложение запущено (по крайней мере, началось первое действие), затем выполните некоторую инициализацию, как вы хотите, на onCreate(). У меня такая же ситуация, как и у вас, приложение должно что-то делать при запуске и выходе. Я создал интерфейс для прослушивания того, что приложение переходит в режим переднего плана и в фоновый режим (активность не выполняется):

interface IApplicationLifeCycle {
    fun onEnterForeground()
    fun onEnterBackground()
    fun onFirstCreated()
    fun onLastDestroyed()
}

Затем я создаю класс для определения того, что приложение переходит в фоновый и передний план

class AppLifeCycleTracker(private val iApplicationLifeCycle: IApplicationLifeCycle? = null) : Application.ActivityLifecycleCallbacks {
private var aliveActivityCount = 0 // created on destroyed
private var activeActivityCount = 0 // started on stopped
private var liveActivityCount = 0 // resumed on paused

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
    aliveActivityCount++
    if (aliveActivityCount == 1) {
        iApplicationLifeCycle?.onFirstCreated()
    }
}

override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}

override fun onActivityStarted(activity: Activity) {
    activeActivityCount++
}

override fun onActivityResumed(activity: Activity) {
    liveActivityCount++
    if (liveActivityCount == 1 && activeActivityCount == 1) {
        iApplicationLifeCycle?.onEnterForeground()
    }
}

override fun onActivityPaused(activity: Activity) {
    liveActivityCount--
}

override fun onActivityStopped(activity: Activity) {
    activeActivityCount--
    if (liveActivityCount == 0 && activeActivityCount == 0) {
        iApplicationLifeCycle?.onEnterBackground()
    }
}

override fun onActivityDestroyed(activity: Activity) {
    aliveActivityCount--
    if (aliveActivityCount == 0) {
        iApplicationLifeCycle?.onLastDestroyed()
    }
}

}

в моем приложении

class MyApplication: IApplicationLifeCycle{

    onCreate() {
        super.onCreate() 
        registerActivityLifecycleCallbacks(AppLifeCycleTracker(this))
    }

    override fun onEnterForeground() {
        Log.i("AppVisibility", "onEnterForeground")
        // do action here
    }

    ...
    ...
    ...
}

в переопределенном методе, onEnterForeground просто выполните действие, как вы хотите, в этом случае вы хотите выполнить некоторую инициализацию

0 голосов
/ 29 июня 2020

Объект Application одноэлементный. Он создается (и вызывается onCreate()), когда создается процесс ОС, в котором размещается ваше приложение. Если ваше приложение размещает передний план Service, то этот процесс ОС будет продолжать существовать, поэтому Application.onCreate() не будет вызываться.

Мне не совсем понятно, зачем вам его вызывать , но вы можете запустить Service в процессе ОС, отличном от других компонентов (Activity, BroadcastReceiver, Provider) вашего приложения. В этом случае процесс ОС, на котором размещен передний план Service, не будет воссоздан, но процесс ОС, в котором размещены ваши действия, будет воссоздан (если он будет остановлен с помощью Android, что обычно происходит, если не работают активные компоненты. в этом). Поскольку объект Application существует в каждом процессе ОС, при воссоздании процесса ОС, в котором выполняются действия, Android создаст экземпляр нового объекта Application и вызовет для него onCreate().

Чтобы ваш Service работал в другом процессе ОС, просто добавьте это в тег <service> в манифесте:

android:process=":remote"

ПРИМЕЧАНИЕ. Вы можете использовать любое имя вместо «удаленного», просто убедитесь, что он начинается с двоеточия (":")

ПРЕДУПРЕЖДЕНИЕ: вы должны знать, что у вас есть 2 процесса ОС для вашего приложения, и планировать соответственно. Код, выполняемый в этих двух процессах, не может видеть друг друга, поэтому это может вызвать дополнительные проблемы в вашем приложении. Любые данные, которыми вы обменивались между компонентами (например, Service и Activity), должны быть помещены в базу данных или общие настройки или какой-либо другой механизм для совместного использования их между процессами ОС.

0 голосов
/ 30 июня 2020

Я бы посоветовал вам создать служебную функцию, содержащую ваш код инициализации. Используйте флаг, чтобы узнать, нужно ли запускать операцию, и ничего не делайте, если этот флаг установлен.

Вызовите это из вашего базового Activity (не из приложения) из-за точной проблемы, с которой вы столкнулись. Это также позволяет оставлять отзывы пользователей во время инициализации.

Снимать флаг после выхода пользователя.

Итак, по сути, переместите свой код в место, где его можно будет вызывать последовательно.

0 голосов
/ 21 июня 2020

Событие onCreate запускается во время создания объекта. После есть onStart. Если приложение было закрыто, объект все еще активен в памяти и будет уничтожен, если устройству потребуются дополнительные свободные ресурсы. Итак, если вы снова откроете приложение, запускается только событие onStart. Попробуйте переместить инициализацию в onStart или поставить галочку или что-то подобное в onStart.

Жизненный цикл активности https://developer.android.com/guide/components/activities/activity-lifecycle

...