Android 8.0: java.lang.IllegalStateException: सेवा आशय शुरू करने की अनुमति नहीं है


359

एप्लिकेशन लॉन्च पर, ऐप उस सेवा को शुरू करता है जिसे कुछ नेटवर्क कार्य करना चाहिए। एपीआई स्तर 26 को लक्षित करने के बाद, मेरा एप्लिकेशन पृष्ठभूमि पर एंड्रॉइड 8.0 पर सेवा शुरू करने में विफल रहता है।

इसके कारण: java.lang.IllegalStateException: सेवा शुरू करने की अनुमति नहीं है {cmp = my.app.tt / com.my.service}: एप्लिकेशन पृष्ठभूमि में है UidRecord (90372b1 u0a136 CEM आइडल प्रोक्स: 1 seq (0,0q) , 0)}

जैसा कि मैंने इसे संबंधित समझा: पृष्ठभूमि निष्पादन सीमा

StartService () विधि अब एक IllegalStateException को फेंकता है यदि एंड्रॉइड 8.0 को लक्षित करने वाला ऐप उस स्थिति में उस पद्धति का उपयोग करने की कोशिश करता है जब उसे पृष्ठभूमि सेवाओं को बनाने की अनुमति नहीं होती है।

" ऐसी स्थिति में जब इसकी अनुमति नहीं है " - इसका वास्तव में क्या मतलब है ?? और इसे कैसे ठीक करें। मैं अपनी सेवा को "अग्रभूमि" के रूप में सेट नहीं करना चाहता


4
इसका मतलब है कि जब आपका ऐप बैकग्राउंड में होगा तो आप एक सेवा शुरू नहीं कर सकते हैं
टिम

22
इसका रनटाइम अनुमतियों से कोई लेना-देना नहीं है
टिम

10
के startForegroundService()बजाय का उपयोग करें startService()
मेंढक

2
आप targetSdkVersion 25 का उपयोग करने का प्रयास कर सकते हैं, लेकिन compileSdkVersion 26 के साथ संकलित कर सकते हैं। इस तरह आप एंड्रॉइड 8 और नवीनतम सपोर्ट लाइब्रेरी से नई कक्षाओं का उपयोग कर सकते हैं, लेकिन आपका ऐप बैकग्राउंड एक्ज़ीक्यूशन लिमिट्स द्वारा सीमित नहीं होगा।
केकेर डेज़ीबेक

2
@KacperDziubek काम करना चाहिए लेकिन एक अस्थायी समाधान है क्योंकि 2018 के पतन में SDK26 को लक्षित करना आवश्यक होगा।
RightHandedMonkey

जवाबों:


194

अनुमत परिस्थितियाँ एक अस्थायी श्वेतसूची हैं जहाँ पृष्ठभूमि सेवा Android O से पहले की तरह ही व्यवहार करती है।

कुछ परिस्थितियों में, एक पृष्ठभूमि ऐप को कई मिनटों के लिए एक अस्थायी श्वेतसूची में रखा जाता है। जबकि एक ऐप वाइटेलिस्ट पर है, यह बिना किसी सीमा के सेवाओं को लॉन्च कर सकता है, और इसकी पृष्ठभूमि सेवाओं को चलाने की अनुमति है। एक ऐप को श्वेतसूची में रखा जाता है जब वह उपयोगकर्ता को दिखाई देने वाले कार्य को संभालता है, जैसे:

  • एक उच्च प्राथमिकता वाले फायरबेस क्लाउड मैसेजिंग (FCM) संदेश को संभालना।
  • एक प्रसारण प्राप्त करना, जैसे कि एसएमएस / एमएमएस संदेश।
  • एक अधिसूचना से एक लंबित निष्पादन।
  • वीपीएन ऐप शुरू करने से पहले वीपीएन सेवा शुरू करने से पहले ही यह स्पष्ट हो जाता है।

स्रोत: https://developer.android.com/about/versions/oreo/background.html

तो दूसरे शब्दों में यदि आपकी पृष्ठभूमि सेवा श्वेतसूची आवश्यकताओं को पूरा नहीं करती है तो आपको नए जॉबस्क्राइडर का उपयोग करना होगा । यह मूल रूप से एक पृष्ठभूमि सेवा के समान है, लेकिन इसे लगातार पृष्ठभूमि में चलने के बजाय समय-समय पर कहा जाता है।

