android Context.startForegroundService() ने तब कॉल नहीं किया Service.startForeground()




operating-system android-8.0-oreo (30)

में डेटा अपडेट कर रहा है onStartCommand(...)

onBind (...)

onBind(...) आरंभ करने के लिए एक बेहतर जीवन चक्र घटना है startForeground बनाम onCreate(...) क्योंकि onBind(...) एक में गुजरता है Intent , जिसमें महत्वपूर्ण डेटा हो सकता है Bundle की जरूरत प्रारंभ करने में Service । हालांकि, यह आवश्यक नहीं है जैसा onStartCommand(...) कि तब कहा जाता है जब Service पहली बार बनाया जाता है या बाद के समय के बाद बुलाया जाता है।

onStartCommand (...)

startForeground में onStartCommand(...) अवगत कराने के लिए महत्वपूर्ण है Service एक बार यह पहले से ही बनाया गया है।

जब ContextCompat.startForegroundService(...) एक के बाद कहा जाता है Service बनाया गया है onBind(...) और onCreate(...) नहीं कहा जाता है। इसलिए, अपडेट किए गए डेटा में डेटा अपडेट करने onStartCommand(...) के Intent Bundle लिए इसके माध्यम से अपडेट किया जा सकता है Service

नमूना

मैं इस पैटर्न का उपयोग Coinverse cryptocurrency न्यूज़ ऐप PlayerNotificationManager में लागू करने के लिए कर रहा हूं । Coinverse

गतिविधि / Fragment.kt

private var uri: Uri = Uri.parse("")

override fun onBind(intent: Intent?) =
        AudioServiceBinder().apply {
            player = ExoPlayerFactory.newSimpleInstance(
                    applicationContext,
                    AudioOnlyRenderersFactory(applicationContext),
                    DefaultTrackSelector())
        }

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    intent?.let {
        when (intent.action) {
            CONTENT_SELECTED_ACTION -> it.getParcelableExtra<Content>(CONTENT_SELECTED_KEY).also { content ->
                val intentUri = Uri.parse(content.audioUrl)
                // Checks whether to update Uri passed in Intent Bundle.
                if (!intentUri.equals(uri)) {
                    uri = intentUri
                    player?.prepare(ProgressiveMediaSource.Factory(
                            DefaultDataSourceFactory(
                                    this,
                                    Util.getUserAgent(this, getString(app_name))))
                            .createMediaSource(uri))
                    player?.playWhenReady = true
                    // Calling 'startForeground' in 'buildNotification(...)'.          
                    buildNotification(intent.getParcelableExtra(CONTENT_SELECTED_KEY))
                }
            }
        }
    }
    return super.onStartCommand(intent, flags, startId)
}

// Calling 'startForeground' in 'onNotificationStarted(...)'.
private fun buildNotification(content: Content): Unit? {
    playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
            this,
            content.title,
            app_name,
            if (!content.audioUrl.isNullOrEmpty()) 1 else -1,
            object : PlayerNotificationManager.MediaDescriptionAdapter {
                override fun createCurrentContentIntent(player: Player?) = ...
                override fun getCurrentContentText(player: Player?) = ...
                override fun getCurrentContentTitle(player: Player?) = ...
                override fun getCurrentLargeIcon(player: Player?,
                                                 callback: PlayerNotificationManager.BitmapCallback?) = ...
            },
            object : PlayerNotificationManager.NotificationListener {
                override fun onNotificationStarted(notificationId: Int, notification: Notification) {
                    startForeground(notificationId, notification)
                }
                override fun onNotificationCancelled(notificationId: Int) {
                    stopForeground(true)
                    stopSelf()
                }
            })
    return playerNotificationManager.setPlayer(player)
}

AudioService.kt

context.startForegroundService(new Intent(context, TaskQueueExecutorService.class));

try {
    Thread.sleep(10000);
} catch (InterruptedException e) {
    e.printStackTrace();
}       

https://code.i-harness.com

मैं Android O OS पर Service वर्ग का उपयोग कर रहा हूं।

मैं पृष्ठभूमि में Service का उपयोग करने की योजना बना रहा हूं।

Android अनुशंसा में कहा गया है कि startService() को startForegroundService() उपयोग करना चाहिए।

यदि आप startForegroundService() उपयोग करते हैं, तो Service फेंकता है

Context.startForegroundService () ने तब कॉल नहीं किया Service.startForeground ()

त्रुटि।

इसमें गलत क्या है?


सर्विस

val nChannel = NotificationChannel("all", "All", NotificationManager.IMPORTANCE_NONE)
val nManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
nManager.createNotificationChannel(nChannel)

start_test_service.setOnClickListener {
    TestService.start(this@MainActivity)
    TestService.stop(this@MainActivity)
}

टेस्टर

D/TestService: onCreate
D/TestService: onStartCommand -> START
D/TestService: onStartCommand -> STOP
D/TestService: onDestroy

परिणाम

   @Override
    public void onCreate() {
try{
}
catch(Exception e)
{
}
finally{
    startForeground(1, notificationbuilder.build());

}
    }

StartForgroundService को कॉल करने के बाद, आपको सूचना दिखाने के लिए 5 सेकंड के भीतर अपनी सेवा में StartForground को कॉल करना चाहिए।

यदि आपका ऐप API स्तर 26 या उच्चतर को लक्षित करता है, तो आपको फ़ोरग्राउंड सेवाओं का उपयोग करना चाहिए और जब आप चाहते हैं कि आपकी सेवा तब भी चलती रहे, जब उपयोगकर्ता ऐप के साथ सहभागिता नहीं कर रहा हो, तो एक सूचना दिखाएं। क्योंकि सिस्टम पृष्ठभूमि सेवाओं को चलाने पर प्रतिबंध लगाता है जब ऐप स्वयं अग्रभूमि में नहीं होता है। इस तरह के ज्यादातर मामलों में, आपके ऐप को इसके बजाय एक निर्धारित नौकरी का उपयोग करना चाहिए।


