কনটেক্সট.স্টার্টফোরগ্রাউন্ড সার্ভিস () তখন পরিষেবা.স্টার্টফোরগ্রাউন্ড () কল করেনি


257

আমি Serviceঅ্যান্ড্রয়েড ও ওএসে ক্লাস ব্যবহার করছি ।

আমি Serviceব্যাকগ্রাউন্ডে এটি ব্যবহার করার পরিকল্পনা করছি ।

অ্যান্ড্রয়েড ডকুমেন্টেশন বলে যে

যদি আপনার অ্যাপ্লিকেশনটি এপিআই স্তরের 26 বা ততোধিক লক্ষ্যকে লক্ষ্য করে, তবে অ্যাপ্লিকেশন নিজেই অগ্রভাগে না থাকলে সিস্টেম ব্যাকগ্রাউন্ড পরিষেবাগুলি ব্যবহার বা তৈরি করতে নিষেধাজ্ঞা আরোপ করে। যদি কোনও অ্যাপ্লিকেশনটির অগ্রভাগ পরিষেবা তৈরি করা দরকার হয় তবে অ্যাপটি কল করা উচিত startForegroundService()

আপনি যদি ব্যবহার startForegroundService()করেন Serviceতবে নিম্নলিখিত ত্রুটিটি ছুড়ে ফেলে।

Context.startForegroundService() did not then call
Service.startForeground() 

এতে দোষ কী?


IOW, দয়া করে একটি ন্যূনতম পুনরুত্পাদনযোগ্য উদাহরণ সরবরাহ করুন । এর মধ্যে পুরো জাভা স্ট্যাক ট্রেস এবং ক্র্যাশটিকে ট্রিগার করছে এমন কোড অন্তর্ভুক্ত থাকবে।
কমন্সওয়্যার

3
ত্রুটি এখনও এখানে 26 এপ্রিল 26 এবং 27 (27.0.3) এ রয়েছে। আক্রান্ত অ্যান্ড্রয়েড সংস্করণগুলি 8.0 এবং 8.1 হয় আপনি স্টার্টফোরগ্রাউন্ড () উভয়ই অনক্রিট () এবং অন স্টার্টকম্যান্ড () এ যোগ করে ক্র্যাশের সংখ্যা হ্রাস করতে পারেন তবে ক্র্যাশগুলি এখনও কিছু ব্যবহারকারীর জন্য ঘটবে। এটিএম ঠিক করার একমাত্র উপায় হ'ল আপনার বিল্ড.gradle এ টার্গেটএসডিকে ভার্সন 25।
অ্যালেক্স


আমি এখন এই কাজটি ব্যবহার করছি। মোহন এর
প্রসাদ পওয়ার

1
আমি একই সমস্যা আছে। আমি এই সমস্যাটি ঠিক করেছি। আমি এই বিষয়টিতে
বেয়াজিদ

উত্তর:


99

অ্যান্ড্রয়েড 8.0 এর আচরণের পরিবর্তনে গুগলের ডক্স থেকে :

অ্যাপ্লিকেশনটি ব্যাকগ্রাউন্ডে থাকা অবস্থায়ও সিস্টেম অ্যাপ্লিকেশনগুলিকে কনটেক্সট.স্টার্টফোরগ্রাউন্ড সার্ভিস () কল করতে অনুমতি দেয়। তবে অ্যাপ্লিকেশনটিকে পরিষেবাটি তৈরি হওয়ার পরে পাঁচ সেকেন্ডের মধ্যে সেই পরিষেবাটির স্টার্টফোরগ্রাউন্ড () পদ্ধতিতে কল করতে হবে।

সমাধান: আপনি যেটি ব্যবহার startForeground()করেন তার onCreate()জন্য কল করুনServiceContext.startForegroundService()

আরও দেখুন: অ্যান্ড্রয়েড 8.0 (ওরিও) এর জন্য পটভূমি সম্পাদন সীমা


19
আমি onStartCommandপদ্ধতিতে এটি করেছি, তবে আমি এখনও এই ত্রুটিটি পাচ্ছি। আমি startForegroundService(intent)আমার ফোন MainActivity। সম্ভবত পরিষেবাটি খুব ধীর শুরু হয়েছে। আমি মনে করি তারা অবিলম্বে পরিষেবা শুরু করার প্রতিশ্রুতি দেওয়ার আগে পাঁচ সেকেন্ডের সীমা থাকা উচিত নয়।
কিমি চিউ

29
5 সেকেন্ড সময়কাল অবশ্যই যথেষ্ট নয়, এই ব্যতিক্রমটি প্রায়শই ডিবাগ সেশনে ঘটে। আমি সন্দেহ করি এটি সময়ে সময়ে প্রকাশের মোডেও ঘটত। এবং চর্বি ছাড়াই এটি অ্যাপটিকে ক্র্যাশ করে! আমি এটিকে থ্রেড.সেটডফল্টউনকুটএক্সসেপশন হ্যান্ডলার () দিয়ে ধরার চেষ্টা করেছি, তবে এটি পেয়ে ও অ্যান্ড্রয়েড উপেক্ষা করেও অ্যাপ্লিকেশন হিমশীতল করে। হ্যান্ডেলমেজেজ () থেকে এই ব্যতিক্রমটি ট্রিগার করা হয়েছে এবং মূল লুপটি কার্যকরভাবে শেষ হয় ... কর্মক্ষেত্রের সন্ধানে।
সাউথারটন

আমি ব্রডকাস্ট রিসিভারে কনটেক্সট.স্টার্টফোরগ্রাউন্ড সার্ভিস () পদ্ধতিটি কল করেছি। তাহলে এই পরিস্থিতিতে কীভাবে পরিচালনা করবেন? কারণ অনক্রিট () ব্রডকাস্ট রিসিভারে উপলভ্য নয়
আনন্দ সাবজানি

6
@ সাউদারটন আমার মনে হয় এর onStartCommand()পরিবর্তে আপনার এটিকে কল করা উচিত onCreate, কারণ আপনি যদি পরিষেবাটি বন্ধ করে আবার চালু করেন তবে onStartCommand()এটি কল না করেই যেতে পারে onCreate...
অ্যান্ড্রয়েড বিকাশকারী

1
আমরা Google দল থেকে প্রতিক্রিয়া এখানে পরীক্ষা করতে পারবেন issuetracker.google.com/issues/76112072#comment56
Prags

82

আমি 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);
        }
}

47
আমিও. তবে আমি এখনও মাঝে মাঝে এই ত্রুটি পেয়ে যাচ্ছি। সম্ভবত অ্যান্ড্রয়েড গ্যারান্টি দিতে পারে না এটি onCreate5 সেকেন্ডের মধ্যে কল করবে । সুতরাং তারা আমাদের বিধিগুলি অনুসরণ করতে বাধ্য করার আগে তাদের এটি পুনরায় নকশা করা উচিত।
কিমি চিউ

5
আমি স্টার্টকমন্ডে () স্টার্টফোরগ্রাউন্ডে কল করছিলাম এবং আমি মাঝে মধ্যে এই ত্রুটি পেয়ে যাচ্ছিলাম। আমি এটি অনক্রিয়েটে স্থানান্তরিত করেছি এবং এটি (আঙ্গুলগুলি অতিক্রম করার) পরে দেখিনি।
টাইলার

4
এটি ওরিওতে একটি স্থানীয় বিজ্ঞপ্তি তৈরি করে যা বলেছে "APP_NAME চলমান running তথ্যটি বন্ধ করতে বা দেখতে টিপুন"। কীভাবে সেই বিজ্ঞপ্তিটি দেখানো বন্ধ করবেন?
আর্টিস্ট 404

6
না, অ্যান্ড্রয়েড টিম দাবি করেছে যে এটি উদ্দেশ্যমূলক আচরণ। সুতরাং আমি কেবল আমার অ্যাপ্লিকেশনটিকে নতুনভাবে ডিজাইন করেছি। এটি হাস্যকর। এই "উদ্দেশ্যমূলক আচরণ" এর কারণে সবসময় অ্যাপ্লিকেশনগুলিকে পুনরায় ডিজাইন করা প্রয়োজন। এটি তৃতীয়বার
কিমি চিউ

12
এই সমস্যার মূল কারণটি পরিষেবাটি অগ্রভাগে উন্নীত করার আগেই বন্ধ করা হয়েছিল। কিন্তু পরিষেবাটি নষ্ট হওয়ার পরে এই দাবিটি থামেনি। StopServiceকল করার পরে যোগ করে আপনি এটি পুনরুত্পাদন করার চেষ্টা করতে পারেন startForegroundService
কিমি চিউ