यदि आप एक IntentService का उपयोग कर रहे हैं, तो आप एक JobIntentService में बदल सकते हैं। नीचे देखें @ kosev का जवाब


"उच्च" पुजारी के GCM संदेश प्राप्त करने के ठीक बाद मैं सेवा शुरू करना चाहता हूं तो मुझे एक दुर्घटना हो रही है। मैं अभी भी GCM: "com.google.android.gms: play-services-gcm: 11.4.2" का उपयोग करता हूं, न कि 'com.google.firebase: firebase- मैसेजिंग: 11.4.2'। हालांकि यह निश्चित नहीं है कि यह मायने रखता है ..
एलेक्स रेडज़िशेव्स्की

"यह मूल रूप से पृष्ठभूमि सेवा के समान है, लेकिन इसे लगातार पृष्ठभूमि में चलने के बजाय समय-समय पर कहा जाता है।" - यह सुनिश्चित नहीं करें कि आप इसका क्या मतलब है, क्योंकि एंड्रॉइड सेवाओं ने कभी भी लगातार निष्पादित नहीं किया है। वे शुरू करते हैं, दौड़ते हैं, फिर बंद हो जाते हैं।
मेल्वार

2
क्या FirebaseInstanceIdService इसका onTokenRefreshतरीका उच्च प्राथमिकता वाला FCM संदेश है?
कॉर्ड रेहान

@phnmnn नहीं, GCMTaskService वास्तव में FCM का पालन नहीं करता है इसलिए वे काम नहीं करते हैं।
अभिनव उपाध्याय

4
क्या आपको JobScheduler या अन्य के बजाय WorkManager (यहां: developer.android.com/topic/lbooks/altecture/workmanager ) का उपयोग नहीं करना चाहिए ? मेरा यह मतलब है: youtu.be/IrKoBFLwTN0
Android डेवलपर

254

मुझे हल मिल गया। पूर्व 8.0 उपकरणों के लिए, आपको बस उपयोग करना होगा startService(), लेकिन 7.0 के बाद के उपकरणों के लिए, आपको उपयोग करना होगा startForgroundService()। सेवा शुरू करने के लिए कोड के लिए यहाँ नमूना है।

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(new Intent(context, ServedService.class));
    } else {
        context.startService(new Intent(context, ServedService.class));
    }

और सेवा वर्ग में, अधिसूचना के लिए कृपया नीचे कोड जोड़ें:

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

जहां O एंड्रॉइड का 26 वर्जन है।


9
एक अग्रभूमि सेवा ऐसी चीज है जिसके बारे में उपयोगकर्ता को पता होगा और इसके लिए एक अधिसूचना की आवश्यकता होती है। यदि यह बहुत लंबा चलता है तो यह भी ANR होगा। तो यह वास्तव में एक उपयुक्त जवाब नहीं है अगर ऐप पहले से ही पृष्ठभूमि में चल रहा है।
सिमोन

80
ContextCompat.startForegroundService(...)इसके बदले इस्तेमाल किया जा सकता है कि एक समर्थन में है।
jayeffkay

37
वह कोई हल नहीं है।
जैकसोफ

17
मैं यह भी मानता हूं कि यह कोई समाधान नहीं है। यह एक वर्कअराउंड है और यह मदद करता है, लेकिन ओरेओ में पृष्ठभूमि की सीमाएं एक कारण के लिए पेश की गई थीं। इस तरह से उन सीमाओं को दरकिनार करना निश्चित रूप से सही दृष्टिकोण नहीं है (भले ही यह काम करता है)। सबसे अच्छा तरीका JobScheduler (स्वीकृत उत्तर को देखें) का उपयोग करना है।
व्रतिस्लाव जिंद

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

85

सबसे अच्छा तरीका JobIntentService का उपयोग करना है जो कि उपलब्ध नहीं होने पर Oreo या पुरानी सेवाओं के लिए नए JobScheduler का उपयोग करता है।

अपनी घोषणा में घोषणा करें:

<service android:name=".YourService"
         android:permission="android.permission.BIND_JOB_SERVICE"/>