ठीक है, कुछ मैंने इस पर ध्यान दिया जो कुछ अन्य लोगों की भी मदद कर सकता है। यह देखने के लिए परीक्षण से कड़ाई से है कि क्या मैं यह पता लगा सकता हूं कि मैं जो कुछ भी देख रहा हूं उसे कैसे ठीक किया जाए। सरलता के लिए, मान लें कि मेरे पास एक तरीका है जो प्रस्तुतकर्ता से इसे कहता है।

new Handler(Looper.getMainLooper()).post(new Runnable() {
        public void run() {
               context.startForegroundService(new Intent(context, 
           TaskQueueExecutorService.class));
               try {
                   Thread.sleep(10000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
              }       
        }
});

यह एक ही त्रुटि के साथ दुर्घटनाग्रस्त हो जाएगा। सेवा पूर्ण होने तक सेवा शुरू नहीं होगी, इसलिए onCreate() सेवा में नहीं ।

इसलिए भले ही आप मुख्य थ्रेड से यूआई को अपडेट करते हैं, अगर आपके पास कुछ भी है जो इसके बाद उस विधि को पकड़ सकता है, तो यह समय पर शुरू नहीं होगा और आपको खतरनाक फोरग्राउंड त्रुटि देगा। मेरे मामले में हम कुछ चीजों को एक कतार में लोड कर रहे थे और प्रत्येक को बुलाया startForegroundService गया था, लेकिन पृष्ठभूमि में प्रत्येक के साथ कुछ तर्क शामिल थे। इसलिए यदि तर्क को वापस लेने में बहुत समय लगता है, क्योंकि उन्हें बैक टू बैक कहा जाता है, क्रैश टाइम। पुराने startService ने इसे नजरअंदाज कर दिया और इस तरह से चला गया और जब से हमने इसे हर बार बुलाया, अगला दौर खत्म हो गया।

यह मुझे आश्चर्यचकित करता है, अगर मैंने पृष्ठभूमि में एक थ्रेड से सेवा को कॉल किया, तो क्या यह पूरी तरह से प्रारंभ पर बाध्य नहीं हो सकता है और तुरंत चल सकता है, इसलिए मैंने प्रयोग करना शुरू कर दिया। हालांकि यह इसे तुरंत शुरू नहीं करता है, यह दुर्घटना नहीं करता है।

 <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

मैं यह जानने का नाटक नहीं करूंगा कि यह दुर्घटनाग्रस्त क्यों नहीं हुआ, हालांकि मुझे संदेह है कि यह प्रतीक्षा करने के लिए मजबूर करता है जब तक कि मुख्य धागा इसे समय पर फैशन में संभाल नहीं सकता। मुझे पता है कि इसे मुख्य धागे से बांधना आदर्श नहीं है, लेकिन जब से मेरा उपयोग इसे पृष्ठभूमि में कहता है, मैं वास्तविक चिंतित नहीं हूं अगर यह इंतजार करता है जब तक कि यह दुर्घटना के बजाय पूरा नहीं हो सकता।


मुझे पता है कि यह एक देर से जवाब है लेकिन, मुझे लगता है कि यह भविष्य में मदद कर सकता है, मैंने JobIntentService इसके बजाय इसका इस्तेमाल किया IntentService है जिसमें इसके जॉबस्क्रिलर शामिल हैं और मेरे लिए सब कुछ संभालते हैं। इस example


मुझे भी यही समस्या थी, लेकिन यह तथ्य था कि मेरा डेटाबेस खाली था, मुझे एक रिकॉर्ड रखना होगा। कोशिश करने के लिए, मेरे पास "targetSdkVersion 28" है, मैं एप्लिकेशन लॉन्च करता हूं, मैं डेटाबेस खाली करता हूं। मैं एप्लिकेशन को पुनरारंभ करता हूं, यह क्रैश हो जाता है, मैंने "targetSdkVersion 25" डाला, मैं एप्लिकेशन चलाता हूं और यह काम करता है। मैंने एक रिकॉर्डिंग को फिर से बनाया। मैं "targetSdkVersion 28" से पुनरारंभ करता हूं और यह काम करता है। इस समस्या की पुष्टि करने के लिए कई बार।


मेरे लिए मैंने प्रकट में अग्रभूमि सेवा को जोड़ा

class TestService : Service() {

    override fun onCreate() {
        super.onCreate()
        Log.d(TAG, "onCreate")

        val nBuilder = NotificationCompat.Builder(this, "all")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("TestService")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        startForeground(1337, nBuilder.build())
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        val rtn = super.onStartCommand(intent, flags, startId)

        if (intent?.action == STOP_ACTION) {
            Log.d(TAG, "onStartCommand -> STOP")
            stopForeground(true)
            stopSelf()
        } else {
            Log.d(TAG, "onStartCommand -> START")
        }

        return rtn
    }

    override fun onDestroy() {
        Log.d(TAG, "onDestroy")
        super.onDestroy()
    }

    override fun onBind(intent: Intent?): IBinder? = null

    companion object {

        private val TAG = "TestService"
        private val STOP_ACTION = "ly.zen.test.TestService.ACTION_STOP"

        fun start(context: Context) {
            ContextCompat.startForegroundService(context, Intent(context, TestService::class.java))
        }

        fun stop(context: Context) {
            val intent = Intent(context, TestService::class.java)
            intent.action = STOP_ACTION
            ContextCompat.startForegroundService(context, intent)
        }

    }

}

अगर यह नीचे टिप्पणी काम करता है मुझे बताएं


मैं फ़ंक्शन को PendingIntent कॉल करने से पहले केवल नल या न ही चेक करता हूं context.startForegroundService(service_intent)

यह मेरे लिए काम करता है

Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{1946947 u0 ...MessageService}

main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x763e01d8 self=0x7d77814c00
  | sysTid=11171 nice=-10 cgrp=default sched=0/0 handle=0x7dfe411560
  | state=S schedstat=( 1337466614 103021380 2047 ) utm=106 stm=27 core=0 HZ=100
  | stack=0x7fd522f000-0x7fd5231000 stackSize=8MB
  | held mutexes=
  #00  pc 00000000000712e0  /system/lib64/libc.so (__epoll_pwait+8)
  #01  pc 00000000000141c0  /system/lib64/libutils.so (android::Looper::pollInner(int)+144)
  #02  pc 000000000001408c  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+60)
  #03  pc 000000000012c0d4  /system/lib64/libandroid_runtime.so (android::android_os_MessageQueue_nativePollOnce(_JNIEnv*, _jobject*, long, int)+44)
  at android.os.MessageQueue.nativePollOnce (MessageQueue.java)
  at android.os.MessageQueue.next (MessageQueue.java:326)
  at android.os.Looper.loop (Looper.java:181)
  at android.app.ActivityThread.main (ActivityThread.java:6981)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1445)

