Android 9.0: सेवा शुरू करने की अनुमति नहीं है: एप्लिकेशन पृष्ठभूमि में है(onResume) के बाद()




android-service android-9.0-pie (4)

मुझे एक म्यूजिक प्लेयर मिला है जो एक Activity onResume() में एक Service शुरू करने का प्रयास करता है। मैंने स्पष्टता के लिए कुछ पंक्तियाँ निकाल दी हैं, लेकिन कोड प्रभावी है:

@Override
protected void onResume() {
    super.onResume();

    startService(new Intent(this, MusicService.class));
}

क्रैश लॉग के अनुसार, यह Android P पर चलने वाले कुछ उपकरणों पर एक अपवाद फेंक रहा है:

Caused by java.lang.IllegalStateException: Not allowed to start service Intent { cmp=another.music.player/com.simplecity.amp_library.playback.MusicService }: app is in background uid UidRecord{6a4a9c6 u0a143 TPSL bg:+3m25s199ms idle change:cached procs:1 seq(1283,1283,1283)}
       at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1577)
       at android.app.ContextImpl.startService(ContextImpl.java:1532)
       at android.content.ContextWrapper.startService(ContextWrapper.java:664)
       at android.content.ContextWrapper.startService(ContextWrapper.java:664)
       at com.simplecity.amp_library.utils.MusicServiceConnectionUtils.bindToService(SourceFile:36)
       at com.simplecity.amp_library.ui.activities.BaseActivity.bindService(SourceFile:129)
       at com.simplecity.amp_library.ui.activities.BaseActivity.onResume(SourceFile:96)

यह कैसे संभव है कि मेरा ऐप बैकग्राउंड में है, इसके तुरंत बाद onResume() और (और onResume() super.onResume() ) कहा जाता है?

इससे मुझे कोई मतलब नहीं है। यह एक मंच बग हो सकता है? इस दुर्घटना से प्रभावित सभी 3500+ उपयोगकर्ता Android P पर हैं।


Google से एक समाधान है:

इस मुद्दे को भविष्य के Android रिलीज़ में संबोधित किया गया है।

एप्लिकेशन क्रैश से बचने के लिए वर्कअराउंड है। एप्लिकेशन ActivManager.getRunningAppProcesses () पर कॉल करके एक्टिविटी.onResume () में प्रक्रिया की स्थिति प्राप्त कर सकते हैं और अगर एक्शन मेनस्ट्रीमर .unningAppProcessInfo.IMPORTANCE_FEGEGROUND की तुलना में कम है, तो सेवा शुरू करने से बचें। यदि डिवाइस पूरी तरह से नहीं जगा है, तो गतिविधियों को तुरंत रोक दिया जाएगा और अंततः पूरी तरह से जागने के बाद फिर से शुरू किया जाएगा।

तो मुझे लगता है कि यह इस तरह होना चाहिए:

// hack for https://issuetracker.google.com/issues/113122354
    List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
    if (runningAppProcesses != null) {
        int importance = runningAppProcesses.get(0).importance;
        // higher importance has lower number (?)
        if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
            URLPlayerService.startActionBroadcastServiceData(PlayerActivity.this);
    }

मैंने हैंडलर को वर्कअराउंड के रूप में इस्तेमाल किया है और यह बहुत अच्छा काम करता है लेकिन 100% नहीं:

// hack for https://issuetracker.google.com/issues/113122354
   handler.postDelayed(() -> URLPlayerService.startService(PlayerActivity.this),200);

अद्यतन: यह हमारे लिए उत्पादन में काम कर रहा है, लेकिन यह 100% नहीं है। मुझे पिछले डेढ़ महीने में एक दुर्घटना की रिपोर्ट मिली है जब सौ से अधिक अच्छी तरह से हो गए होते। जब तक यह ठीक से तय नहीं हो जाता, तब तक यह हमारे लिए सबसे अच्छा विकल्प है। शायद अगर मैं 300 से आगे का समय बढ़ाता तो एक दुर्घटना कभी नहीं होती?

हम अभी इसका परीक्षण कर रहे हैं जो अब तक काम कर रहा है। जैसे ही हम और परिणाम देखेंगे अपडेट करेंगे

class ResumingServiceManager(val lifecycle: Lifecycle) : LifecycleObserver {

    init {
        lifecycle.addObserver(this)
    }

    val disposable: CompositeDisposable = CompositeDisposable()

    fun startService(context: Context, intent: Intent) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            context.startService(intent)
        } else {
            Single.just(true)
                    .delaySubscription(300, TimeUnit.MILLISECONDS)
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeBy(
                            onSuccess = {
                                context.startService(intent)
                            }

                    ).addTo(disposable)
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopped() {
        disposable.clear()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        lifecycle.removeObserver(this)
    }
}

onCreate() इसे इनिशियलाइज़ करें और फिर कभी भी आप onResume में एक सेवा शुरू करना चाहते हैं। बस resumingServiceManager.startService(this, intent) कॉल करें

यह जीवनचक्र के बारे में जानता है, इसलिए यह डिस्पोजेबल को साफ कर देगा यदि यह ऑनस्क्रीन को रद्द करने से ट्रिगर करने से रोकता है जब यह तत्काल खुले / बंद के साथ पृष्ठभूमि के रास्ते पर हो सकता है।


उन्होंने दुर्घटना को ठीक किया (कुछ भविष्य में रिलीज, निश्चित रूप से नहीं) और अब के लिए एक वर्कअराउंड प्रदान किया: https://issuetracker.google.com/issues/110237673#comment9


शायद android.arch.lifecycle को इस एंड्रॉइड 9 बग के लिए वर्कअराउंड के रूप में इस्तेमाल किया जा सकता है?

public class MyActivity extends Activity implements LifecycleObserver {

    protected void onResume() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
                startService(intent);
            } else {
                ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
            }
        } else {
            startService(intent);
        }
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onEnterForeground() {
        startService(intent);
        ProcessLifecycleOwner.get().getLifecycle().removeObserver(this);
    }
}

मैंने इसे यहां पाया है।







android-9.0-pie