और आपकी सेवा में आपको ऑनहैंडलवर्क को ऑनहैंडलवर्क से बदलना होगा:

public class YourService extends JobIntentService {

    public static final int JOB_ID = 1;

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, YourService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // your code
    }

}

फिर आप के साथ अपनी सेवा शुरू करते हैं:

YourService.enqueueWork(context, new Intent());


आप एक गैर-स्थैतिक विधि को एक स्थिर विधि के अंदर कैसे कॉल कर सकते हैं? क्या आप समझा सकते हैं?
मैडी

@ मैडी enqueueWork(...)एक स्थिर विधि है।
hgoebl

2
आप YourService.enqueueWork (संदर्भ, नई आशय ()) को कहां कहेंगे; ? प्रसारण रिसीवर से?
TheLearner

मुझे विश्वास नहीं होता कि यह सबसे आसान उपाय है। WorkManager के बारे में नीचे मेरी टिप्पणी देखें। यह उपयुक्त होने पर JobIntentService का उपयोग करता है, लेकिन इसमें बहुत कम बॉयलर प्लेट है।
Tale

36

सेवा एक पृष्ठभूमि सूत्र में बढ़ा कर चल रहा है IntentService, तो आप बदल सकते हैं IntentServiceके साथ JobIntentServiceजो Android समर्थन लाइब्रेरी के भाग के रूप प्रदान की जाती है

उपयोग करने JobIntentServiceका लाभ यह है कि यह IntentServiceपूर्व-ओ उपकरणों पर और ओ और उच्चतर पर व्यवहार करता है, यह इसे नौकरी के रूप में भेजता है

JobSchedulerसमय-समय पर / मांग वाली नौकरियों के लिए भी इस्तेमाल किया जा सकता है। लेकिन, बैकवर्ड संगतता को संभालने के लिए सुनिश्चित करें क्योंकि JobSchedulerएपीआई केवल एपीआई 21 से उपलब्ध है


1
JobIntentService के साथ समस्या यह है कि एंड्रॉइड आपके काम को मनमाने ढंग से शेड्यूल कर सकता है, और इसे IntentService के विपरीत, कुछ छेड़छाड़ के बिना अंतर्निहित रूप से शुरू नहीं किया जा सकता है। देखें stackoverflow.com/questions/52479262/...
kilokahn

15

में Oreo एंड्रॉयड परिभाषित पृष्ठभूमि सेवाओं तक सीमित करता है

उपयोगकर्ता अनुभव को बेहतर बनाने के लिए, एंड्रॉइड 8.0 (एपीआई स्तर 26) पृष्ठभूमि में चलने के दौरान एप्लिकेशन क्या कर सकता है, इस पर सीमाएं लगाता है।

फिर भी यदि आपको हमेशा चलने वाली सेवा की आवश्यकता है, तो आप अग्रभूमि सेवा का उपयोग कर सकते हैं।

बैकग्राउंड सर्विस लिमिटेशन: जबकि एक ऐप बेकार है, इसके बैकग्राउंड सेवाओं के उपयोग की सीमाएँ हैं। यह अग्रभूमि सेवाओं पर लागू नहीं होता है, जो उपयोगकर्ता के लिए अधिक ध्यान देने योग्य हैं।

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

एक समाधान अगर -

आप अपनी सेवा के लिए एक अधिसूचना नहीं चाहते हैं?

आप समय-समय पर कार्य कर सकते हैं, 1. यह आपकी सेवा शुरू करता है, 2. सेवा अपना काम करेगी और 3. खुद को रोकती है। इसके द्वारा आपके ऐप को बैटरी ड्रेनिंग नहीं माना जाएगा।

आप अलार्म मैनेजर , जॉब शेड्यूलर , एवरनोट-जॉब्स या वर्क मैनेजर के साथ आवधिक कार्य का उपयोग कर सकते हैं ।

मैंने वर्क-मैनेजर के साथ हमेशा चलने वाली सेवा का परीक्षण किया है।


WorkManager जाने के लिए सबसे अच्छा तरीका है, ऐसा लगता है कि काम को तुरंत निष्पादित नहीं करना है। यह एपीआई 14 के पीछे संगत है, एपीआई 23+ वाले उपकरणों पर जॉबसैकिलर का उपयोग करते हुए और एपीआई 14-22 के साथ उपकरणों पर ब्रॉडकास्टसीवर + अलार्ममैनेजर का संयोजन
जेम्स एलन