मैं @ अचम्भा उत्तर में कुछ कोड जोड़ रहा हूँ। इसलिए कोई प्रारंभिक अधिसूचना नहीं है। यह एक वर्कअराउंड हो सकता है लेकिन यह मेरे लिए काम करता है।

@Override
public int onStartCommand(Intent intent,
    int flags, int startId) {

    //call startForeground first
    boolean stopService = false;
    if (intent != null) {
        stopService = intent.getBooleanExtra("request_stop", false);
    }
    if (stopService) {
        stopSelf();
        return START_STICKY;
    }
    //Continue with the background task
    return START_STICKY;
}

मैं अधिसूचना में छोटे आइकन और रंग में पारदर्शी रंग जोड़ रहा हूं। यह काम करेगा।


मैंने startService(intent) इसके बजाय सेवा शुरू करने Context.startForeground() और इसके startForegound() तुरंत बाद कॉल करने के साथ समस्या को ठीक किया है super.OnCreate() । इसके अतिरिक्त, यदि आप बूट पर सेवा शुरू कर रहे हैं, तो आप बूट प्रसारण पर सेवा शुरू करने वाली गतिविधि शुरू कर सकते हैं। यद्यपि यह एक स्थायी समाधान नहीं है, यह काम करता है।


यह सब दूर हो जाता है यदि आप w / bindService शुरू करने के लिए अपनी सेवा को फिर से लिखते हैं।

इसे कैसे किया जा सकता है, इसका एक उदाहरण यहां देखा जा सकता है: https://github.com/paulpv/ForegroundServiceAPI26/tree/bound

मेरी "रिप्रो" शाखा का एक अंतर यहां देखा जा सकता है: https://github.com/paulpv/ForegroundServiceAPI26/compare/repro...bound?expand=1


यहां तक कि फोन करने के बाद startForeground में Service , यह कुछ उपकरणों पर दुर्घटनाओं अगर हम कहते हैं stopService बस से पहले onCreate कहा जाता है। इसलिए, मैंने एक अतिरिक्त ध्वज के साथ सेवा शुरू करके इस मुद्दे को ठीक किया:

PendingIntent pendingIntent=PendingIntent.getBroadcast(context,0,intent,PendingIntent.FLAG_NO_CREATE);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && pendingIntent==null){
            context.startForegroundService(service_intent);
        }
        else
        {
            context.startService(service_intent);
        }
}

और यह देखने के लिए onStartCommand में एक चेक जोड़ा कि क्या वास्तव में इसे बंद करना शुरू किया गया था:

import android.app.Notification;
public class AuthenticationService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(1,new Notification());
    }
}

PS यदि सेवा वास्तव में नहीं चल रही थी, तो यह सेवा को पहले शुरू करेगी जो एक उपरि है।


सुनिश्चित करें कि सभी कोड पथ स्टार्टफ़ोरग्राउंड विधि को कॉल करते हैं, उदाहरण के लिए कोड ऑन-क्रिएट पर एक अपवाद उत्पन्न कर सकता है आपकी सेवा का तरीका जो स्टार्ट फ़ॉरग्राउंड को रोकने से रोकता है

 @Override public void onCreate() { try{ } catch(Exception e) { } finally{ startForeground(1, notificationbuilder.build()); } } 

सेवा या आशय सेवा के बाद तुरंत कॉल स्टार्टफोरग्राउंड विधि। इस तरह:

context?.bindService(
        Intent(context, AudioService::class.java),
        serviceConnection, Context.BIND_AUTO_CREATE)
ContextCompat.startForegroundService(
        context!!,
        Intent(context, AudioService::class.java).apply {
            action = CONTENT_SELECTED_ACTION
            putExtra(CONTENT_SELECTED_KEY, contentToPlay.content.apply {
                audioUrl = uri.toString()
            })
        })

Android O API 26 के साथ समस्या