55

এই সমস্যাটি কেন ঘটছে তা হ'ল অ্যান্ড্রয়েড ফ্রেমওয়ার্ক আপনার সেবাটি 5 সেকেন্ডের মধ্যেই শুরু করার গ্যারান্টি দিতে পারে না তবে অন্যদিকে ফ্রেমওয়ার্কটি পরিষেবাটি শুরু করার চেষ্টা করেছিল কিনা তা পরীক্ষা না করেই 5 সেকেন্ডের মধ্যে অগ্রভাগের বিজ্ঞপ্তিটির কঠোর সীমাবদ্ধতা বরখাস্ত করা উচিত ।

এটি অবশ্যই একটি কাঠামোর সমস্যা, তবে এই সমস্যার মুখোমুখি সমস্ত বিকাশকারীরা তাদের সেরাটি করছেন না:

  1. startForegroundএকটি বিজ্ঞপ্তি অবশ্যই উভয় মধ্যেই থাকতে হবে onCreateএবং onStartCommandকারণ আপনার পরিষেবাটি ইতিমধ্যে তৈরি হয়ে থাকলে এবং কোনওভাবে যদি আপনার ক্রিয়াকলাপ আবার এটি শুরু করার চেষ্টা করে onCreateতবে ডাকা হবে না।

  2. বিজ্ঞপ্তি আইডি 0 হওয়া উচিত নয় অন্যথায় একই ক্রাশ ঘটবে এমনকি এটি একই কারণ নয়।

  3. stopSelfআগে বলা হবে না startForeground

উপরের 3 টির সাথে এই সমস্যাটি কিছুটা হ্রাস করা যায় তবে এখনও কোনও সমাধান নয়, আসল ফিক্স বা ধরা যাক ওয়ার্কআরাউন্ডটি আপনার টার্গেটের এসডিকে সংস্করণটি 25 এ ডাউনগ্রেড করা।

এবং মনে রাখবেন যে সম্ভবত অ্যান্ড্রয়েড পি এখনও এই সমস্যাটি বহন করবে কারণ গুগল কী চলছে তা বুঝতে এমনকি অস্বীকার করেছে এবং বিশ্বাস করে না যে এটি তাদের দোষ, আরও তথ্যের জন্য # 36 এবং # 56 পড়ুন


9
কেন অনক্রিট এবং অন স্টার্টকম্যান্ড উভয়? আপনি কি কেবল এটি স্টার্টকম্যান্ডে রাখতে পারেন?
rसेल

স্টপসেলফকে স্টার্টফোরগ্রাউন্ড => এর আগে বা সরাসরি এর পরে কল করা উচিত নয়, কারণ আপনি যখন করবেন তখন "স্টার্টফোরগ্রাউন্ড" বাতিল বলে মনে হচ্ছে।
ফ্রাঙ্ক

1
আমি কয়েকটি পরীক্ষা চালিয়েছি, এবং যদি পরিষেবাটি ইতিমধ্যে তৈরি করা হয়ে থাকে তবে অনক্রিট নাও বলা হয়, আপনাকে আবার স্টার্টফোরগ্রাউন্ডে কল করার দরকার নেই। অতএব আপনি এটি কেবলমাত্র অনক্রিট পদ্ধতিতে কল করতে পারেন এবং অন স্টার্টকমন্ডে নয়। সম্ভবত তারা পরিষেবাটির একক দৃষ্টিকোণটিকে প্রথম কল করার পরে অবধি পূর্বেরূপে হিসাবে বিবেচনা করে।
Lxu

আমি প্রাথমিক কলটির বিজ্ঞপ্তি আইডি হিসাবে 0 ব্যবহার করছি startForeground। এটিকে 1 এ পরিবর্তন করা আমার জন্য সমস্যাটি সমাধান করে (আশা করি)
এমআর 5

তাহলে সমাধান কি?
ইগোরগানাপলস্কি

35

আমি জানি, ইতিমধ্যে অনেকগুলি উত্তর প্রকাশিত হয়েছে, তবে সত্য - স্টার্টফোরগ্রাউন্ডসেসরিজ কোনও অ্যাপ স্তরে স্থির করা যায় না এবং আপনার এটি ব্যবহার বন্ধ করা উচিত। কনটেক্সট # স্টার্টফোরগ্রাউন্ডস সার্ভিস () বলা হওয়ার পরে 5 সেকেন্ডের মধ্যে সার্ভিস # স্টার্টফোরগ্রাউন্ড () এপিআই ব্যবহারের গুগলের পরামর্শটি কোনও অ্যাপ্লিকেশন সর্বদা করতে পারে এমন কিছু নয়।

অ্যান্ড্রয়েড একযোগে প্রচুর প্রক্রিয়া চালায় এবং এর কোনও গ্যারান্টি নেই যে লুপার আপনার টার্গেট পরিষেবাটিকে কল করবে যেটি 5 সেকেন্ডের মধ্যে স্টার্টফোরগ্রাউন্ডে () কল করার কথা। যদি আপনার টার্গেট পরিষেবাটি 5 সেকেন্ডের মধ্যে কলটি না পেয়ে থাকে তবে আপনি ভাগ্যের বাইরে এসেছেন এবং আপনার ব্যবহারকারীরা এএনআর পরিস্থিতি অনুভব করবেন। আপনার স্ট্যাক ট্রেসটিতে আপনি এরকম কিছু দেখতে পাবেন:

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)

আমি যেমন বুঝতে পেরেছি, লুপার এখানে সারিটি বিশ্লেষণ করেছে, একটি "গালিগালাজী" খুঁজে পেয়েছিল এবং কেবল এটি হত্যা করেছিল। সিস্টেমটি এখন সুখী এবং স্বাস্থ্যকর, যদিও বিকাশকারী এবং ব্যবহারকারীরা নন, তবে যেহেতু গুগল তাদের দায়িত্বগুলি সিস্টেমে সীমাবদ্ধ রাখে, তবে কেন তারা পরবর্তী দুটি সম্পর্কে যত্ন নেবে? স্পষ্টত তারা না। তারা কি এটি আরও ভাল করতে পারে? অবশ্যই, উদাহরণস্বরূপ, তারা "অ্যাপ্লিকেশন ব্যস্ত" ডায়লগটি পরিবেশন করতে পারত, কোনও ব্যবহারকারীকে অ্যাপটির অপেক্ষায় বা হত্যা করার বিষয়ে সিদ্ধান্ত নিতে বলত, তবে কেন বিরক্ত করবেন, এটি তাদের দায়িত্ব নয়। মূল বিষয়টি হ'ল সিস্টেমটি এখন সুস্থ।

আমার পর্যবেক্ষণগুলি থেকে, এটি তুলনামূলকভাবে খুব কমই ঘটে থাকে, আমার ক্ষেত্রে 1 কে ব্যবহারকারীদের জন্য এক মাসে প্রায় 1 ক্রাশ হয়। এটি পুনরুত্পাদন করা অসম্ভব এবং এটি পুনরুত্পাদন করা হলেও স্থায়ীভাবে স্থির করার জন্য আপনার করার মতো কিছুই নেই।

"সূচনা" এর পরিবর্তে "বাঁধাই" ব্যবহার করার জন্য এই থ্রেডে একটি ভাল পরামর্শ ছিল এবং তারপরে যখন পরিষেবা প্রস্তুত থাকে, onSecorConnected প্রক্রিয়া করুন, কিন্তু আবার, এর অর্থ স্টার্টফোরগ্রাউন্ডস সার্ভিস কলগুলি একেবারেই ব্যবহার না করা।

আমি মনে করি, গুগল পক্ষ থেকে সঠিক এবং সৎ পদক্ষেপটি প্রত্যেককে বলা হবে যে স্টার্টফোরগেন্ডসার্চির কোনও ঘাটতি রয়েছে এবং এটি ব্যবহার করা উচিত নয়।

প্রশ্নটি এখনও রয়ে গেছে: পরিবর্তে কী ব্যবহার করবেন? সৌভাগ্যক্রমে আমাদের জন্য, এখন চাকরিচুলক এবং জবস সার্ভিস রয়েছে, যা অগ্রভাগ পরিষেবাগুলির জন্য আরও ভাল বিকল্প। এটি এর চেয়ে ভাল বিকল্প, কারণ:

