Android में शेड्यूलिंग आवर्ती कार्य


122

मैं एक ऐसा ऐप डिजाइन कर रहा हूं जिसमें एक समर्पित सर्वर को उपस्थिति भेजने का एक आवर्ती कार्य है जब तक कि ऐप अग्रभूमि में है।

वेब भर में अपनी खोजों में मैंने कुछ अलग तरीके देखे और जानना चाहा कि ऐसा करने का सबसे अच्छा तरीका क्या है।

सर्वर कॉल शेड्यूल करने का सबसे अच्छा तरीका क्या है?

मैंने जो विकल्प देखे वे थे:

  1. टाइमर

  2. शेड्यूल्डड्रेडपूल एक्सिक्यूटर

  3. सेवा

  4. प्रसारण प्रबंधक के साथ AlarmManager

आपकी क्या राय है?

संपादित करें:
मुझे इसकी आवश्यकता एक चैट आधारित ऐप के लिए है जो सभी उपयोगकर्ता कार्यों को दूरस्थ सर्वर पर भेजता है।
यानी उपयोगकर्ता एक संदेश लिख रहा है, उपयोगकर्ता एक संदेश पढ़ रहा है, उपयोगकर्ता ऑनलाइन है, उपयोगकर्ता ऑफ़लाइन है आदि।

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

व्हाट्सएप संदेश प्रतिक्रिया तंत्र के समान: संदेश वितरित दिखता है

EDIT # 2:
आवर्ती कार्यों को अब लगभग हमेशा JobSchedulerएपीआई (या FirebaseJobDispatcherलोअर एपीआई के लिए) के माध्यम से निर्धारित किया जाना चाहिए ताकि बैटरी ड्रेनिंग के मुद्दों को रोका जा सके जैसा कि एंड्रॉइड ट्रेनिंग के इन विटल्स सेक्शन में पढ़ा जा सकता है।

EDIT # 3:
FirebaseJobDispatcher को पदावनत कर दिया गया और उसकी जगह Workmanager ने ले ली , जिसमें JobScheduler की विशेषताएं भी शामिल हैं।


2
AlarmManager के साथ BroaccastReceiver उपयोग करने के लिए बहुत सीधा है। यह उपरोक्त वैकल्पिक विकल्पों में से एक है जिसे मैंने कोशिश की है।

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

कम चलने वाले जीवनचक्र के लिए, अर्थात वर्तमान में अग्रभूमि में प्रत्येक गतिविधि में हर 30 सेकंड में कुछ कार्य करें, शेड्यूल्डड्रेडपूल एक्ज़ीक्यूटर (या टाइमर) का उपयोग अधिक कुशल है। लंबे समय तक चलने वाले जीवनचक्र के लिए, अर्थात पृष्ठभूमि सेवा में हर 1 घंटे में कुछ कार्य करें, अलार्म मैनजर का उपयोग अधिक विश्वसनीयता देता है।
yorkw

आपको भेजने की समय-सारणी की आवश्यकता क्यों है? अपने एप्लिकेशन विवरण से आप इसे वास्तविक समय में क्यों नहीं भेजते?
iTech

क्योंकि उपयोगकर्ता मानता है कि आप ऑनलाइन हैं, टाइमआउट का उपयोग कर रहे हैं। मतलब, अगर मुझे पिछले X राशि में "उपस्थिति" या "टाइपिंग" संदेश नहीं मिला है, तो मुझे लगता है कि आप ऐसा नहीं कर रहे हैं
thepoosh

जवाबों:


164

मुझे यकीन नहीं है लेकिन मेरे ज्ञान के अनुसार मैं अपने विचार साझा करता हूं। मैं हमेशा सबसे अच्छा जवाब स्वीकार करता हूं अगर मैं गलत हूं।

अलार्म मैनेजर

अलार्म मैनेजर एक सीपीयू वेक लॉक रखता है जब तक अलार्म रिसीवर की onReceive()विधि निष्पादित होती है। यह गारंटी देता है कि फोन तब तक नहीं सोएगा जब तक आपने प्रसारण को संभालना समाप्त नहीं कर दिया। एक बार onReceive()वापस आने पर, अलार्म मैनेजर इस वेक लॉक को जारी करता है। इसका मतलब है कि आपका केस onReceive()पूरा होते ही फोन कुछ मामलों में सो जाएगा । यदि आपके अलार्म रिसीवर ने कॉल किया है Context.startService(), तो संभव है कि अनुरोधित सेवा लॉन्च होने से पहले फोन सो जाएगा। इसे रोकने के लिए, आपकी BroadcastReceiverऔर Serviceको यह सुनिश्चित करने के लिए एक अलग वेक लॉक नीति को लागू करने की आवश्यकता होगी कि सेवा उपलब्ध होने तक फोन चालू रहे।

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