यदि आप तुरंत सेवा बंद कर देते हैं (इसलिए आपकी सेवा वास्तव में नहीं चलती है (शब्द / समझ) और आप एएनआर अंतराल के तहत रास्ते में हैं, तो आपको स्टॉप से ​​पहले भी स्टार्टफ़ोरग्राउंड कॉल करने की आवश्यकता है

https://plus.google.com/116630648530850689477/posts/L2rn4T6SAJ5

इस दृष्टिकोण की कोशिश की लेकिन यह अभी भी एक त्रुटि बनाता है: -

if (Util.SDK_INT > 26) {
    mContext.startForegroundService(playIntent);
} else {
    mContext.startService(playIntent);
}

मैं त्रुटि का समाधान होने तक इसका उपयोग कर रहा हूं

mContext.startService(playIntent);

अगर आप Context.startForegroundService(...) कॉल करते हैं तो आपका ऐप क्रैश हो जाएगा और फिर Service.startForeground(...) को कॉल करने से पहले Service.startForeground(...) को कॉल करें।

मैं यहाँ एक स्पष्ट repro है ForegroundServiceAPI26

मैंने इस पर एक बग खोला है: issuetracker.google.com/issues/76112072

इस पर कई कीड़े खोले गए और ठीक नहीं हुए।

उम्मीद है कि स्पष्ट रेप्रो चरणों के साथ मेरा कटौती करेगा।

Google टीम द्वारा दी गई जानकारी

issuetracker.google.com/issues/76112072#comment36

यह एक ढांचा बग नहीं है; यह जानबूझकर है। यदि एप्लिकेशन startForegroundService() साथ एक सेवा उदाहरण शुरू करता है, तो उसे उस सेवा आवृत्ति को अग्रभूमि में स्थानांतरित करना होगा और अधिसूचना दिखाना होगा। यदि startForeground() पर कॉल करने से पहले सेवा का उदाहरण बंद हो जाता है, तो वह वादा अधूरा है: यह ऐप में एक बग है।

# 31 को पुन: प्रकाशित करना, एक ऐसी सेवा का प्रकाशन जो अन्य ऐप सीधे शुरू कर सकते हैं, मौलिक रूप से असुरक्षित है। आप इस बात को कम कर सकते हैं कि उस सेवा के सभी आरंभिक कार्यों को शुरू करने की आवश्यकता है जैसा कि startForeground() आवश्यकता है, हालांकि स्पष्ट रूप से वह नहीं हो सकता है जो आपके मन में था।

issuetracker.google.com/issues/76112072#comment56

विभिन्न परिदृश्यों के एक जोड़े हैं जो यहां एक ही परिणाम के लिए नेतृत्व करते हैं।

एकमुश्त अर्थगत मुद्दा, कि यह startForegroundService() साथ किसी चीज़ को किक करने के लिए बस एक त्रुटि है, लेकिन वास्तव में इसे शुरू करने के लिए उपेक्षा करने के लिए इसे शुरू करने के लिए startForeground() माध्यम से, बस एक अर्थपूर्ण मुद्दा है। वह जानबूझकर एक ऐप बग के रूप में व्यवहार किया जाता है। इसे अग्रभूमि में परिवर्तित करने से पहले सेवा रोकना एक ऐप त्रुटि है। यह ओपी का क्रुक्स था, और इसीलिए इस मुद्दे को "इच्छानुसार काम करते हुए" चिह्नित किया गया है।

हालाँकि, इस समस्या का पता लगाने के बारे में भी सवाल हैं। यह एक वास्तविक समस्या के रूप में माना जा रहा है, हालांकि इसे इस विशेष बग ट्रैकर मुद्दे से अलग से ट्रैक किया जा रहा है। हम शिकायत करने के लिए बहरे नहीं हैं।


इतने सारे जवाब लेकिन किसी ने भी मेरे मामले में काम नहीं किया।

मैंने इस तरह की सेवा शुरू की है।

              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    startForegroundService(intent);
                } else {
                    startService(intent);
                }

और onStartCommand में मेरी सेवा में

   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("SmartTracker Running")
                .setAutoCancel(true);
        Notification notification = builder.build();
        startForeground(NOTIFICATION_ID, notification);
    } else {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle(getString(R.string.app_name))
                .setContentText("SmartTracker is Running...")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setAutoCancel(true);
        Notification notification = builder.build();
        startForeground(NOTIFICATION_ID, notification);
    }

और नोटिफ़िकेशन_आईडी नॉन जीरो सेट करना न भूले

निजी स्थिर अंतिम स्ट्रिंग ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel"; निजी स्थिर अंतिम int NOTIFICATION_ID = 555;

SO सब कुछ सही था, लेकिन फिर भी 8.1 पर दुर्घटनाग्रस्त हो गया, इसलिए इसका कारण नीचे था।

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            stopForeground(true);
        } else {
            stopForeground(true);
        }

मैंने स्टॉप फोरग्राउंड को रिमूव नोटिफ़ैटन के साथ बुलाया है लेकिन एक बार नोटिफिकेशन निकाले जाने की सेवा बैकग्राउंड हो जाती है और बैकग्राउंड से एंड्रॉइड ओ में बैकग्राउंड सर्विस नहीं चल सकती। धक्का मिलने के बाद शुरू हुआ।

इतना जादुई शब्द है

  stopSelf();

अब तक किसी भी कारण से आपकी सेवा दुर्घटनाग्रस्त हो गई है, ऊपर दिए गए सभी चरणों का पालन करें और आनंद लें।


इस समस्या के लिए मेरे पास एक काम है। मैंने अपने स्वयं के ऐप (300K + DAU) में इस फिक्स को सत्यापित किया है, जो इस तरह की दुर्घटना के कम से कम 95% को कम कर सकता है, लेकिन फिर भी 100% इस समस्या से बच नहीं सकता है।

यह समस्या तब भी होती है, जब आप Google द्वारा प्रलेखित सेवा शुरू होने के ठीक बाद startForeground () को कॉल करना सुनिश्चित करते हैं। ऐसा इसलिए हो सकता है क्योंकि सेवा निर्माण और आरंभीकरण की प्रक्रिया में पहले से ही कई परिदृश्यों में 5 सेकंड से अधिक का समय लगता है, फिर कोई बात नहीं है जब आप startForeground () विधि कहते हैं, तो यह क्रैश अपरिहार्य है।