যখন কোনও কাজ চলছে তখন সিস্টেমটি আপনার অ্যাপের পক্ষ থেকে একটি জাগ্রত রাখবে lock এই কারণে, ডিভাইসটি কাজের সময়কালের জন্য জাগ্রত থাকে তার গ্যারান্টি দেওয়ার জন্য আপনার কোনও পদক্ষেপ নেওয়ার দরকার নেই।

এর অর্থ হ'ল আপনার আর জেগে থাকাগুলি পরিচালনা করার বিষয়ে যত্ন নেওয়ার দরকার নেই এবং এ কারণেই এটি পূর্বের পরিষেবাগুলি থেকে আলাদা নয়। বাস্তবায়ন দৃষ্টিকোণ থেকে জবশেডুলার আপনার পরিষেবা নয়, এটি একটি সিস্টেমের, সম্ভবত এটি সঠিকভাবে সারিটি পরিচালনা করবে এবং গুগল কখনই তার নিজের সন্তানকে সমাপ্ত করবে না :)

স্যামসুং তাদের স্যামসাং অ্যাকসেসরি প্রোটোকল (এসএপি) এ স্টার্টফোরগ্রাউন্ডস সার্ভিস থেকে জবশেডুলার এবং জবস সার্ভিসে স্যুইচ করেছে। এটি স্মার্টওয়াচের মতো ডিভাইসগুলির ফোনের মতো হোস্টের সাথে কথা বলার প্রয়োজন হলে এটি খুব সহায়ক where যেহেতু কাজগুলি শিডিয়ুলার দ্বারা মূল থ্রেডে পোস্ট করা হয়েছে, এটি সম্ভব হয়ে ওঠে। আপনার মনে রাখা উচিত যে চাকরিটি মূল থ্রেডে চলছে এবং সমস্ত ভারী স্টাফ অন্যান্য থ্রেড এবং অ্যাসিঙ্ক কার্যগুলিতে অফলোড করে।

এই পরিষেবাটি আপনার আবেদনের মূল থ্রেডে চলমান হ্যান্ডলারের প্রতিটি আগত কাজ সম্পাদন করে। এর অর্থ হ'ল আপনাকে অবশ্যই নিজের এক্সিকিউশন লজিকটিকে আপনার পছন্দের অন্য থ্রেড / হ্যান্ডলার / অ্যাসিঙ্কটাস্কে অফলোড করতে হবে

জবশেডুলার / জবস সার্ভিসে স্যুইচ করার একমাত্র সমস্যাটি হ'ল আপনাকে পুরানো কোডটি রিফ্যাক্টর করতে হবে এবং এটি মজাদার নয়। আমি স্যামসাংয়ের নতুন এসএপি বাস্তবায়নটি ব্যবহার করতে গত দু'দিন ব্যয় করেছি। আমি আমার ক্র্যাশ প্রতিবেদনগুলি দেখব এবং ক্র্যাশগুলি আবার দেখলে আপনাকে জানাব। তাত্ত্বিকভাবে এটি হওয়া উচিত নয়, তবে সবসময় এমন বিবরণ থাকে যা আমরা সচেতন হতে পারি না।

আপডেট আপডেট প্লে স্টোর দ্বারা আর ক্র্যাশ রিপোর্ট করা হয়নি। এর অর্থ হ'ল জবশেডুলার / জবস সার্ভিস এ জাতীয় সমস্যা নেই এবং এই মডেলটিতে স্যুইচ করা স্টার্টফোরগ্রাউন্ডসোসাইরি সমস্যাটি একবার এবং চিরতরে মুক্তি পাওয়ার জন্য সঠিক পন্থা। আমি আশা করি, গুগল / অ্যান্ড্রয়েড এটি পড়ে এবং শেষ পর্যন্ত প্রত্যেকের জন্য মন্তব্য / পরামর্শ / অফিসিয়াল গাইডেন্স প্রদান করবে।

আপডেট 2

যারা এসএপি ব্যবহার করেন এবং জিজ্ঞাসা করছেন যে কীভাবে এসএপি ভি 2 জবসোসভিয়ার ব্যবহার করে তা নীচে রয়েছে।

আপনার কাস্টম কোডে আপনাকে এসএপি শুরু করতে হবে (এটি কোটলিন):

SAAgentV2.requestAgent(App.app?.applicationContext, 
   MessageJobs::class.java!!.getName(), mAgentCallback)

ভিতরে কী চলছে তা দেখতে এখন আপনাকে স্যামসংয়ের কোডটি ছড়িয়ে দিতে হবে। SAAgentV2- এ অনুরোধএজেন্ট বাস্তবায়ন এবং নিম্নলিখিত লাইনটি একবার দেখুন:

SAAgentV2.d var3 = new SAAgentV2.d(var0, var1, var2);

where d defined as below

private SAAdapter d;

এখনই SAAdapter ক্লাসে যান এবং সার্ভিস সংযোগআরকিস্টেড ফাংশনটি সন্ধান করুন যা নিম্নলিখিত কলটি ব্যবহার করে কোনও কাজের শিডিউল করে:

SAJobService.scheduleSCJob(SAAdapter.this.d, var11, var14, var3, var12); 

এসএজবসওয়ার্স হ'ল অ্যান্ড্রয়েড'ড জব সার্ভিসের একটি বাস্তবায়ন এবং এটিই একটি কাজের সময় নির্ধারণ করে:

private static void a(Context var0, String var1, String var2, long var3, String var5, SAPeerAgent var6) {
    ComponentName var7 = new ComponentName(var0, SAJobService.class);
    Builder var10;
    (var10 = new Builder(a++, var7)).setOverrideDeadline(3000L);
    PersistableBundle var8;
    (var8 = new PersistableBundle()).putString("action", var1);
    var8.putString("agentImplclass", var2);
    var8.putLong("transactionId", var3);
    var8.putString("agentId", var5);
    if (var6 == null) {
        var8.putStringArray("peerAgent", (String[])null);
    } else {
        List var9;
        String[] var11 = new String[(var9 = var6.d()).size()];
        var11 = (String[])var9.toArray(var11);
        var8.putStringArray("peerAgent", var11);
    }

    var10.setExtras(var8);
    ((JobScheduler)var0.getSystemService("jobscheduler")).schedule(var10.build());
}

আপনি দেখতে পাচ্ছেন, এখানে সর্বশেষ লাইনটি এই সিস্টেম পরিষেবাটি পেতে এবং একটি কাজের সময় নির্ধারণের জন্য অ্যান্ড্রয়েড'ড জবশেডুলার ব্যবহার করে।

অনুরোধএজেন্ট কলটিতে আমরা এমজেন্টক্যালব্যাক পাস করেছি, এটি একটি কলব্যাক ফাংশন যা কোনও গুরুত্বপূর্ণ ঘটনা ঘটলে নিয়ন্ত্রণ প্রাপ্ত হবে। কলব্যাকটি আমার অ্যাপে এভাবে সংজ্ঞায়িত করা হয়েছে:

private val mAgentCallback = object : SAAgentV2.RequestAgentCallback {
    override fun onAgentAvailable(agent: SAAgentV2) {
        mMessageService = agent as? MessageJobs
        App.d(Accounts.TAG, "Agent " + agent)
    }

    override fun onError(errorCode: Int, message: String) {
        App.d(Accounts.TAG, "Agent initialization error: $errorCode. ErrorMsg: $message")
    }
}

ম্যাসেজজবস এখানে একটি শ্রেণি যা আমি স্যামসুং স্মার্টওয়াচ থেকে আসা সমস্ত অনুরোধগুলি প্রক্রিয়া করতে প্রয়োগ করেছি। এটি সম্পূর্ণ কোড নয়, কেবল একটি কঙ্কাল:

class MessageJobs (context:Context) : SAAgentV2(SERVICETAG, context, MessageSocket::class.java) {


    public fun release () {

    }


    override fun onServiceConnectionResponse(p0: SAPeerAgent?, p1: SASocket?, p2: Int) {
        super.onServiceConnectionResponse(p0, p1, p2)
        App.d(TAG, "conn resp " + p1?.javaClass?.name + p2)


    }

    override fun onAuthenticationResponse(p0: SAPeerAgent?, p1: SAAuthenticationToken?, p2: Int) {
        super.onAuthenticationResponse(p0, p1, p2)
        App.d(TAG, "Auth " + p1.toString())

    }