घड़ी

timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {

        synchronized public void run() {

            \\ here your todo;
            }

        }}, TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(1));

Timerकुछ कमियां हैं जिनके द्वारा हल किया जाता है ScheduledThreadPoolExecutor। तो यह सबसे अच्छा विकल्प नहीं है

शेड्यूल्डड्रेडपूल एक्सिक्यूटर

आप पृष्ठभूमि थ्रेड पर नियमित अंतराल पर होने वाली क्रिया को शेड्यूल करने के लिए ( java.util.Timerया ScheduledThreadPoolExecutorपसंदीदा) का उपयोग कर सकते हैं ।

यहाँ बाद का उपयोग करके एक नमूना दिया गया है:

ScheduledExecutorService scheduler =
    Executors.newSingleThreadScheduledExecutor();

scheduler.scheduleAtFixedRate
      (new Runnable() {
         public void run() {
            // call service
         }
      }, 0, 10, TimeUnit.MINUTES);

इसलिए मैंने प्राथमिकता दी ScheduledExecutorService

लेकिन इसके अलावा इस बारे में सोचें कि यदि आपके आवेदन के चलने के दौरान अपडेट होगा, तो आप Timerअन्य उत्तर या नए में सुझाए अनुसार उपयोग कर सकते हैं ScheduledThreadPoolExecutor। यदि आपका एप्लिकेशन तब भी अपडेट होगा, जब वह नहीं चल रहा हो, तो आपको उसके साथ जाना चाहिए AlarmManager

अलार्म प्रबंधक उन मामलों के लिए अभिप्रेत है, जहां आप अपना एप्लिकेशन कोड एक विशिष्ट समय पर चलाना चाहते हैं, भले ही आपका एप्लिकेशन वर्तमान में नहीं चल रहा हो।

ध्यान दें कि यदि आप अपना आवेदन बंद होने पर अद्यतन करने की योजना बनाते हैं, तो हर दस मिनट में एक बार काफी बार-बार आते हैं, और इस तरह संभवतः थोड़ा बहुत बिजली की खपत होती है।


मैं एक आवधिक कार्य के लिए इस विधि की कोशिश कर रहा हूँ, लेकिन यह stackoverflow.com/questions/27872016/…
dowjones123

साधारण चीज़ों के लिए - जैसे कि राज्य की जाँच हर n-seconds -Timer करेगा।
इगोरगानापल्स्की

1
@ Maid786 एक सप्ताह या अवधि के दिनों में कुछ कार्य (जैसे सूचनाएं भेजना) करना चाहते हैं तो हमें क्या उपयोग करना चाहिए? क्या अलार्म मैनेजर उसके लिए बहुत अधिक पृष्ठभूमि गणना या प्रसंस्करण करेगा?
चिंतन शाह

30

घड़ी

जैसा कि javadocs पर बताया गया है कि आप शेड्यूल्डड्रेडपूलएक्सक्यूटोर का उपयोग करके बेहतर हैं।

ScheduledThreadPoolExecutor

इस वर्ग का उपयोग तब करें जब आपके उपयोग के मामले में कई कार्यकर्ता थ्रेड्स की आवश्यकता हो और नींद का अंतराल छोटा हो। कितना छोटा ? खैर, मैं 15 मिनट के बारे में कहूंगा। AlarmManagerशुरू होता है इस समय अंतराल अनुसूची और यह पता चलता है कि छोटे नींद अंतराल के लिए इस वर्ग के लिए किया जा सकता है। मेरे पास अंतिम विवरण वापस करने के लिए डेटा नहीं है। यह एक कूबड़ है।

सर्विस

VM द्वारा आपकी सेवा किसी भी समय बंद की जा सकती है। आवर्ती कार्यों के लिए सेवाओं का उपयोग न करें। आवर्ती कार्य एक सेवा शुरू कर सकता है, जो पूरी तरह से एक और मामला है।

प्रसारण प्रबंधक के साथ AlarmManager

लंबे समय तक नींद के अंतराल (> 15 मिनट) के लिए, यह जाने का रास्ता है। AlarmManagerपहले से ही स्थिरांक हैं ( AlarmManager.INTERVAL_DAY) यह सुझाव देता है कि यह शुरू होने के कई दिनों बाद कार्यों को ट्रिगर कर सकता है। यह आपके कोड को चलाने के लिए सीपीयू को भी जगा सकता है।