मेरा समाधान यह सुनिश्चित करना है कि startForegroundService () विधि के बाद startForeground () को 5 सेकंड के भीतर निष्पादित किया जाएगा, भले ही आपकी सेवा को बनाने और आरंभ करने की आवश्यकता कितनी भी हो। यहाँ विस्तृत समाधान है।

  1. पहली जगह पर startForegroundService का उपयोग न करें, auto_create ध्वज के साथ bindService () का उपयोग करें। यह सेवा के आरंभ होने की प्रतीक्षा करेगा। यहाँ कोड है, मेरी नमूना सेवा MusicService है:

    final Context applicationContext = context.getApplicationContext();
    Intent intent = new Intent(context, MusicService.class);
    applicationContext.bindService(intent, new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            if (binder instanceof MusicBinder) {
                MusicBinder musicBinder = (MusicBinder) binder;
                MusicService service = musicBinder.getService();
                if (service != null) {
                    // start a command such as music play or pause.
                    service.startCommand(command);
                    // force the service to run in foreground here.
                    // the service is already initialized when bind and auto_create.
                    service.forceForeground();
                }
            }
            applicationContext.unbindService(this);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }, Context.BIND_AUTO_CREATE);
  2. फिर यहां संगीतबीर कार्यान्वयन है:

    /**
     * Use weak reference to avoid binder service leak.
     */
     public class MusicBinder extends Binder {
    
         private WeakReference<MusicService> weakService;
    
         /**
          * Inject service instance to weak reference.
          */
         public void onBind(MusicService service) {
             this.weakService = new WeakReference<>(service);
         }
    
         public MusicService getService() {
             return weakService == null ? null : weakService.get();
         }
     }
  3. सबसे महत्वपूर्ण हिस्सा, MusicService कार्यान्वयन, forceForeground () विधि यह सुनिश्चित करेगी कि startForeground (सेवा) विधि को startForegroundService () के बाद कहा जाता है:

    public class MusicService extends MediaBrowserServiceCompat {
    ...
        private final MusicBinder musicBind = new MusicBinder();
    ...
        @Override
        public IBinder onBind(Intent intent) {
            musicBind.onBind(this);
            return musicBind;
        }
    ...
        public void forceForeground() {
            // API lower than 26 do not need this work around.
            if (Build.VERSION.SDK_INT >= 26) {
                Intent intent = new Intent(this, MusicService.class);
                // service has already been initialized.
                // startForeground method should be called within 5 seconds.
                ContextCompat.startForegroundService(this, intent);
                Notification notification = mNotificationHandler.createNotification(this);
                // call startForeground just after startForegroundService.
                startForeground(Constants.NOTIFICATION_ID, notification);
            }
        }
    }
  4. यदि आप एक लंबित इरादे में चरण 1 कोड स्निपेट चलाना चाहते हैं, जैसे कि यदि आप अपने ऐप को खोले बिना विजेट (विजेट बटन पर एक क्लिक) में अग्रभूमि सेवा शुरू करना चाहते हैं, तो आप एक प्रसारण रिसीवर में कोड स्निपेट लपेट सकते हैं। , और स्टार्ट सर्विस कमांड के बजाय एक प्रसारण कार्यक्रम को आग लगा दें।

बस इतना ही। आशा करता हूँ की ये काम करेगा। सौभाग्य।


कृपया OnCreate () विधि के अंदर किसी भी StartForgroundServices को कॉल न करें, आपको कार्यकर्ता धागे के बाद StartForground सेवाओं को onStartCommand () में कॉल करना होगा अन्यथा आपको हमेशा ANR मिल जाएगा, इसलिए कृपया onStartCommand () के मुख्य लॉगिन में जटिल लॉगिन न लिखें ;

public class Services extends Service {

    private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText("SmartTracker Running")
                    .setAutoCancel(true);
            Notification notification = builder.build();
            startForeground(0, notification);
            Log.e("home_button","home button");
        } else {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                    .setContentTitle(getString(R.string.app_name))
                    .setContentText("SmartTracker is Running...")
                    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                    .setAutoCancel(true);
            Notification notification = builder.build();
            startForeground(0, notification);
            Log.e("home_button_value","home_button_value");

        }
        return super.onStartCommand(intent, flags, startId);

    }
}

संपादित करें: सावधानी! startForeground फ़ंक्शन पहले तर्क के रूप में 0 नहीं ले सकता है, यह एक अपवाद बढ़ाएगा! इस उदाहरण में गलत फ़ंक्शन कॉल है, 0 को अपने स्वयं के कॉस्ट में बदलें जो 0 नहीं हो सकता है या अधिकतम (Int32) से अधिक हो सकता है


बस एक सिर ऊपर के रूप में मैं इस पर कई घंटे रास्ता बर्बाद कर दिया। मुझे यह अपवाद तब भी मिलता रहा जब मैं startForeground(..) को startForeground(..) में पहली चीज कह रहा था। अंत में मैंने पाया कि समस्या NOTIFICATION_ID = 0 का उपयोग करने के कारण हुई थी। किसी अन्य मान का उपयोग करना इसे ठीक करना प्रतीत होता है।


मुझे पता है, बहुत सारे उत्तर पहले ही प्रकाशित हो चुके हैं, हालांकि सच्चाई यह है - startForegroundService को एक ऐप स्तर पर तय नहीं किया जा सकता है और आपको इसका उपयोग बंद कर देना चाहिए। Context # startForegroundService () के बाद 5 सेकंड के भीतर सेवा # startForeground () API का उपयोग करने के लिए Google की सिफारिश को कुछ ऐसा नहीं कहा जा सकता है जो एक ऐप हमेशा कर सकता है।

एंड्रॉइड एक साथ बहुत सारी प्रक्रियाएं चलाता है और इसमें कोई गारंटी नहीं है कि लूपर आपकी लक्ष्य सेवा को कॉल करेगा जिसे 5 सेकंड के भीतर startForeground () कॉल करना है। यदि आपकी लक्ष्य सेवा 5 सेकंड के भीतर कॉल प्राप्त नहीं करती है, तो आप भाग्य से बाहर हैं और आपके उपयोगकर्ता ANR स्थिति का अनुभव करेंगे। आपके स्टैक ट्रेस में आपको कुछ इस तरह दिखाई देगा:

Intent intent = new Intent(context,
                YourService.class);
intent.putExtra("request_stop", true);
context.startService(intent);

जैसा कि मैं समझता हूं, लूपर ने यहां कतार का विश्लेषण किया है, एक "अपमानजनक" पाया और बस इसे मार दिया। सिस्टम अभी खुश और स्वस्थ है, जबकि डेवलपर्स और उपयोगकर्ता नहीं हैं, लेकिन चूंकि Google सिस्टम के लिए अपनी जिम्मेदारियों को सीमित करता है, इसलिए उन्हें बाद के दो के बारे में क्यों ध्यान रखना चाहिए? जाहिर है वे नहीं है। क्या वे इसे बेहतर बना सकते थे? बेशक, उदाहरण के लिए, वे "एप्लिकेशन व्यस्त है" संवाद कर सकते हैं, उपयोगकर्ता को ऐप का इंतजार करने या मारने के बारे में निर्णय लेने के लिए कह सकते हैं, लेकिन परेशान क्यों होते हैं, यह उनकी जिम्मेदारी नहीं है। मुख्य बात यह है कि सिस्टम अब स्वस्थ है।

मेरी टिप्पणियों से, यह अपेक्षाकृत कम ही होता है, मेरे मामले में 1K उपयोगकर्ताओं के लिए एक महीने में लगभग 1 दुर्घटना। इसे फिर से प्रस्तुत करना असंभव है, और भले ही इसे पुन: पेश किया जाए, कुछ भी नहीं है जो आप इसे स्थायी रूप से ठीक करने के लिए कर सकते हैं।

इस धागे में "स्टार्ट" के बजाय "बाइंड" का उपयोग करने के लिए एक अच्छा सुझाव था और फिर जब सेवा तैयार हो जाती है, तो onServiceConnected प्रक्रिया करें, लेकिन फिर, इसका मतलब है कि startForegroundService कॉल का उपयोग बिल्कुल न करें।

मुझे लगता है, Google की ओर से सही और ईमानदार कार्रवाई सभी को बताना होगा कि startForegourndServcie में एक कमी है और इसका उपयोग नहीं किया जाना चाहिए।

क्यू अभी भी बनी हुई है: इसके बजाय क्या उपयोग करना है? हमारे लिए सौभाग्य से, अब जॉबस्क्राइडर और जॉब सर्विस हैं, जो अग्रभूमि सेवाओं के लिए एक बेहतर विकल्प हैं। यह एक बेहतर विकल्प है, इस वजह से:

जब कोई नौकरी चल रही होती है, तो सिस्टम आपके ऐप की ओर से एक वैकलॉक रखता है। इस कारण से, आपको यह गारंटी देने के लिए कोई कार्रवाई करने की आवश्यकता नहीं है कि डिवाइस नौकरी की अवधि के लिए जागता है।

इसका मतलब है कि आपको अब वैकलॉक्स को संभालने की परवाह करने की आवश्यकता नहीं है और इसीलिए यह अग्रभूमि सेवाओं से अलग नहीं है। कार्यान्वयन से पीओवी जॉबस्क्राइडर आपकी सेवा नहीं है, यह एक प्रणाली है, संभवतः यह कतार को सही तरीके से संभाल लेगा, और Google कभी भी अपने बच्चे को समाप्त नहीं करेगा :)

सैमसंग ने अपने सैमसंग ऐक्सेसरी प्रोटोकॉल (SAP) में StartForegroundService से JobScheduler और JobService में स्विच किया है। यह बहुत उपयोगी है जब स्मार्टवॉच जैसे उपकरणों को फोन जैसे मेजबानों से बात करने की आवश्यकता होती है, जहां ऐप के मुख्य धागे के माध्यम से उपयोगकर्ता के साथ काम करने की आवश्यकता होती है। चूंकि नौकरियों को अनुसूचक द्वारा मुख्य धागे में पोस्ट किया जाता है, इसलिए यह संभव हो जाता है। हालांकि आपको याद रखना चाहिए कि नौकरी मुख्य धागे पर चल रही है और सभी भारी सामान को अन्य थ्रेड्स और एसिंक्स कार्यों में लोड करना है।

यह सेवा आपके एप्लिकेशन के मुख्य थ्रेड पर चल रहे हैंडलर पर आने वाली प्रत्येक नौकरी को निष्पादित करती है। इसका मतलब है कि आपको अपने निष्पादन तर्क को अपने चयन के दूसरे थ्रेड / हैंडलर / AsyncTask पर लोड करना होगा

JobScheduler / JobService पर स्विच करने का एकमात्र नुकसान यह है कि आपको पुराने कोड को रिफलेक्टर करने की आवश्यकता होगी, और यह मज़ेदार नहीं है। मैंने पिछले दो दिन बिताए हैं कि नए सैमसंग एसएपी कार्यान्वयन का उपयोग करें। मैं अपनी क्रैश रिपोर्ट देखूंगा और आपको बता दूंगा कि क्या क्रैश फिर से दिखाई देंगे। सैद्धांतिक रूप से ऐसा नहीं होना चाहिए, लेकिन हमेशा ऐसे विवरण होते हैं जिनके बारे में हमें जानकारी नहीं हो सकती है।

अद्यतन करें Play Store द्वारा रिपोर्ट की गई कोई और क्रैश नहीं है। इसका मतलब यह है कि जॉबस्क्राइडर / जॉब सर्विस को इस तरह की समस्या नहीं है और इस मॉडल पर स्विच करना एक बार और हमेशा के लिए startForegroundService इश्यू से छुटकारा पाने का सही तरीका है। मुझे उम्मीद है, Google / Android इसे पढ़ता है और अंततः सभी के लिए एक आधिकारिक मार्गदर्शन प्रदान करेगा / टिप्पणी करेगा / सलाह देगा।