    override protected fun onServiceConnectionRequested(agent: SAPeerAgent) {


        }
    }

    override fun onFindPeerAgentsResponse(peerAgents: Array<SAPeerAgent>?, result: Int) {
    }

    override fun onError(peerAgent: SAPeerAgent?, errorMessage: String?, errorCode: Int) {
        super.onError(peerAgent, errorMessage, errorCode)
    }

    override fun onPeerAgentsUpdated(peerAgents: Array<SAPeerAgent>?, result: Int) {

    }

}

যেমন আপনি দেখতে পাচ্ছেন, মেসেজজবসের জন্য মেসেজসকেট ক্লাসেরও প্রয়োজন রয়েছে যে আপনাকে প্রয়োগ করতে হবে এবং এটি আপনার ডিভাইস থেকে আসা সমস্ত বার্তাগুলি প্রক্রিয়া করে।

নীচের লাইন, এটি এত সহজ নয় এবং এর জন্য কিছু অভ্যন্তরীণ এবং কোডিংয়ের জন্য খনন করা দরকার তবে এটি কাজ করে এবং সর্বাগ্রে গুরুত্বপূর্ণ - এটি ক্রাশ হয় না।


ভাল উত্তর কিন্তু একটি বড় সমস্যা আছে, নিচে ওরিও JobIntentServiceহিসাবে তাত্ক্ষণিকভাবে চালানো হয় IntentService, তবে ওরিওর ওপরে কোনও কাজের সময়সূচি JobIntentServiceদেয় , তাই অবিলম্বে শুরু হয় না। আরও তথ্য
23

1
@ কপসঅনআরওড এটি খুব কার্যকর এবং এটি আমার ক্ষেত্রে সঙ্গে সঙ্গেই শুরু হয়ে যায়, যেমনটি আমি লিখেছি, এটি ফোন এবং স্মার্টওয়াচের মধ্যে রিয়েল টাইম ইন্টারঅ্যাকশন জন্য ব্যবহৃত হয়। কোনও উপায় নেই, কোনও ব্যবহারকারী এই দুজনের মধ্যে ডেটা প্রেরণে 15 মিনিট অপেক্ষা করবেন। খুব ভাল কাজ করে এবং কখনও ক্র্যাশ হয় না।
ওলেগ গ্রিব

1
দুর্দান্ত লাগছে, আপনার উত্তরটি বেশ মূল্যবান করে তুলবে যদি আপনি কিছু নমুনা কোড ভাগ করে নিতে পারেন তবে আমি অ্যান্ড্রয়েডে নতুন এবং এটি খুঁজে Job...পেতে সময় লাগে এবং এটির অগ্রিম সংস্করণ AlarmManager
পুলিশসনআরড করুন

2
সম্ভবত আমি যখন সময় অনুমতি দেব: আমি কাস্টম-নির্দিষ্ট কোড থেকে এটিকে
দ্বি

1
@ ব্যাটম্যাচি - জব সার্ভিসটি এসএপি অভ্যন্তরীণভাবে ব্যবহার করে। বিশদের জন্য ওপিতে আপডেট 2 দেখুন।
ওলেগ গ্রাইব

32

আপনি কল করলে Context.startForegroundService(...)এবং তারপরে কল Context.stopService(...)করার আগে কল করলে আপনার অ্যাপ্লিকেশন ক্রাশ হয়ে যাবে Service.startForeground(...)

আমার এখানে ফোরগ্রাউন্ড সার্ভিস এপি 26 এর স্পষ্ট প্রতিবেদন রয়েছে

আমি এটিতে এখানে একটি বাগ খোলা করেছি: গুগল ইস্যু ট্র্যাকার

এটি সম্পর্কে বেশ কয়েকটি বাগ খোলা এবং উইন্ট ফিক্স বন্ধ হয়ে গেছে।

আশা করি স্পষ্ট তিরস্কারের পদক্ষেপগুলি সহ আমার কাটা কাটা হবে।

গুগল দল প্রদত্ত তথ্য

গুগল ইস্যু ট্র্যাকার মন্তব্য 36

এটি কোনও ফ্রেমওয়ার্ক বাগ নয়; এটা ইচ্ছাকৃত। যদি অ্যাপ্লিকেশনটি কোনও পরিষেবা উদাহরণ দিয়ে শুরু করে startForegroundService(), তবে অবশ্যই সেবার সেই দৃষ্টান্তটিকে অগ্রভাগের স্থানে স্থানান্তর করতে হবে এবং বিজ্ঞপ্তিটি প্রদর্শন করতে হবে। যদি পরিষেবা দৃষ্টান্তটির আগে এটি বন্ধ করা startForeground()হয়, তবে সেই প্রতিশ্রুতি অসম্পূর্ণ: এটি অ্যাপটিতে একটি বাগ।

# 31 পুনরায় , এমন একটি পরিষেবা প্রকাশ করা যা অন্য অ্যাপ্লিকেশনগুলি সরাসরি শুরু করতে পারে তা মূলত অসুরক্ষিত। আপনি যে পরিষেবার শুরু সমস্ত ক্রিয়াকলাপটিকে প্রয়োজনীয় হিসাবে বিবেচনা করে কিছুটা প্রশমিত করতে পারেন startForeground(), যদিও আপনার মনের কথাটি সম্ভবত এটি নাও হতে পারে।

গুগল ইস্যু ট্র্যাকার মন্তব্য 56

এখানে বেশ কয়েকটি ভিন্ন পরিস্থিতি রয়েছে যা এখানে একই ফলাফলের দিকে নিয়ে যায়।

প্রত্যক্ষ শব্দার্থক ইস্যু, এটি যে কিছু দিয়ে লাথি মারতে কেবল ত্রুটি startForegroundService()কিন্তু বাস্তবে এর মাধ্যমে অগ্রভাগে স্থানান্তর করতে অবহেলা , ঠিক সেটাই startForeground(): একটি শব্দার্থক বিষয়। এটিকে ইচ্ছাকৃতভাবে অ্যাপ্লিকেশনের বাগ হিসাবে বিবেচনা করা হয়। অগ্রভাগে স্থানান্তরিত করার আগে পরিষেবাটি থামানো একটি অ্যাপ্লিকেশন ত্রুটি। এটাই ছিল ওপি-র কর্কট এবং এ কারণেই এই ইস্যুটিকে "ইচ্ছাকৃতভাবে কাজ করা" হিসাবে চিহ্নিত করা হয়েছে।

যাইহোক, এই সমস্যাটির উদ্দীপনা সনাক্তকরণ সম্পর্কেও প্রশ্ন রয়েছে । যে হয় , একটি জেনুইন সমস্যা হিসেবে চিকিত্সা করা হচ্ছে যদিও এটা হচ্ছে এই বিশেষ বাগ যে ব্যক্তি অনুসরণ করে ইস্যু থেকে আলাদাভাবে ট্র্যাক করা হয়েছে। আমরা অভিযোগের কাছে বধির নই।


2
আমি যে সেরা আপডেটটি দেখেছি তা হ'ল ইস্যুটিয়রেকার.কম । আমি আমার কোডটি কনটেক্সট.বাইন্ডসোভার্স ব্যবহার করতে পুনরায় লিখেছিলাম যা কনটেক্সট.স্টার্টফোরগ্রাউন্ডস সার্ভিসে সমস্যাযুক্ত কলটিকে সম্পূর্ণভাবে এড়িয়ে চলে। আপনি আমার নমুনা কোড দেখতে পারেন github.com/paulpv/ForegroundServiceAPI26/tree/bound/app/src/...
swooby

হ্যাঁ, আমি যেমন লিখেছি, বাঁধাই কাজ করা উচিত, তবে আমি ইতিমধ্যে জবসার্ভেভে স্যুইচ করেছি এবং যদি এটি খুব বেশি না ভেঙে যায় তবে কিছুই পরিবর্তন করতে যাব না ':)
ওলেগ গ্র্যাব

19

আমি এটি নিয়ে কয়েক দিন গবেষণা করেছি এবং সমাধান পেয়েছি। এখন অ্যান্ড্রয়েড ওয়ে আপনি নীচের মত ব্যাকগ্রাউন্ড সীমাবদ্ধতা সেট করতে পারেন

যে পরিষেবাটি একটি পরিষেবা শ্রেণি কল করছে

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
    }
}

3
আপনি কি এমন কোনও অ্যাপ্লিকেশনটিতে চেষ্টা করেছেন যার অন্তত কয়েক হাজার ব্যবহারকারী রয়েছে? আমি চেষ্টা করেছি, কিছু ব্যবহারকারীর এখনও ক্র্যাশ সমস্যা রয়েছে।
অ্যালেক্স