WorkManager के बारे में महत्वपूर्ण बात यह है कि WorkManager उन कार्यों के लिए अभिप्रेत है, जो असाध्य हैं
अर्थात्,

13

हाँ, ऐसा इसलिए है क्योंकि आप अब एपीआई 26 पर पृष्ठभूमि में सेवाएं शुरू नहीं कर सकते हैं। इसलिए आप एपीआई 26 के ऊपर फोरग्राउंड सर्विस शुरू कर सकते हैं।

आपको उपयोग करना पड़ेगा

ContextCompat.startForegroundService(...)

और रिसाव को संसाधित करते समय एक अधिसूचना पोस्ट करें।


1
ओपी ने विशेष रूप से कहा कि वह अग्रभूमि के रूप में नहीं चाहते हैं। इसे एक टिप्पणी के रूप में या अधिक पूर्ण उत्तर के भाग के रूप में रखा जाना चाहिए।
रिकार्डो ए।

7

जैसा कि @kosev ने कहा कि उनके जवाब में आप JobIntentService का उपयोग कर सकते हैं। लेकिन मैं एक वैकल्पिक समाधान का उपयोग करता हूं - मैं IllegalStateException को पकड़ता हूं और सेवा को अग्रभूमि के रूप में शुरू करता हूं। उदाहरण के लिए, यह फ़ंक्शन मेरी सेवा शुरू करता है:

@JvmStatic
protected fun startService(intentAction: String, serviceType: Class<*>, intentExtraSetup: (Intent) -> Unit) {
    val context = App.context
    val intent = Intent(context, serviceType)
    intent.action = intentAction
    intentExtraSetup(intent)
    intent.putExtra(NEED_FOREGROUND_KEY, false)

    try {
        context.startService(intent)
    }
    catch (ex: IllegalStateException) {
        intent.putExtra(NEED_FOREGROUND_KEY, true)
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent)
        }
        else {
            context.startService(intent)
        }
    }
}

और जब मैं इरादे की प्रक्रिया करता हूं तो मैं ऐसी बात करता हूं:

override fun onHandleIntent(intent: Intent?) {
    val needToMoveToForeground = intent?.getBooleanExtra(NEED_FOREGROUND_KEY, false) ?: false
    if(needToMoveToForeground) {
        val notification = notificationService.createSyncServiceNotification()
        startForeground(notification.second, notification.first)

        isInForeground = true
    }

    intent?.let {
        getTask(it)?.process()
    }
}

मुझे आपकी कोशिश कैच सॉल्यूशन पसंद है। मेरे लिए यह एक समाधान है, क्योंकि कभी कभी context.startServiceपृष्ठभूमि में काम करता है - नहीं कभी कभी - केवल सबसे अच्छा तरीका है इस तरह दिखता है अन्यथा आप अपने मुख्य वर्ग में और अधिक कोड को लागू करने के लिए है extending Applicationऔर implementing ActivityLifecycleCallbacksऔर ट्रैक रखने लगाने देती है अग्रभूमि या पृष्ठभूमि में है और अपने इरादे शुरू तदनुसार।
पियरे

क्या यह अपवाद कैच हो सकता है?
thecr0w

5

से firebase रिलीज नोट्स , वे राज्य एंड्रॉयड हे के लिए समर्थन पहले 10.2.1 में जारी किया गया था (हालांकि मैं नवीनतम संस्करण का उपयोग की सलाह देते हैं)।

कृपया Android O के लिए नई फायरबेस मैसेजिंग निर्भरता जोड़ें

compile 'com.google.firebase:firebase-messaging:11.6.2'

जरूरत पड़ने पर google play services और google repositories को अपग्रेड करें।


यह सवाल का जवाब नहीं देता है, और न ही सवाल का फायरबेस से कोई लेना-देना है। इसे एक टिप्पणी के रूप में रखा जाना चाहिए।
रिकार्डो ए।

5