मेरे पास एक widget जो डिवाइस के जागने पर अपेक्षाकृत लगातार अपडेट करता है और मुझे कुछ ही दिनों में हजारों क्रैश दिखाई दे रहे थे।

मुद्दा ट्रिगर

मैंने अपने पिक्सेल 3 एक्सएल पर भी इस मुद्दे पर ध्यान दिया, जब मैंने सोचा था कि डिवाइस में बहुत अधिक लोड नहीं होगा। और किसी भी और सभी कोड पथ startForeground() साथ कवर किए गए थे। लेकिन तब मुझे महसूस हुआ कि कई मामलों में मेरी सेवा को वास्तव में जल्दी काम मिल जाता है। मेरा मानना ​​है कि मेरे ऐप के लिए ट्रिगर यह था कि सेवा समाप्त हो रही थी इससे पहले कि सिस्टम वास्तव में एक अधिसूचना दिखाने के लिए चारों ओर हो गया।

समाधान / समाधान

मैं सभी दुर्घटनाओं से छुटकारा पाने में सक्षम था। मैंने जो कुछ किया वह stopSelf() को हटाने के लिए stopSelf() (जब तक मैं निश्चित रूप से सूचना नहीं दिखा रहा था, तब तक मैं स्टॉप में देरी के बारे में सोच रहा था, लेकिन मैं नहीं चाहता कि उपयोगकर्ता अधिसूचना देखें यदि यह आवश्यक नहीं है।) जब सेवा एक मिनट या सिस्टम के लिए निष्क्रिय हो गई है। बिना किसी अपवाद के फेंकने से यह सामान्य रूप से नष्ट हो जाता है।

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    stopForeground(true);
} else {
    stopSelf();
}

मैं इस मुद्दे पर शोध कर रहा हूं और यही मैंने अब तक खोजा है। यदि हमारे पास इसके समान कोड है तो यह दुर्घटना हो सकती है:

MyForegroundService.java

public class MyForegroundService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(...);
    }
}

MainActivity.java

Intent serviceIntent = new Intent(this, MyForegroundService.class);
startForegroundService(serviceIntent);
...
stopService(serviceIntent);

अपवाद को कोड के निम्नलिखित ब्लॉक में फेंक दिया जाता है:

ActiveServices.java

private final void bringDownServiceLocked(ServiceRecord r) {
    ...
    if (r.fgRequired) {
        Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
                  + r);
        r.fgRequired = false;
        r.fgWaiting = false;
        mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),
                    AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName);
        mAm.mHandler.removeMessages(
                    ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
        if (r.app != null) {
            Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
            msg.obj = r.app;
            msg.getData().putCharSequence(
                ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
            mAm.mHandler.sendMessage(msg);
         }
    }
    ...
}

इस विधि को MyForegroundService के MyForegroundService onCreate() से पहले निष्पादित किया जाता है क्योंकि एंड्रॉइड मुख्य थ्रेड हैंडलर पर सेवा के निर्माण को शेड्यूल करता है लेकिन bringDownServiceLocked जाता है BinderThread को एक BinderThread पर बुलाया जाता है, जो एक दौड़ की स्थिति है। इसका मतलब है कि MyForegroundService पास startForeground को कॉल करने का मौका नहीं था जो दुर्घटना का कारण होगा।

इसे ठीक करने के लिए हमें यह सुनिश्चित करना होगा कि bringDownServiceLocked के MyForegroundService onCreate() से पहले bringDownServiceLocked को नहीं बुलाया गया है।

public class MyForegroundService extends Service {

    private static final String ACTION_STOP = "com.example.MyForegroundService.ACTION_STOP";

    private final BroadcastReceiver stopReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            context.removeStickyBroadcast(intent);
            stopForeground(true);
            stopSelf();
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        startForeground(...);
        registerReceiver(
            stopReceiver, new IntentFilter(ACTION_STOP));
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(stopReceiver);
    }

    public static void stop(Context context) {
        context.sendStickyBroadcast(new Intent(ACTION_STOP));
    }
}

चिपचिपा प्रसारणों का उपयोग करके हम यह सुनिश्चित करते हैं कि प्रसारण लुप्त न हो जाए और stopReceiver को स्टॉप आशय प्राप्त हो, क्योंकि यह MyForegroundService के MyForegroundService onCreate() में पंजीकृत हो गया है। इस समय तक हम पहले ही startForeground(...) चुके हैं। हमें अगली बार अधिसूचित स्टॉपराइवर को रोकने के लिए उस चिपचिपे प्रसारण को भी हटाना होगा।

कृपया ध्यान दें कि विधि sendStickyBroadcast को पदावनत किया गया है और मैं इस समस्या को ठीक करने के लिए इसे केवल अस्थायी समाधान के रूप में उपयोग करता हूं।


मैं एक ही मुद्दे का सामना कर रहा हूँ और समय बिताने के बाद एक विलेयन्स मिला जिसे आप नीचे दिए गए कोड में आज़मा सकते हैं यदि आपकी Service का उपयोग कर रहे हैं, तो इस कोड को onCreate में रखें या फिर Intent Intent Service का उपयोग करके इस कोड को onHandleIntent में डालें।

if (Build.VERSION.SDK_INT >= 26) {
        String CHANNEL_ID = "my_app";
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                "MyApp", NotificationManager.IMPORTANCE_DEFAULT);
        ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("")
                .setContentText("").build();
        startForeground(1, notification);
    }

मैंने कुछ दिनों के लिए इस पर शोध किया है और समाधान प्राप्त किया है। अब Android O में आप नीचे की तरह बैकग्राउंड लिमिटेशन सेट कर सकते हैं