না না আমি সঠিক কোডটি ব্যবহার করছি এবং আমি ক্লায়েন্টদের ক্র্যাশ হতে দেখছি না।
আহমদ আরসলান

আপনার কত ব্যবহারকারী আছে? আমি প্রতিদিন অ্যাপ্লিকেশনে 10k ব্যবহারকারী ছিল এমন daily 10-30 + ক্র্যাশ দেখেছি (ত্রুটি সহ)। অবশ্যই, এটি শুধুমাত্র অ্যান্ড্রয়েড 8.0 এবং অ্যান্ড্রয়েড 8.1 এর ব্যবহারকারীদের ক্ষেত্রেই ঘটে, যদি টার্গেটএসডিকি ভার্সন ২ is হয় তবে সমস্ত সমস্যা 0 ক্র্যাশে অদৃশ্য হয়ে যায় যখন আমি টার্গেট এসডকে সংস্করণটি 25-এ স্থির করেছিলাম।
অ্যালেক্স

কেবল 2200 ব্যবহারকারী: - / তবে কোনও ক্র্যাশ পেলেন না
আহমদ আরসলান

1
@ জিভা, সত্যই নয়। এটিএম, আমি সংকলনএসডিপি ভার্সন ২ target সহ টার্গেটএসডিপি ভার্সন 25 ব্যবহার করি It এটি অনেকগুলি পরীক্ষার পরে সবচেয়ে ভাল উপায় পছন্দ করে বলে মনে করি .... আশা করি তারা আগস্ট 2018 এর আগে ডেভেলপার.অ্যান্ড্রয়েড / টপিক / লাইব্রিজি / আর্কিটেকচার / শেষ করবেন কারণ অ্যান্ড্রয়েড-বিকাশকারীরা ব্লগ .com / 2017/12 /…
অ্যালেক্স

16

আমার একটি উইজেট রয়েছে যা ডিভাইসটি জাগ্রত হওয়ার সময় তুলনামূলকভাবে ঘন ঘন আপডেট করে এবং আমি কয়েক দিনের মধ্যে কয়েক হাজার ক্র্যাশ দেখছিলাম।

ইস্যু ট্রিগার

এমনকি আমি আমার পিক্সেল 3 এক্সএলতেও বিষয়টি লক্ষ্য করেছি যখন আমি ডিভাইসটিকে মোটেই বেশি বোঝা দেবার কথা ভাবতাম না। এবং যে কোনও এবং সমস্ত কোড পাথের সাথে আচ্ছাদিত ছিল startForeground()। তবে আমি বুঝতে পেরেছিলাম যে অনেক ক্ষেত্রে আমার পরিষেবা সত্যিই দ্রুত কাজটি সম্পন্ন করে। আমি বিশ্বাস করি যে আমার অ্যাপ্লিকেশনটির জন্য ট্রিগারটি হ'ল পরিষেবাটি কোনও বিজ্ঞপ্তি দেখানোর আগে প্রায় শেষ হওয়ার আগেই পরিষেবাটি শেষ হয়েছিল।

কাজের সমাধান / সমাধান

আমি সমস্ত ক্রাশ থেকে মুক্তি পেতে সক্ষম হয়েছি। আমি যা করেছি তা হ'ল কলটি সরিয়ে দেওয়া stopSelf()(বিজ্ঞপ্তিটি প্রদর্শিত না হওয়া অবধি আমি স্টপটি বিলম্ব করার বিষয়ে ভাবছিলাম, তবে আমি চাই না যে ব্যবহারকারী প্রয়োজনে নোটিফিকেশনটি দেখেন।) পরিষেবাটি এক মিনিট বা সিস্টেমের জন্য অলস অবস্থায় থাকা অবস্থায় কোনও ব্যতিক্রম ছুঁড়ে না ফেলে এটিকে সাধারণত ধ্বংস করে দেয়।

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

11

আমি এতে অনেক ঘন্টা নষ্ট করার সাথে সাথে কেবল একটি মাথা উপরে। আমি startForeground(..)প্রথম জিনিস হিসাবে কল করার পরেও এই ব্যতিক্রমটি পেয়েছি onCreate(..)। শেষ পর্যন্ত আমি আবিষ্কার করেছিলাম যে সমস্যাটি ব্যবহার করে হয়েছিল NOTIFICATION_ID = 0। অন্য কোনও মান ব্যবহার করে এটি ঠিক করা হয়েছে বলে মনে হচ্ছে।


আমার ক্ষেত্রে আমি আইডি 1 ব্যবহার করছিলাম, ধন্যবাদ, সমস্যাটি সমাধান হয়ে গেল
আমিন পিনজারি

4
আমি 101 আইডি ব্যবহার করছি, এখনও আমি কখনও কখনও কখনও এই ত্রুটিটি পাই receive
কক্সঅনরোড

9

এই সমস্যাটির জন্য আমার প্রায় কাজ আছে। আমি আমার নিজের অ্যাপ্লিকেশন (300K + DAU) এ এই সমস্যাটি যাচাই করেছি, যা কমপক্ষে 95% এই জাতীয় ক্রাশ হ্রাস করতে পারে তবে 100% এই সমস্যাটি এড়াতে পারে না।

গুগল ডকুমেন্টেড হিসাবে পরিষেবা শুরু হওয়ার ঠিক পরে আপনি যখন স্টার্টফোরগ্রাউন্ডে () কল করতে নিশ্চিত হন তখনও এই সমস্যাটি ঘটে happens এটি হতে পারে কারণ পরিষেবা তৈরি এবং প্রারম্ভিককরণের জন্য ইতিমধ্যে অনেক পরিস্থিতিতে অনেক বেশি 5 সেকেন্ডের বেশি ব্যয় হয়, তারপরে আপনি কখন এবং কোথায় স্টার্টফোরগ্রাউন্ড () পদ্ধতি কল করবেন না কেন, এই ক্রাশটি অনিবার্য।

আমার সমাধান হ'ল স্টার্টফোরগ্রাউন্ড সার্ভিস () পদ্ধতির পরে 5 সেকেন্ডের মধ্যেই স্টার্টফোরগ্রাউন্ড () কার্যকর করা হবে তা নিশ্চিত করা, আপনার পরিষেবাটি আর কতক্ষণ তৈরি এবং আরম্ভ করতে হবে তা নির্ধারণ করা নয়। এখানে বিস্তারিত সমাধান দেওয়া হল।

  1. প্রথমে স্টার্টফোরগ্রাউন্ড সার্ভিস ব্যবহার করবেন না, অটো_ক্রিয়েট ফ্ল্যাগ সহ বাইন্ডসেসওয়ার () ব্যবহার করুন। এটি পরিষেবা শুরুর জন্য অপেক্ষা করবে। কোডটি এখানে, আমার নমুনা পরিষেবাটি মিউজিক সার্ভিস:

    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. সর্বাধিক গুরুত্বপূর্ণ অংশ, মিউজিক সার্ভিস বাস্তবায়ন, ফোর্সফোরগ্রাউন্ড () পদ্ধতিটি নিশ্চিত করবে যে স্টার্টফোরগ্রাউন্ড () পদ্ধতিটি স্টার্টফোরগ্রাউন্ড সার্ভিস () এর ঠিক পরে ডাকা হবে:

    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 কোড স্নিপেট চালাতে চান, যেমন আপনি যদি নিজের অ্যাপ্লিকেশনটি না খোলা কোনও উইজেটে (উইজেটের বোতামে ক্লিক করুন) অগ্রভাগ পরিষেবা শুরু করতে চান তবে আপনি কোড স্নিপেট একটি ব্রডকাস্ট রিসিভারে মোড়াতে পারবেন , এবং সার্ভিস কমান্ডের পরিবর্তে একটি সম্প্রচার ইভেন্ট ফায়ার করুন।

এটাই সব। আশা করি এটা সাহায্য করবে. শুভকামনা।


8

এই ত্রুটি যখন Android এর উপর 8+ ঘটে Service.startForeground (int- আইডি, নোটিফিকেশন প্রজ্ঞাপন) যখন বলা হয় আইডি 0 সেট করা হয়।

আইডি ইন্টি: নোটিফিকেশন ম্যানেজ.নোটাইফাই (ইনট, নোটিফিকেশন) অনুসারে এই বিজ্ঞপ্তির জন্য সনাক্তকারী; অবশ্যই 0 হবে না