यदि ऐप के बैकग्राउंड में होने पर कोई इरादा पहले से ठीक था, तो यह एंड्रॉइड 8 और उससे ऊपर के किसी भी मामले में नहीं होगा। केवल उस अभिप्राय का जिक्र किया जा रहा है, जब बैकग्राउंड में ऐप होने पर कुछ प्रोसेसिंग करनी होती है।

नीचे दिए गए चरणों का पालन करना होगा:

  1. उपर्युक्त आशय के JobIntentServiceबजाय का उपयोग करना चाहिए IntentService
  2. वर्ग जो विस्तार करता है, उसे JobIntentServiceलागू करना चाहिए - onHandleWork(@NonNull Intent intent)विधि और विधि के नीचे होनी चाहिए, जो विधि को लागू करेगी onHandleWork:

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, xyz.class, 123, work);
    }
  3. enqueueWork(Context, intent)उस वर्ग से कॉल करें जहां आपका इरादा परिभाषित है।

    नमूना कोड:

    Public class A {
    ...
    ...
        Intent intent = new Intent(Context, B.class);
        //startService(intent); 
        B.enqueueWork(Context, intent);
    }

नीचे का वर्ग पहले सेवा वर्ग का विस्तार कर रहा था

Public Class B extends JobIntentService{
...

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, B.class, JobId, work);
    }

    protected void onHandleWork(@NonNull Intent intent) {
        ...
        ...
    }
}
  1. com.android.support:support-compatके लिए आवश्यक है JobIntentServiceमैं उपयोग - 26.1.0 V

  2. सबसे महत्वपूर्ण यह सुनिश्चित करने के लिए है कि फायरबेस पुस्तकालयों का संस्करण कम से कम हो 10.2.1, मेरे पास मुद्दे थे 10.2.0- अगर आपके पास कोई है!

  3. आपके प्रदर्शन में सेवा वर्ग के लिए निम्न अनुमति होनी चाहिए:

    service android:name=".B"
    android:exported="false"
    android:permission="android.permission.BIND_JOB_SERVICE"

उम्मीद है की यह मदद करेगा।


4

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

सबसे आसान उपाय नया आर्किटेक्चर घटक का उपयोग करना है जिसे वर्कमैनर कहा जाता है। आप यहाँ प्रलेखन की जाँच कर सकते हैं: https://developer.android.com/topic/libraries/architecture/workmanager/

आप बस अपने कार्यकर्ता वर्ग को परिभाषित करते हैं जो कार्यकर्ता का विस्तार करता है।

public class CompressWorker extends Worker {

    public CompressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Worker.Result doWork() {

        // Do the work here--in this case, compress the stored images.
        // In this example no parameters are passed; the task is
        // assumed to be "compress the whole library."
        myCompress();

        // Indicate success or failure with your return value:
        return Result.SUCCESS;

        // (Returning RETRY tells WorkManager to try this task again
        // later; FAILURE says not to try again.)
    }
}

जब आप इसे चलाना चाहते हैं तब आप शेड्यूल करते हैं।

    OneTimeWorkRequest compressionWork = 
        new OneTimeWorkRequest.Builder(CompressWorker.class)
            .build();
    WorkManager.getInstance().enqueue(compressionWork);

आसान! ऐसे कई तरीके हैं जिनसे आप श्रमिकों को कॉन्फ़िगर कर सकते हैं। यह आवर्ती नौकरियों का समर्थन करता है और आप ज़रूरत पड़ने पर जटिल चीज़ों का भी उपयोग कर सकते हैं। उम्मीद है की यह मदद करेगा।


3
वर्तमान में WorkManager अभी भी अल्फ़ा है।
19

3
05 मार्च, 2019 - वर्कमैनेजर 1.0.0 स्थिर रिलीज।
phnmnn

चौराहे या JobIntentService का उपयोग करने के बजाय WorkManager का उपयोग करना चाहिए
sivaBE35

1
WorkManager is intended for tasks that are deferrable—that is, not required to run immediately... यह सबसे आसान हो सकता है, हालांकि, मेरे ऐप को एक पृष्ठभूमि सेवा की आवश्यकता है जो उपयोगकर्ताओं के अनुरोधों को तुरंत निष्पादित करती है!
किसी ने