जिस सेवा को सेवा वर्ग कह रहा है

Intent serviceIntent = new Intent(SettingActivity.this,DetectedService.class);
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){

                        SettingActivity.this.startForegroundService(serviceIntent);
                    }else{
                        startService(serviceIntent);
                    }

और सेवा वर्ग जैसा होना चाहिए

public class DetectedService extends Service { 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        int NOTIFICATION_ID = (int) (System.currentTimeMillis()%10000);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(NOTIFICATION_ID, new Notification.Builder(this).build());
        }


        // Do whatever you want to do here
    }
}

मैंने तब सेवा शुरू करने के लिए ContextCompat.startForegroundService(this, intent) कहा

सर्विस onCreate

 @Override
 public void onCreate() {
        super.onCreate();

        if (Build.VERSION.SDK_INT >= 26) {
            String CHANNEL_ID = "my_channel_01";
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);

            ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);

            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle("")
                    .setContentText("").build();

            startForeground(1, notification);
        }
}

यह त्रुटि एंड्रॉइड 8+ पर भी होती है जब Service.startForeground (int id, Notification notification) को कॉल किया जाता है जबकि आईडी 0 पर सेट हो जाता है।

आईडी इंट: अधिसूचना अधिसूचना के अनुसार इस अधिसूचना के लिए पहचानकर्ता। सूचना (इंट, अधिसूचना); 0 नहीं होना चाहिए


यह समस्या क्यों हो रही है, क्योंकि एंड्रॉइड फ्रेमवर्क 5 सेकंड के भीतर आपकी सेवा शुरू होने की गारंटी नहीं दे सकता है, लेकिन दूसरी ओर फ्रेमवर्क की सख्त सीमा है 5 सेकंड के भीतर अग्रभूमि अधिसूचना को निकाल दिया जाना चाहिए, अगर जांच के बिना कि फ्रेमवर्क ने सेवा शुरू करने की कोशिश की है। ।

यह निश्चित रूप से एक फ्रेमवर्क मुद्दा है, लेकिन इस मुद्दे का सामना करने वाले सभी डेवलपर्स अपना सर्वश्रेष्ठ प्रदर्शन नहीं कर रहे हैं:

  1. startForeground एक अधिसूचना onStartCommand और onStartCommand दोनों में होनी चाहिए, क्योंकि यदि आपकी सेवा पहले से ही बनाई गई है और किसी तरह आपकी गतिविधि इसे फिर से शुरू करने की कोशिश कर रही है, तो onCreate नहीं कहा जाएगा।

  2. नोटिफिकेशन आईडी 0 नहीं होनी चाहिए अन्यथा दुर्घटना हो जाएगी, यह भी एक ही कारण नहीं है।

  3. stopSelf से पहले stopSelf को नहीं बुलाया जाना चाहिए।

3 से ऊपर सभी के साथ इस समस्या को थोड़ा कम किया जा सकता है, लेकिन अभी भी एक फिक्स नहीं है, असली फिक्स या मान लें कि वर्कअराउंड अपने लक्ष्य एसडीके संस्करण को 25 पर डाउनग्रेड करना है।

और ध्यान दें कि सबसे अधिक संभावना एंड्रॉइड पी अभी भी इस मुद्दे को ले जाएगा क्योंकि Google यह समझने से भी इनकार करता है कि क्या चल रहा है और यह नहीं मानता कि यह उनकी गलती है, अधिक जानकारी के लिए issuetracker.google.com/issues/76112072#comment36 और issuetracker.google.com/issues/76112072#comment56 पढ़ें


एंड्रॉइड 8.0 व्यवहार परिवर्तन पर Google के डॉक्स से:

सिस्टम ऐप्स को पृष्ठभूमि में रहते हुए भी Context.startForegroundService () को कॉल करने की अनुमति देता है। हालाँकि, ऐप को सेवा बनने के पांच सेकंड के भीतर उस सेवा के स्टार्टफोरग्राउंड () विधि को कॉल करना होगा।

समाधान: उस Service लिए startForeground() में startForeground() कॉल करें जो आप startForeground() का उपयोग करते हैं

इसे भी देखें: एंड्रॉइड 8.0 (Oreo) के लिए पृष्ठभूमि निष्पादन सीमाएं


https://developer.android.com/reference/android/content/Context.html#startForegroundService(android.content.Intent)

StartService (इरादे) के समान है, लेकिन एक अंतर्निहित वादे के साथ कि सेवा शुरू होने के बाद startForeground (int, android.app.Notification) को कॉल करेगी। सेवा को ऐसा करने के लिए ANR अंतराल के बराबर समय दिया जाता है, अन्यथा सिस्टम स्वचालित रूप से सेवा बंद कर देगा और ऐप ANR घोषित करेगा।

साधारण प्रारंभ सेवा (इरादे) के विपरीत, इस पद्धति का उपयोग किसी भी समय किया जा सकता है, भले ही सेवा की मेजबानी करने वाला ऐप एक अग्रभूमि में हो।

सुनिश्चित करें कि आप onCreate ( Service.startForeground(int, android.app.Notification) पर Service.startForeground(int, android.app.Notification) को कॉल करते हैं Service.startForeground(int, android.app.Notification) इसलिए आप यह सुनिश्चित करते हैं कि इसे कॉल किया जाएगा। यदि आपके पास कोई शर्त है जो आपको ऐसा करने से रोक सकती है, तो आप बेहतर बंद कर देंगे। सामान्य Context.startService(Intent) का उपयोग करके और स्वयं Service.startForeground(int, android.app.Notification) कॉल करें।

ऐसा लगता है कि Context.startForegroundService() को नष्ट करने से पहले आप Service.startForeground(int, android.app.Notification) नामक एक वॉचडॉग जोड़ता है ...





android-8.0-oreo