3
বিজ্ঞপ্তি আইডির জন্য উচ্চতর নম্বর ব্যবহার করবেন না। এক অঙ্কের আইডি ব্যবহার করার চেষ্টা করুন। stackoverflow.com/a/12228555/2527204
মারলন

7

যেহেতু এখানে দেখার জন্য প্রত্যেকে একই সমস্যায় ভুগছেন, তাই আমি আমার সমাধানটি ভাগ করতে চাই যা অন্য কেউ এর আগে চেষ্টা করেনি (যাই হোক এই প্রশ্নে)। আমি আপনাকে আশ্বস্ত করতে পারি যে এটি কাজ করছে, এমনকি বন্ধ হওয়া ব্রেকপয়েন্টেও যা এই পদ্ধতির নিশ্চয়তা দেয়

সমস্যাটি হ'ল Service.startForeground(id, notification)সার্ভিস থেকে নিজেই ডেকে আনা, তাই না? দুর্ভাগ্যক্রমে অ্যান্ড্রয়েড ফ্রেমওয়ার্কটি 5 সেকেন্ডের Service.startForeground(id, notification)মধ্যে কল করার গ্যারান্টি দেয় না তবে Service.onCreate()যাইহোক ব্যতিক্রম ছুঁড়ে দেয়, তাই আমি এইভাবে এগিয়ে এসেছি।

  1. কল করার আগে পরিষেবাটি বাইন্ডারের সাথে পরিষেবাটি একটি প্রসঙ্গে বেঁধে রাখুন Context.startForegroundService()
  2. বাইন্ডটি সফল Context.startForegroundService() হলে পরিষেবা সংযোগ থেকে কল করুন এবং তত্ক্ষণাত পরিষেবা সংযোগের অভ্যন্তরে কল করুন Service.startForeground()
  3. গুরুত্বপূর্ণ দ্রষ্টব্য: চেষ্টাটিকে ধরারContext.bindService() অভ্যন্তরে পদ্ধতিটি কল করুন কারণ কিছু ক্ষেত্রে কলটি একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে, সেক্ষেত্রে আপনাকে Context.startForegroundService()সরাসরি কল করার উপর নির্ভর করতে হবে এবং আশা করি এটি ব্যর্থ হবে না। একটি উদাহরণ একটি সম্প্রচারক গ্রহীতা প্রসঙ্গ হতে পারে, তবে অ্যাপ্লিকেশন প্রসঙ্গে প্রাপ্তি সে ক্ষেত্রে ব্যতিক্রম ঘটায় না, তবে প্রসঙ্গটি সরাসরি ব্যবহার করে।

এমনকি পরিষেবাটি বাঁধাইয়ের পরে এবং "স্টার্টফোরগ্রাউন্ড" কলটি ট্রিগার করার আগে যখন আমি ব্রেকপয়েন্টে অপেক্ষা করি তখন এটি কাজ করে। ২-৩ সেকেন্ডের মধ্যে অপেক্ষা করা ব্যতিক্রমটিকে ট্রিগার করে না যখন 5 সেকেন্ড পরে এটি ব্যতিক্রম ছুঁড়ে দেয়। (যদি ডিভাইসটি 5 সেকেন্ডের মধ্যে দুটি লাইন কোড কার্যকর করতে না পারে, তবে এটি এখন ট্র্যাশে ফেলে দেওয়ার সময় এসেছে))

সুতরাং, একটি পরিষেবা সংযোগ তৈরি করে শুরু করুন।

// Create the service connection.
ServiceConnection connection = new ServiceConnection()
{
    @Override
    public void onServiceConnected(ComponentName name, IBinder service)
    {
        // The binder of the service that returns the instance that is created.
        MyService.LocalBinder binder = (MyService.LocalBinder) service;

        // The getter method to acquire the service.
        MyService myService = binder.getService();

        // getServiceIntent(context) returns the relative service intent 
        context.startForegroundService(getServiceIntent(context));

        // This is the key: Without waiting Android Framework to call this method
        // inside Service.onCreate(), immediately call here to post the notification.
        myService.startForeground(myNotificationId, MyService.getNotification());

        // Release the connection to prevent leaks.
        context.unbindService(this);
    }

    @Override
    public void onBindingDied(ComponentName name)
    {
        Log.w(TAG, "Binding has dead.");
    }

    @Override
    public void onNullBinding(ComponentName name)
    {
        Log.w(TAG, "Bind was null.");
    }

    @Override
    public void onServiceDisconnected(ComponentName name)
    {
        Log.w(TAG, "Service is disconnected..");
    }
};

আপনার পরিষেবার অভ্যন্তরে, এমন একটি বাইন্ডার তৈরি করুন যা আপনার পরিষেবার উদাহরণটি ফিরিয়ে দেয়।

public class MyService extends Service
{
    public class LocalBinder extends Binder
    {
        public MyService getService()
        {
            return MyService.this;
        }
    }

    // Create the instance on the service.
    private final LocalBinder binder = new LocalBinder();

    // Return this instance from onBind method.
    // You may also return new LocalBinder() which is
    // basically the same thing.
    @Nullable
    @Override
    public IBinder onBind(Intent intent)
    {
        return binder;
    }
}

তারপরে, পরিষেবাটিকে সেই প্রসঙ্গ থেকে বাঁধতে চেষ্টা করুন । যদি এটি সফল হয়, ServiceConnection.onServiceConnected()আপনি যে পরিষেবা সংযোগটি ব্যবহার করছেন তা থেকে এটি কল করবে । তারপরে, উপরে প্রদর্শিত কোডটিতে লজিকটি পরিচালনা করুন। একটি উদাহরণ কোড এর মত দেখতে হবে:

// Try to bind the service
try
{
     context.bindService(getServiceIntent(context), connection,
                    Context.BIND_AUTO_CREATE);
}
catch (RuntimeException ignored)
{
     // This is probably a broadcast receiver context even though we are calling getApplicationContext().
     // Just call startForegroundService instead since we cannot bind a service to a
     // broadcast receiver context. The service also have to call startForeground in
     // this case.
     context.startForegroundService(getServiceIntent(context));
}

আমার বিকাশকৃত অ্যাপ্লিকেশনগুলিতে এটি কাজ করছে বলে মনে হচ্ছে, তাই আপনার চেষ্টা করার পরেও এটি কাজ করা উচিত।


5

অ্যান্ড্রয়েড ও এপিআই 26 এর সাথে সমস্যা

আপনি যদি এখনই পরিষেবাটি বন্ধ করে দেন (সুতরাং আপনার পরিষেবাটি প্রকৃতপক্ষে চলবে না (শব্দবন্ধ / বোঝা) এবং আপনি এএনআর ব্যবধানের আওতায় চলেছেন, স্টপসেলফের আগে আপনাকে এখনও স্টার্টফোরগ্রাউন্ডে কল করতে হবে

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

এই পদ্ধতির চেষ্টা করে তবে এটি ত্রুটি তৈরি করে:

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

ত্রুটিটি সমাধান না হওয়া পর্যন্ত আমি এটি ব্যবহার করছি

mContext.startService(playIntent);

3
Util.SDK_INT> = 26 হওয়া উচিত, কেবল বড় নয়
অ্যান্ডিস

4

আমি একই সমস্যার মুখোমুখি এবং সময় ব্যয় করার পরে একটি দ্রাবক খুঁজে পেয়েছি আপনি কোডের নীচে চেষ্টা করতে পারেন। আপনি যদি ব্যবহার করেন Serviceতবে এই কোডটি অনক্রিট করুন অন্যথায় আপনার ব্যবহারের Intent Serviceপরে এই কোডটি হ্যান্ডলআইন্টেন্টে রাখুন।

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);
    }

4

আমি এই সমস্যাটি নিয়ে গবেষণা করে চলেছি এবং এটি আমি এ পর্যন্ত আবিষ্কার করেছি। আমাদের যদি এর মতো কোড থাকে তবে এই ক্রাশটি ঘটতে পারে:

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);
         }
    }
    ...
}

এই পদ্ধতি আগে মৃত্যুদন্ড কার্যকর করা হয় onCreate()এর MyForegroundServiceকারণ অ্যানড্রইড সময়সূচী মূল থ্রেড হ্যান্ডলার পরিষেবা সৃষ্টির কিন্তু bringDownServiceLockedএকটি উপর বলা হয় BinderThread, কোনটা একটি জাতি অবস্থা। এর অর্থ হল যে MyForegroundServiceকল করার কোনও সুযোগ নেই startForegroundযা ক্রাশের কারণ হবে।