आपको अपने समय और कार्यकर्ता धागे की जरूरतों के आधार पर उन समाधानों में से एक का उपयोग करना चाहिए।


1
तो क्या होगा अगर मैं ऐप का उपयोग करना चाहता हूं, और हर आधे घंटे में मैं बैक-अप बनाना चाहता हूं। लेकिन मैं एप का इस्तेमाल नहीं करना चाहता, जबकि ऐप इस्तेमाल में नहीं है (जो कुल बेकार होगा)। अलार्ममैन लगातार रिबूट तक कार्रवाई दोहराएगा (यह कम से कम मैंने क्या सुना है)। आप क्या सुझाव देंगे? शेड्यूल्डड्रेडपूल एक्सिक्यूटर या अलार्ममैनगर?
हैड्रबल

13

मुझे लगता है कि यह एक पुराना सवाल है और इसका उत्तर दिया जा चुका है लेकिन इससे किसी की मदद हो सकती है। अपने मेंactivity

private ScheduledExecutorService scheduleTaskExecutor;

में onCreate

  scheduleTaskExecutor = Executors.newScheduledThreadPool(5);

    //Schedule a task to run every 5 seconds (or however long you want)
    scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            // Do stuff here!

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    // Do stuff to update UI here!
                    Toast.makeText(MainActivity.this, "Its been 5 seconds", Toast.LENGTH_SHORT).show();
                }
            });

        }
    }, 0, 5, TimeUnit.SECONDS); // or .MINUTES, .HOURS etc.

2

शेड्यूलिंग रिपीटिंग अलार्म को उद्धृत करना - ट्रेड-ऑफ्स डॉक्स को समझें :

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

इसलिए, इसके आधार पर, सर्वर कॉल को शेड्यूल करने का सबसे अच्छा तरीका सिंक एडाप्टर के साथ संयोजन में Google क्लाउड मैसेजिंग (GCM) का उपयोग करना है ।


1

मैंने समय कार्य पर बनाया है जिसमें वह कार्य जिसे उपयोगकर्ता दोहराना चाहता है, कस्टम टाइमकट रन () विधि में जोड़ें। यह सफलतापूर्वक reoccurring है।

 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Timer;
 import java.util.TimerTask;

 import android.os.Bundle;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.TextView;
 import android.app.Activity;
 import android.content.Intent;

 public class MainActivity extends Activity {

     CheckBox optSingleShot;
     Button btnStart, btnCancel;
     TextView textCounter;

     Timer timer;
     MyTimerTask myTimerTask;

     int tobeShown = 0  ;

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

    optSingleShot = (CheckBox)findViewById(R.id.singleshot);
    btnStart = (Button)findViewById(R.id.start);
    btnCancel = (Button)findViewById(R.id.cancel);
    textCounter = (TextView)findViewById(R.id.counter);
    tobeShown = 1;

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }

    btnStart.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View arg0) {


            Intent i = new Intent(MainActivity.this, ActivityB.class);
            startActivity(i);

            /*if(timer != null){
                timer.cancel();
            }

            //re-schedule timer here
            //otherwise, IllegalStateException of
            //"TimerTask is scheduled already" 
            //will be thrown
            timer = new Timer();
            myTimerTask = new MyTimerTask();

            if(optSingleShot.isChecked()){
                //singleshot delay 1000 ms
                timer.schedule(myTimerTask, 1000);
            }else{
                //delay 1000ms, repeat in 5000ms
                timer.schedule(myTimerTask, 1000, 1000);
            }*/
        }});

    btnCancel.setOnClickListener(new OnClickListener(){

        @Override
        public void onClick(View v) {
            if (timer!=null){
                timer.cancel();
                timer = null;
            }
        }
    });

}

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

    if(timer != null){
        timer.cancel();
    }

    //re-schedule timer here
    //otherwise, IllegalStateException of
    //"TimerTask is scheduled already" 
    //will be thrown
    timer = new Timer();
    myTimerTask = new MyTimerTask();

    if(optSingleShot.isChecked()){
        //singleshot delay 1000 ms
        timer.schedule(myTimerTask, 1000);
    }else{
        //delay 1000ms, repeat in 5000ms
        timer.schedule(myTimerTask, 1000, 1000);
    }
}


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

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

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

    if (timer!=null){
        timer.cancel();
        timer = null;
    }

}

class MyTimerTask extends TimerTask {

    @Override
    public void run() {

        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat simpleDateFormat = 
                new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss a");
        final String strDate = simpleDateFormat.format(calendar.getTime());

        runOnUiThread(new Runnable(){

            @Override
            public void run() {
                textCounter.setText(strDate);
            }});
    }
}

}

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