यदि आपको कार्य को तुरंत पूरा करने की आवश्यकता है, तो आपको अग्रभूमि सेवा का उपयोग करना चाहिए। उपयोगकर्ता एक सूचना देखेगा और जान सकता है कि आप काम कर रहे हैं। यदि आपको क्या उपयोग करने का निर्णय लेने में सहायता की आवश्यकता है, तो डॉक्स देखें। उनके पास बैकग्राउंड प्रोसेसिंग के लिए बहुत अच्छा गाइड है। डेवलपर
.android.com

4

JobScheduler का उपयोग करके वैकल्पिक समाधान, यह समय के नियमित अंतराल में पृष्ठभूमि में सेवा शुरू कर सकता है।

सबसे पहले क्लास का नाम Util.java रखा

import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;

public class Util {
// schedule the start of the service every 10 - 30 seconds
public static void schedulerJob(Context context) {
    ComponentName serviceComponent = new ComponentName(context,TestJobService.class);
    JobInfo.Builder builder = new JobInfo.Builder(0,serviceComponent);
    builder.setMinimumLatency(1*1000);    // wait at least
    builder.setOverrideDeadline(3*1000);  //delay time
    builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  // require unmetered network
    builder.setRequiresCharging(false);  // we don't care if the device is charging or not
    builder.setRequiresDeviceIdle(true); // device should be idle
    System.out.println("(scheduler Job");

    JobScheduler jobScheduler = null;
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
        jobScheduler = context.getSystemService(JobScheduler.class);
    }
    jobScheduler.schedule(builder.build());
   }
  }

फिर, JobService क्लास को TestJobService.java नाम दें

import android.app.job.JobParameters;
import android.app.job.JobService;
import android.widget.Toast;

  /**
   * JobService to be scheduled by the JobScheduler.
   * start another service
   */ 
public class TestJobService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
    Util.schedulerJob(getApplicationContext()); // reschedule the job
    Toast.makeText(this, "Bg Service", Toast.LENGTH_SHORT).show();
    return true;
}

@Override
public boolean onStopJob(JobParameters params) {
    return true;
  }
 }

उसके बाद ब्रॉडकास्ट रिसीवर वर्ग ने ServiceReceiver.java नाम दिया

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

 public class ServiceReceiver extends BroadcastReceiver {
 @Override
public void onReceive(Context context, Intent intent) {
    Util.schedulerJob(context);
 }
}

सर्विस और रिसीवर क्लास कोड के साथ मेनिफेस्ट फाइल अपडेट करें

<receiver android:name=".ServiceReceiver" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <service
        android:name=".TestJobService"
        android:label="Word service"
        android:permission="android.permission.BIND_JOB_SERVICE" >

    </service>

मुख्य maintctivity.java फ़ाइल के लिए मुख्य main_intent लॉन्चर जो डिफ़ॉल्ट रूप से बनाया गया है, और MainActivity.java फ़ाइल में परिवर्तन हैं

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Util.schedulerJob(getApplicationContext());
  }
 }

WOOAAH !! पृष्ठभूमि सेवा फोरग्राउंड सेवा के बिना शुरू होती है


2

अगर आप 8.0 पर अपना कोड चला रहे हैं तो एप्लिकेशन क्रैश हो जाएगा। इसलिए अग्रभूमि में सेवा शुरू करें। अगर नीचे 8.0 का उपयोग करें:

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
context.startService(serviceIntent);

यदि ऊपर या 8.0 है तो इसका उपयोग करें:

Intent serviceIntent = new Intent(context, RingtonePlayingService.class);
ContextCompat.startForegroundService(context, serviceIntent );

केवल उन मामलों के लिए फोरग्राउंड सेवाओं का उपयोग करने की सिफारिश की जाती है जहां उपयोगकर्ता को यह जानना होगा कि कोई सेवा चल रही है। विशिष्ट उदाहरण पृष्ठभूमि में संगीत बजाने के लिए है। ऐसे अन्य मामले हैं जो समझ में आते हैं, लेकिन आपको अपनी सभी सेवाओं को फ़ोरग्राउंड सेवाओं में परिवर्तित नहीं करना चाहिए। Google के आर्किटेक्चरल घटकों से WorkManager का उपयोग करने के लिए अपनी सेवाओं को परिवर्तित करने पर विचार करें जब आपको पृष्ठभूमि में कुछ काम करने की आवश्यकता होती है और गारंटी दी जाती है कि यह चलेगा।
16:14 पर टेल