এই আমরা নিশ্চিত যে করতে হবে ঠিক করতে bringDownServiceLockedসামনে বলা হয় না onCreate()এর MyForegroundService

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যত তাড়াতাড়ি এটা নিবন্ধিত হয়েছে স্টপ অভিপ্রায় পায় onCreate()এর MyForegroundService। এই সময়ের মধ্যে আমরা ইতিমধ্যে ফোন করেছি startForeground(...)। পরের বার স্টপ রিসিভারকে অবহিত করা রোধ করতে আমাদের সেই স্টিকি সম্প্রচারটিও সরিয়ে ফেলতে হবে।

দয়া করে নোট করুন যে পদ্ধতিটি sendStickyBroadcastহ্রাস পেয়েছে এবং আমি এই সমস্যাটি সমাধান করার জন্য এটি কেবল অস্থায়ী কর্মক্ষেত্র হিসাবে ব্যবহার করি।


আপনি পরিষেবাটি বন্ধ করতে চাইলে আপনার প্রাসঙ্গিক স্টপ সার্ভিস (সার্ভিস ইন্টেন্ট) এর পরিবর্তে এটি কল করা উচিত।
makovkastar

4

অনেক উত্তর কিন্তু আমার ক্ষেত্রে কেউ কাজ করেনি।

আমি এইভাবে পরিষেবা শুরু করেছি।

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

এবং অন স্টার্টকমন্ডে আমার পরিষেবাতে

    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);
    }

এবং NOTIFICATION_ID শূন্য নয় সেট করতে ভুলবেন না

private static final String ANDROID_CHANNEL_ID = "com.xxxx.Location.Channel";
private static final int NOTIFICATION_ID = 555;

সুতরাং সবকিছু নিখুঁত ছিল তবে 8.1 এ এখনও ক্র্যাশ হচ্ছে তাই কারণ নীচের মতো ছিল।

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

আমি মুছে ফেলা নোটিফিক্যাটনের সাথে স্টোর ফোরগ্রাউন্ড বলেছি কিন্তু নোটিফিকেশন সরানো পরিষেবাটি ব্যাকগ্রাউন্ডে পরিণত হয় এবং পটভূমি পরিষেবা ব্যাকগ্রাউন্ড থেকে অ্যান্ড্রয়েড ও তে চালানো যায় না। ধাক্কা পাওয়ার পরে শুরু।

তাই যাদু শব্দ

   stopSelf();

এখনও অবধি কোনও কারণে আপনার পরিষেবা ক্র্যাশ করছে এবং উপরের সমস্ত পদক্ষেপগুলি অনুসরণ করুন এবং উপভোগ করুন।


যদি (বিল্ড.ভি.এস.আর.এস.ডি.এন.পি.টি. = = বিল্ড.VERSION_CODES.O) {স্টপফোরগ্রাউন্ড (সত্য); } অন্য {স্টপফোরগ্রাউন্ড (সত্য); else এটা আর কি যদি হয়? উভয় ক্ষেত্রেই আপনি একই কাজ করছিলেন, স্টপফোরগ্রাউন্ড (সত্য);
ব্যবহারকারী 3135923

আমি বিশ্বাস করি আপনি স্টপসেল্ফ () লাগিয়েছিলেন; স্টপফোরগ্রাউন্ডের পরিবর্তে অন্য ব্লকের ভিতরে (সত্য);
জাস্টিন স্ট্যানলি

1
হ্যাঁ, @ জাস্টিনস্ট্যানলি স্টপসেলফ ব্যবহার করুন ();
বেলে

startForegroundভিতরে ডাকা উচিত নয় onCreate?
আবা

আমি নোটিফিকেশন ম্যানেজার এবং নোটিফিকেশন ক্লাস ব্যবহার করছি। আমি কীভাবে এটি বাস্তবায়ন করতে পারি?
প্রজওয়াল ডাব্লু

3

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

স্টার্ট সার্ভিস (ইনটেন্ট) এর অনুরূপ, তবে একটি অন্তর্নিহিত প্রতিশ্রুতি দিয়ে যে পরিষেবাটি চলমান শুরু হওয়ার সাথে সাথে স্টার্টফোরগ্রাউন্ড (ইনট্রয়েড.অ্যাপ.নোটিকেশন) কল করবে। এটি করার জন্য এএনআর ব্যবধানের সাথে পরিষেবাটিকে তুলনামূলক পরিমাণ সময় দেওয়া হয়, অন্যথায় সিস্টেমটি স্বয়ংক্রিয়ভাবে পরিষেবাটি বন্ধ করে দেবে এবং অ্যাপটি এএনআর ঘোষণা করবে।

সাধারণ স্টার্ট সার্ভিস (ইন্টেন্ট) এর বিপরীতে, এই পরিষেবাটি যে কোনও সময় ব্যবহার করা যেতে পারে, পরিষেবা হোস্টিং অ্যাপটি পূর্বের অবস্থায় রয়েছে কিনা তা বিবেচনা না করেই।

আপনি Service.startForeground(int, android.app.Notification)অনক্রিট () এ কল করেছেন তা নিশ্চিত করুন যাতে এটি কল করা হবে আপনি নিশ্চিত হন..আপনার যদি এমন কোনও অবস্থা থেকে থাকে যা আপনাকে এটি করতে বাধা দিতে পারে তবে আপনি স্বাভাবিকটি ব্যবহার না Context.startService(Intent)করেই Service.startForeground(int, android.app.Notification)নিজেকে কল করতে পারেন ।

দেখে মনে হচ্ছে যে এটি ধ্বংস হওয়ার আগে আপনি এটি Context.startForegroundService()ডাকলেন তা নিশ্চিত করার জন্য একটি নজরদারি যুক্ত করেছে Service.startForeground(int, android.app.Notification)...


3

দয়া করে ভিতরে কোনও স্টার্টফ্রাউন্ড সার্ভিসেস কল করবেন না onCreate () পদ্ধতি, আপনি 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);

    }
}

সম্পাদনা: সাবধান! স্টার্টফোরগ্রাউন্ড ফাংশন 0 প্রথম যুক্তি হিসাবে নিতে পারে না, এটি একটি ব্যতিক্রম বাড়াবে! এই উদাহরণটিতে ভুল ফাংশন কল রয়েছে, 0 আপনার নিজস্ব কনস্টে পরিবর্তন করুন যা 0 হতে পারে না বা সর্বোচ্চ (অন্তর্ 32) এর চেয়ে বড় হতে পারে


2

এমনকি কলিং পর startForegroundService, এটি কিছু ডিভাইসে ক্র্যাশ যদি আমরা কল stopServiceঠিক আগে onCreateবলা হয়। সুতরাং, আমি অতিরিক্ত পতাকা দিয়ে পরিষেবা শুরু করে এই সমস্যাটি সমাধান করেছি:

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

এবং স্টার্টকমন্ডে একটি চেক যুক্ত করেছে এটি বন্ধ করা শুরু হয়েছে কিনা তা দেখার জন্য:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //call startForeground first
    if (intent != null) {
        boolean stopService = intent.getBooleanExtra("request_stop", false);
        if (stopService) {
            stopSelf();
        }
    }

    //Continue with the background task
    return START_STICKY;
}

PS যদি পরিষেবাটি চালু না থাকে তবে এটি পরিষেবাটি প্রথমে শুরু করবে যা একটি ওভারহেড।


2

টার্গেট এসডিকে ২৮ বা তার বেশি ব্যবহার করার সময় অ্যান্ড্রয়েড 9 ডিভাইসের জন্য আপনাকে বেলো হিসাবে অনুমতি যোগ করতে হবে বা ব্যতিক্রম সর্বদা ঘটবে:

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

1

আমি কেবল PendingIntentনালটি পরীক্ষা করি বা না ডাকার আগে না not context.startForegroundService(service_intent) ফাংশনটি ।

এটা আমার জন্য কাজ করে

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);
        }
}

এটি আসলে শূন্যপদে সার্ভিসটিকে লাঞ্ছিত করে স্টার্টফোরগ্রাউন্ড সার্ভিসের পরিবর্তে স্টার্ট সার্ভিসে। যদি বিবৃতিটি নেস্ট করাতে হয় তবে অন্যথায় অ্যাপটি কোনও সময়ে পরবর্তী সংস্করণে পরিষেবাগুলি ব্যবহার করার চেষ্টা করে ক্রাশ হয়ে যাবে।
a54 স্টুডিও

1

সার্ভিস বা ইনটেন্ট সার্ভিস তৈরি হওয়ার সাথে সাথে কেবল স্টার্টফোরগ্রাউন্ড পদ্ধতিতে কল করুন। এটার মত:

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

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

চূড়ান্ত উত্সাহ: মূল অ্যান্ড্রয়েড.অ্যাপ.রেমসোসেস্প এক্সসেপশন: স্টার্টফোরগ্রাউন্ডের জন্য খারাপ বিজ্ঞপ্তি: java.lang.RuntimeException: পরিষেবা বিজ্ঞপ্তির জন্য অবৈধ চ্যানেল: বিজ্ঞপ্তি (চ্যানেল = নাল প্রাই = 0 সামগ্রীভিউ = নাল ভাইব্রেট = নাল সাউন্ড = নাল ডিফল্ট = 0x0 ফ্ল্যাগ = 0x40 রঙ = 0x00000000 ভিজি = প্রাইভেট) এ android.app.ActivityThread $ H.handleMessage (ActivityThread.java:1821) এ android.os.Handler.dispatchMessage (Handler.java:106) এ android.os.Looper.loop (লুপার) এ। java: 164) at android.app.ActivityThread.main (ActivityThread.java:6626)
গেরি

1

ঠিক আছে, আমি এটিতে লক্ষ্য করেছি এমন একটি কিছু যা অন্য কয়েকজনকেও সহায়তা করতে পারে। আমি যে ঘটনাগুলি দেখছি সেগুলি কীভাবে ঠিক করতে হবে তা আমি নির্ধারণ করতে পারছি কিনা তা পরীক্ষা থেকে কঠোর strictly সরলতার জন্য, ধরা যাক আমার কাছে এমন একটি পদ্ধতি আছে যা উপস্থাপকের কাছ থেকে এটি কল করে।

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

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

এটি একই ত্রুটির সাথে ক্রাশ হবে। পদ্ধতিটি শেষ না হওয়া অবধি পরিষেবা শুরু হবে না, তাই onCreate()পরিষেবাতে নেই।

সুতরাং আপনি যদি ইউআইটি মূল থ্রেডটি আপডেট করে থাকেন তবে যদি আপনার কাছে সেই পদ্ধতিটি ধরে রাখার মতো কিছু থাকে তবে তা সময়মতো শুরু হবে না এবং আপনাকে ভয়ঙ্কর অগ্রভূমি ত্রুটি দেয়। আমার ক্ষেত্রে আমরা কিছু জিনিস একটি কাতারে লোড করছিলাম এবং প্রত্যেককে ডাকা হয়েছিল startForegroundService, তবে পটভূমির প্রতিটিটির সাথে কিছু যুক্তি জড়িত ছিল। সুতরাং যদি যুক্তিটি সেই পদ্ধতিটি শেষ করতে খুব বেশি সময় নেয় যেহেতু তাদেরকে পিছনে পিছনে ডেকে আনা হয়, ক্রাশের সময়। পুরাতনstartService কেবল এটিকে অগ্রাহ্য করেছে এবং সে পথে চলেছে এবং যেহেতু আমরা প্রত্যেকবার এটি বলেছি, পরবর্তী রাউন্ডটি শেষ হবে।

এটি আমার অবাক করে দিয়েছিল, আমি যদি পটভূমির কোনও থ্রেড থেকে পরিষেবাটি কল করি তবে এটি কি পুরোপুরি শুরুর উপর আবদ্ধ না হয়ে অবিলম্বে চলতে পারে, তাই আমি পরীক্ষা-নিরীক্ষা শুরু করি। যদিও এটি অবিলম্বে এটি শুরু না করে, এটি ক্রাশ হয় না।

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();
              }       
        }
});

কেন এটি ক্রাশ হয় না তা জানার ভান করব না যদিও আমি সন্দেহ করি যে এটি মূল থ্রেড সময় মতোভাবে পরিচালনা করতে না পারা পর্যন্ত এটি অপেক্ষা করতে বাধ্য করে। আমি জানি যে এটি মূল থ্রেডে বেঁধে রাখা আদর্শ নয়, তবে যেহেতু আমার ব্যবহার এটিকে পটভূমিতে কল করে তাই ক্র্যাশ হওয়ার পরিবর্তে এটি সম্পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করা হয় কিনা তা নিয়ে আমি সত্যিই উদ্বিগ্ন নই।


আপনি ব্যাকগ্রাউন্ড থেকে আপনার পরিষেবা শুরু করছেন বা ক্রিয়াকলাপে?
মতিন চৌধুরী চৌধুরী

পটভূমি। সমস্যাটি হ'ল অ্যান্ড্রয়েড গ্যারান্টি দিতে পারে না যে নির্ধারিত সময়ে পরিষেবাটি শুরু হবে। কেউ ভাবেন যে তারা চাইলে এটিকে অগ্রাহ্য করার জন্য কেবল একটি ত্রুটি ফেলবে তবে হায়, অ্যান্ড্রয়েড নয়। এটি মারাত্মক হতে হবে। এটি আমাদের অ্যাপ্লিকেশনটিতে সহায়তা করেছে তবে এটি পুরোপুরি ঠিক করে নি।
a54 স্টুডিও

1

আমি @ হামাজেদ উত্তরে কিছু কোড যুক্ত করছি। সুতরাং কোনও প্রাথমিক বিজ্ঞপ্তি নেই। এটি একটি কার্যকরী হতে পারে তবে এটি আমার পক্ষে কার্যকর।

@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("")
                    .setColor(ContextCompat.getColor(this, R.color.transparentColor))
                    .setSmallIcon(ContextCompat.getColor(this, R.color.transparentColor)).build();

            startForeground(1, notification);
        }
}

আমি বিজ্ঞপ্তিতে ছোট আইকন এবং রঙে স্বচ্ছ রঙ যুক্ত করছি। এটা কাজ করবে।


0

startService(intent)পরিবর্তে পরিষেবাটি চালু করার সাথে সাথে সাথে সাথে Context.startForeground()কল startForegound()করার ক্ষেত্রে আমি সমস্যার সমাধান করেছি super.OnCreate()। অতিরিক্তভাবে, আপনি বুটে পরিষেবা শুরু করলে আপনি ক্রিয়াকলাপ শুরু করতে পারেন যা বুট সম্প্রচারে পরিষেবা শুরু করে। যদিও এটি কোনও স্থায়ী সমাধান নয়, এটি কাজ করে।


কিছু কিছু শাওমি ডিভাইসে ব্যাকগ্রাউন্ড থেকে ক্রিয়াকলাপ শুরু করা যায় না
মতিন চৌধুরী চৌধুরী

0

তথ্য আপডেট করা হচ্ছে onStartCommand(...)

onBind (...)

onBind(...)startForegroundবনাম শুরু করার জন্য একটি আরও ভাল জীবনচক্রীয় ঘটনা, onCreate(...)কারণ onBind(...)এটিতে পাস করার ফলে প্রারম্ভিক করার Intentজন্য Bundleপ্রয়োজনীয় ডেটা থাকতে পারে Service। যাইহোক, এটা প্রয়োজনীয় নয় onStartCommand(...)যখন বলা হয় Serviceবা পরবর্তী বার পরে প্রথমবারের মত তৈরি করা হয় বলা হয়।

onStartCommand (...)

startForegroundমধ্যে onStartCommand(...)আপডেট করতে অনুক্রমে গুরুত্বপূর্ণ Serviceএকবার এটি ইতিমধ্যে তৈরি করা হয়েছে।

যখন ContextCompat.startForegroundService(...)পরে একটি বলা হয় Serviceতৈরি করা হয়েছে onBind(...)এবং onCreate(...)বলা নেই। অতএব, আপডেট ডাটা প্রেরণ করা সম্ভব onStartCommand(...)মাধ্যমে Intent Bundleডাটা আপডেট করার জন্য Service

নমুনা

আমি এই প্যাটার্ন ব্যবহার করছি বাস্তবায়ন PlayerNotificationManagerমধ্যে Coinverse cryptocurrency খবর অ্যাপ্লিকেশন।

ক্রিয়াকলাপ / ফ্রেগমেন্ট.কেটি

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()
            })
        })

AudioService.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)
}

-1

সেবা

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)
        }

    }

}

পরীক্ষক

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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.