startForegroundService को अनुमति की आवश्यकता है, अन्यथा java.lang.SecurityException: Permission Denial: startForeground from pid=13708, uid=10087 requires android.permission.FOREGROUND_SERVICE। फिक्स पर stackoverflow.com/a/52382711/550471
किसी ने कहीं न कहीं

1

यदि आपने फायरबेस संदेश धक्का अधिसूचना को एकीकृत किया है, तो,

पृष्ठभूमि निष्पादन सीमाओं के कारण Android O (Android 8.0) के लिए नई / अपडेट फायरबेस मैसेजिंग निर्भरता जोड़ें ।

compile 'com.google.firebase:firebase-messaging:11.4.0'

जरूरत पड़ने पर google play services और google repositories को अपग्रेड करें।

अपडेट करें:

 compile 'com.google.firebase:firebase-messaging:11.4.2'

0

के startForegroundService()बजाय का उपयोग करें startService() और startForeground(1,new Notification());सेवा शुरू करने के 5 सेकंड के भीतर अपनी सेवा में बनाने के लिए मत भूलना ।


2
ऐसा लगता है कि नया नोटिफ़िकेशन () एंड्रॉइड 8.1 से काम नहीं करता है; आपको नोटिफिकेशन के लिए चैनल बनाना चाहिए: stackoverflow.com/a/47533338/1048087
Prizoff

0

इस उत्तर पर विवादास्पद वोटों के कारण (इस संपादन के रूप में + ४ / ४), अन्य लोगों के पहले कृपया देखें और एक ही परिणाम के रूप में उपयोग करें । मैंने केवल एक बार एक नेटवर्किंग ऐप के लिए इसका उपयोग किया था जो रूट के रूप में चलता है और मैं सामान्य राय से सहमत हूं कि इस समाधान का उपयोग सामान्य परिस्थितियों में नहीं किया जाना चाहिए।

नीचे मूल उत्तर:

अन्य उत्तर सभी सही हैं, लेकिन मैं यह बताना चाहूंगा कि इसके लिए एक और तरीका यह है कि उपयोगकर्ता को आपके ऐप के लिए बैटरी ऑप्टिमाइज़ेशन अक्षम करने के लिए कहें (यह आमतौर पर एक अच्छा विचार नहीं है जब तक कि आपका ऐप सिस्टम से संबंधित नहीं है)। Google Play में आपके एप्लिकेशन को प्रतिबंधित किए बिना बैटरी ऑप्टिमाइज़ेशन से बाहर निकलने का अनुरोध करने के तरीके के लिए यह उत्तर देखें ।

आपको यह भी जांचना चाहिए कि क्रैश के माध्यम से रोकने के लिए आपके रिसीवर में बैटरी ऑप्टिमाइज़ेशन बंद हैं या नहीं:

if (Build.VERSION.SDK_INT < 26 || getSystemService<PowerManager>()
        ?.isIgnoringBatteryOptimizations(packageName) != false) {
    startService(Intent(context, MyService::class.java))
} // else calling startService will result in crash

1
अपने उपयोगकर्ताओं से पूछते हुए कि आपके पास जितना संभव हो उतना मुफ्त बैटरी का उपयोग करने के लिए एक मुफ्त पास है एक अच्छा समाधान नहीं है। अपने कोड को अधिक बैटरी अनुकूल समाधान में बदलने पर विचार करें। आपके उपयोगकर्ता आपको धन्यवाद देंगे।
टेल '

5
@ टैली नहीं हर पृष्ठभूमि सेवा का उपयोग JobSchedulerऔर सामान के साथ बैटरी के अनुकूल बनाया जा सकता है । कुछ एप्लिकेशनों को विशिष्ट सिंकिंग अनुप्रयोगों की तुलना में निचले स्तर पर काम करने की आवश्यकता होती है। यह एक वैकल्पिक समाधान है जब यह काम नहीं करता है।
माईगॉड

-17

onStartCommand में उपयोग न करें:

return START_NOT_STICKY

बस इसे बदलें:

return START_STICKY

और यह काम कर रहा है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.