लूपर का उद्देश्य क्या है और इसका उपयोग कैसे करें?


454

मैं Android के लिए नया हूँ। मैं जानना चाहता हूं कि Looperवर्ग क्या करता है और इसका उपयोग कैसे करना है। मैंने एंड्रॉइड लूपर क्लास प्रलेखन पढ़ा है, लेकिन मैं इसे पूरी तरह से समझने में असमर्थ हूं। मैंने इसे बहुत जगह देखा है लेकिन इसके उद्देश्य को समझने में असमर्थ हूं। Looperयदि संभव हो तो एक सरल उदाहरण देकर और किसी के उद्देश्य को परिभाषित करके कोई मेरी मदद कर सकता है?


7
मुझे बस लूपर का असाधारण रूप से गहन और स्पष्ट विवरण मिला और सफारी बुक्स ऑनलाइन पर इसका उपयोग। दुर्भाग्य से, मुझे संदेह है कि यदि केवल एक सीमित समय के लिए नि: शुल्क पहुंच है। safaribooksonline.com/library/view/efficient-android-threading/…
जो लैप

1
एंड्रॉइड लेख और संदर्भ पृष्ठों के लिए आपको पिछले लेख की समझ और जानकारी की आवश्यकता होती है, इससे पहले कि आप वर्तमान को समझ सकें। मेरा सुझाव है कि आप Api गाइड में गतिविधि और सेवा लेख पढ़ें, और फिर हैंडलर और लूपर पढ़ें। यह भी मदद करता है अगर आपको समझ है कि एक धागा क्या है (एंड्रॉइड थ्रेड नहीं है, लेकिन सामान्य रूप से एक धागा है ... उदाहरण के लिए POSIX)।
FutureSci

1
मुझे यह लेख उपयोगी लगा: codetheory.in/…
Herman

जवाबों:


396

लूपर क्या है?

लूपर एक वर्ग है जिसका उपयोग संदेशों (Runnables) को एक कतार में निष्पादित करने के लिए किया जाता है। सामान्य धागों की ऐसी कोई कतार नहीं होती है, जैसे साधारण धागे की कोई कतार नहीं होती है। यह एक बार और निष्पादन के बाद खत्म हो जाता है, थ्रेड एक अन्य संदेश (रन करने योग्य) नहीं चलेगा।

हम लूपर वर्ग का उपयोग कहां कर सकते हैं?

यदि कोई व्यक्ति कई संदेशों (Runnables) को निष्पादित करना चाहता है, तो उसे लूपर वर्ग का उपयोग करना चाहिए जो धागे में एक कतार बनाने के लिए जिम्मेदार है। उदाहरण के लिए, इंटरनेट से फ़ाइलों को डाउनलोड करने वाले एप्लिकेशन को लिखते समय, हम कतार में डाउनलोड की जाने वाली फ़ाइलों को डालने के लिए लूपर क्लास का उपयोग कर सकते हैं।

यह काम किस प्रकार करता है?

नहीं है prepare()Looper तैयार करने के लिए विधि। तब आप loop()वर्तमान थ्रेड में एक संदेश लूप बनाने के लिए विधि का उपयोग कर सकते हैं और अब आपका लूपर पंक्ति में अनुरोधों को निष्पादित करने के लिए तैयार है जब तक आप लूप छोड़ नहीं देते।

यहां वह कोड है जिसके द्वारा आप लूपर तैयार कर सकते हैं।

class LooperThread extends Thread {
      public Handler mHandler;

      @Override
      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              @Override
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

17
एक AsyncTask उस उद्देश्य के लिए बेहतर है और कम जटिल है क्योंकि यह सभी थ्रेड प्रबंधन को एन्क्रिप्ट करता है।
फर्नांडो गैलेगो

4
रन से पहले @ ऑवरराइड एनोटेशन होना चाहिए () और हैंडलमैसेज () मेथड्स
एंड्रयू मैकेंजी

5
दस्तावेज़ इंगित करता है कि आपको looper.quit को कॉल करना होगा। ऊपर आपके कोड में, Looper.loop अनिश्चित काल के लिए ब्लॉक हो जाएगा।
AndroidDev

2
लूप कैसे छोड़ें। मेरा मतलब है कि उपरोक्त कोड उदाहरण में Looper.quit () को कहां शामिल किया जाए?
सीनू69

6
मुझे लगता है कि हैंडलर थ्रेड का उपयोग करना बेहतर होगा जो लूपर के साथ थ्रेड के लिए एक सुविधाजनक वर्ग है।
निमरोड दयाण

287

आप समझ सकते हैं कि Looper GUI फ्रेमवर्क के संदर्भ में क्या है। लूपर को 2 काम करने के लिए बनाया गया है।

1) Looper एक सामान्य थ्रेड को रूपांतरित करता है , जो तब चलता है जब इसकी रन () विधि वापस आती है, एंड्रॉइड ऐप के चलने तक कुछ लगातार चलता रहता है , जिसे GUI फ्रेमवर्क में आवश्यक है (तकनीकी रूप से, यह अभी भी समाप्त होता है जब रन () विधि वापस आती है। स्पष्ट करें कि मेरा क्या मतलब है नीचे)।

2) लूपर एक कतार प्रदान करता है जहां नौकरी करने के लिए गणना की जाती है, जो कि GUI ढांचे में भी आवश्यक है।

जैसा कि आप जानते हैं, जब कोई एप्लिकेशन लॉन्च किया जाता है, तो सिस्टम एप्लिकेशन के लिए निष्पादन का एक थ्रेड बनाता है, जिसे "मुख्य" कहा जाता है, और एंड्रॉइड एप्लिकेशन आम तौर पर "मुख्य धागा" को डिफ़ॉल्ट रूप से एक ही धागे पर पूरी तरह से चलाते हैं। लेकिन मुख्य धागा कुछ गुप्त, विशेष धागा नहीं है । यह आपके द्वारा new Thread()कोड के साथ बनाए गए थ्रेड के समान एक सामान्य धागा है , जिसका अर्थ है कि जब इसकी रन () विधि वापस आती है तो यह समाप्त हो जाती है! नीचे के उदाहरण के बारे में सोचो।

public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}

अब, इस सरल सिद्धांत को Android ऐप्स पर लागू करते हैं। यदि एंड्रॉइड ऐप सामान्य धागे पर चलता है तो क्या होगा? एक धागा जिसे "मुख्य" या "यूआई" कहा जाता है या जो भी आपका आवेदन शुरू करता है, और सभी यूआई खींचता है। तो, पहली स्क्रीन उपयोगकर्ताओं के लिए प्रदर्शित की जाती है। तो अब क्या? मुख्य धागा समाप्त हो गया? नहीं, ऐसा नहीं होना चाहिए। यह तब तक इंतजार करना चाहिए जब तक उपयोगकर्ता कुछ करते हैं, ठीक है? लेकिन हम इस व्यवहार को कैसे प्राप्त कर सकते हैं? खैर, हम Object.wait()या के साथ कोशिश कर सकते हैंThread.sleep()। उदाहरण के लिए, मुख्य धागा पहली स्क्रीन, और नींद प्रदर्शित करने के लिए अपना प्रारंभिक काम पूरा करता है। यह जागता है, जिसका अर्थ है बाधित, जब एक नया काम करना है। अब तक बहुत अच्छा है, लेकिन इस समय हमें कई नौकरियों को रखने के लिए एक कतार जैसी डेटा संरचना की आवश्यकता है। उस मामले के बारे में सोचें जब कोई उपयोगकर्ता क्रमिक रूप से स्क्रीन को छूता है, और एक कार्य को समाप्त होने में अधिक समय लगता है। इसलिए, हमें पहले-पहले-आउट तरीके से कार्य करने के लिए डेटा संरचना रखने की आवश्यकता है। इसके अलावा, आप कल्पना कर सकते हैं कि कभी-कभी-चलने-और-प्रक्रिया-नौकरी-जब-तब आने वाले धागे को बीच में रोककर लागू करना आसान नहीं है, और जटिल और अक्सर अस्वीकार्य कोड की ओर जाता है। हम इस तरह के उद्देश्य के लिए एक नया तंत्र बनाना चाहते हैं, और यही लूपर के बारे में हैलूपर वर्ग का आधिकारिक दस्तावेजकहते हैं, "डिफ़ॉल्ट रूप से थ्रेड्स में उनके साथ एक संदेश लूप नहीं होता है", और लूपर एक वर्ग है "जिसका उपयोग थ्रेड के लिए एक संदेश लूप चलाने के लिए किया जाता है"। अब आप समझ सकते हैं कि इसका क्या मतलब है।

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

public final class ActivityThread {
    ...
    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        Looper.loop();
        ...
    }
}

और Looper.loop()विधि लूप असीम रूप से और एक बार में एक संदेश और प्रक्रिया को समाप्त करता है:

public static void loop() {
    ...
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ...
        msg.target.dispatchMessage(msg);
        ...
    }
}

तो, मूल रूप से लूपर एक वर्ग है जो GUI ढांचे में होने वाली समस्या को हल करने के लिए बनाया गया है। लेकिन इस तरह की जरूरतें अन्य परिस्थितियों में भी हो सकती हैं। वास्तव में यह मल्टी थ्रेड्स एप्लिकेशन के लिए एक बहुत प्रसिद्ध पैटर्न है, और आप इसके बारे में अधिक जान सकते हैं कि डॉग ली (विशेष रूप से, अध्याय 4.1.4 "वर्कर थ्रेड्स" से " जावा में समवर्ती प्रोग्रामिंग " में मदद मिलेगी)। इसके अलावा, आप कल्पना कर सकते हैं कि इस तरह का तंत्र एंड्रॉइड फ्रेमवर्क में अद्वितीय नहीं है, लेकिन सभी जीयूआई ढांचे को इसके समान होने की आवश्यकता हो सकती है। आप जावा स्विंग ढांचे में लगभग एक ही तंत्र पा सकते हैं।


26
यह एकमात्र उत्तर है जो वास्तव में इस बारे में कुछ भी बताता है कि लूपर वर्ग कभी क्यों इस्तेमाल किया जाएगा। मुझे यकीन नहीं है कि यह शीर्ष उत्तर क्यों नहीं है, तीन उच्च श्रेणी के उत्तर कुछ भी नहीं समझाते हैं।
एंड्रयू कोस्टर

4
@AK। इसलिए मैंने इस जवाब को जोड़ा, यहां तक ​​कि बहुत देर हो गई। मुझे खुशी है कि मेरे जवाब ने आपकी मदद की! :)
김준호

1
@ हे-मेन-व्हाट्सअप यस
men

1
इसे पढ़ने से पहले मैं "Looper ???" जैसा था। और अब "ओह, हाँ, चलिए चर्चा करते हैं"। धन्यवाद आदमी, महान जवाब :)
umerk44

त्वरित प्रश्न। आपने कहा था कि मुख्य थ्रेड में यूआई तत्वों को निकालने के बाद इसे सोने के लिए रखा जाता है। लेकिन मान लें कि उपयोगकर्ता स्क्रीन पर एक बटन के साथ इंटरैक्ट करता है, क्या वह बटन मुख्य कतार में भी नहीं लगाया जाता है, फिर कोई वस्तु उसे सही गतिविधि के लिए भेज देगी, फिर उस गतिविधि के लिए मुख्य थ्रेड जागृत हो जाएगा और यह निष्पादित हो जाएगा उस बटन पर क्लिक करने के लिए कॉलबैक में कोड?
CapturedTree

75

लूपर कार्यों को एकल थ्रेड पर क्रमिक रूप से निष्पादित करने की अनुमति देता है। और हैंडलर उन कार्यों को परिभाषित करता है जिन्हें हमें निष्पादित करने की आवश्यकता होती है। यह एक विशिष्ट परिदृश्य है जिसे मैं इस उदाहरण में चित्रित करने का प्रयास कर रहा हूं:

class SampleLooper extends Thread {
@Override
public void run() {
  try {
    // preparing a looper on current thread     
    // the current thread is being detected implicitly
    Looper.prepare();

    // now, the handler will automatically bind to the
    // Looper that is attached to the current thread
    // You don't need to specify the Looper explicitly
    handler = new Handler();

    // After the following line the thread will start
    // running the message loop and will not normally
    // exit the loop unless a problem happens or you
    // quit() the looper (see below)
    Looper.loop();
  } catch (Throwable t) {
    Log.e(TAG, "halted due to an error", t);
  } 
}
}

अब हम निष्पादित करने के लिए लूपर पर कार्य पोस्ट करने के लिए हैंडलर का उपयोग कुछ अन्य थ्रेड्स (ui थ्रेड) कह सकते हैं।

handler.post(new Runnable()
{
public void run() {
//This will be executed on thread using Looper.
    }
});

UI थ्रेड पर हमारे पास एक अंतर्निहित लूपर है जो हमें ui थ्रेड पर संदेशों को संभालने की अनुमति देता है।


यह किसी भी UI प्रोसेस को लॉक नहीं करेगा, क्या यह सच है?
गमरू

4
"जॉब्स" को कतार में कैसे पोस्ट किया जाए, इसके नमूने के लिए धन्यवाद
पीटर लिलवॉल्ड

यह व्याख्या नहीं करता है कि कोई इस वर्ग का उपयोग क्यों करेगा, केवल कैसे।
एंड्रयू कोस्टर

33

Android Looperसंलग्न MessageQueueकरने के लिए एक आवरण है Threadऔर यह कतार प्रसंस्करण का प्रबंधन करता है। यह एंड्रॉइड प्रलेखन में बहुत गूढ़ दिखता है और कई बार हमें सामना करना पड़ सकता हैLooper संबंधित यूआई एक्सेस मुद्दों का । यदि हम मूल बातें नहीं समझते हैं तो इसे संभालना बहुत कठिन हो जाता है।

यहाँ एक है लेख जो बताते हैं Looperजीवन चक्र, यह और के उपयोग कैसे उपयोग करने के लिए LooperमेंHandler

यहां छवि विवरण दर्ज करें

लूपर = थ्रेड + मैसेजक्यू


3
यह व्याख्या नहीं करता है कि कोई इस वर्ग का उपयोग क्यों करेगा, केवल कैसे।
एंड्रयू कोस्टर

14

लूपर और हैंडलर की परिभाषा:

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

विवरण:

तो एक पाइपलाइन थ्रेड एक थ्रेड है जो हैंडलर के माध्यम से अन्य थ्रेड्स से अधिक कार्यों को स्वीकार कर सकता है।

Looper नाम इसलिए दिया गया है क्योंकि यह पाश को लागू करता है - अगले काम लेता है, वह निष्पादित तो अगले एक और इतने पर ले जाता है। हैंडलर को हैंडलर कहा जाता है क्योंकि इसका उपयोग अगले कार्य को हर बार किसी अन्य थ्रेड से संभालने या स्वीकार करने के लिए किया जाता है और लूपर (थ्रेड या पाइपलाइन थ्रेड) को पास किया जाता है।

उदाहरण:

एक लूपर और हैंडलर या पाइपलाइन थ्रेड का बहुत ही सटीक उदाहरण है एक से अधिक छवियों को डाउनलोड करना या उन्हें बैकग्राउंड में प्रत्येक नेटवर्क कॉल के लिए एक नया थ्रेड शुरू करने के बजाय एक ही धागे में एक-एक करके सर्वर (Http) पर अपलोड करना।

Looper और हैंडलर और पाइपलाइन थ्रेड की परिभाषा के बारे में यहाँ और पढ़ें:

Android हिम्मत: लूपर्स और हैंडलर्स के लिए परिचय


7

एक Looper एक है synchronized MessageQueueकि इस प्रक्रिया कतार पर रखा संदेश के लिए प्रयोग किया जाता है।

यह एक Threadविशिष्ट भंडारण पैटर्न को लागू करता है ।

केवल एक Looperप्रति Thread। मुख्य विधियों में शामिल हैं prepare(), loop()और quit()

prepare()Threadएक के रूप में वर्तमान को इनिशियलाइज़ करता है Looperprepare()वह staticविधि है जो ThreadLocalनीचे दिखाए अनुसार कक्षा का उपयोग करती है ।

   public static void prepare(){
       ...
       sThreadLocal.set
       (new Looper());
   }
  1. prepare() ईवेंट लूप चलाने से पहले स्पष्ट रूप से कहा जाना चाहिए।
  2. loop()ईवेंट लूप चलाता है, जो संदेशों के लिए किसी विशिष्ट थ्रेड के संदेश पर पहुंचने की प्रतीक्षा करता है। अगला संदेश प्राप्त होते ही, loop()विधि संदेश को अपने लक्ष्य हैंडलर को भेज देती है
  3. quit()इवेंट लूप को बंद कर देता है। यह लूप को समाप्त नहीं करता है, लेकिन इसके बजाय यह एक विशेष संदेश देता है

LooperThreadकई चरणों के माध्यम से क्रमादेशित किया जा सकता है

  1. बढ़ाएँ Thread

  2. Looper.prepare()थ्रेड को इनिशियलाइज़ करने के लिए कॉल करें aLooper

  3. Handlerआने वाले संदेशों को संसाधित करने के लिए एक या अधिक (ओं) बनाएँ

  4. Looper.loop()संदेशों को प्रोसेस करने के लिए तब तक कॉल करें जब तक कि लूप को न बता दिया जाए quit()

5

विधि के पूरा होने के बाद जावा थ्रेड का जीवनकाल समाप्त हो गया है run()। एक ही धागा फिर से शुरू नहीं किया जा सकता है।

लूपरThread एक संदेश लूप में सामान्य रूपांतरित करता है। इसकी प्रमुख विधियाँ Looperहैं:

void prepare ()

लूपर के रूप में वर्तमान थ्रेड को प्रारंभ करें। यह आपको हैंडलर बनाने का मौका देता है जो वास्तव में लूप शुरू करने से पहले इस लूपर को संदर्भित करता है। इस विधि को कॉल करने के बाद लूप () को कॉल करना सुनिश्चित करें, और इसे कॉल () छोड़ कर समाप्त करें।

void loop ()

संदेश थ्रेड को इस थ्रेड में चलाएँ। लूप को समाप्त करने के लिए कॉल () छोड़ना सुनिश्चित करें।

void quit()

लोफर छोड़ देता है।

संदेश कतार में किसी भी अधिक संदेश को संसाधित किए बिना लूप () विधि को समाप्त करता है।

Janishar का यह माइंडकोर लेख मूल अवधारणाओं को अच्छे तरीके से समझाता है।

यहां छवि विवरण दर्ज करें

Looperएक थ्रेड के साथ जुड़ा हुआ है। यदि आपको LooperUI थ्रेड पर आवश्यकता है , Looper.getMainLooper()तो संबंधित थ्रेड वापस आ जाएगा।

आपको Looperएक हैंडलर के साथ जुड़ा होना चाहिए ।

Looper, Handlerऔर HandlerThreadअतुल्यकालिक प्रोग्रामिंग की समस्याओं को हल करने का एंड्रॉयड का तरीका है।

आपके पास एक बार Handler, आप एपीआई से नीचे कॉल कर सकते हैं।

post (Runnable r)

संदेश कतार में Runnable r जोड़ने का कारण बनता है। रननेबल को उस थ्रेड पर चलाया जाएगा, जिससे यह हैंडलर जुड़ा हुआ है।

boolean sendMessage (Message msg)

वर्तमान समय से पहले सभी लंबित संदेशों के बाद संदेश कतार के अंत में एक संदेश देता है। इस हैंडलर से जुड़े धागे में इसे हैंडलमेसेज (संदेश) में प्राप्त किया जाएगा।

HandlerThread एक नया धागा शुरू करने के लिए आसान वर्ग है जिसमें एक लूपर है। लूपर का उपयोग तब हैंडलर कक्षाएं बनाने के लिए किया जा सकता है

कुछ स्थितियों में, आप RunnableUI थ्रेड पर कार्य नहीं चला सकते हैं । उदाहरण के लिए नेटवर्क संचालन: एक सॉकेट पर संदेश भेजें, एक URL खोलें और पढ़ने से सामग्री प्राप्त करेंInputStream

इन मामलों में, HandlerThreadउपयोगी है। आप मुख्य थ्रेड के बजाय Looperऑब्जेक्ट से प्राप्त कर सकते हैं HandlerThreadऔर Handlerऑन कर सकते हैं HandlerThread

HandlerThread कोड इस तरह होगा:

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

उदाहरण कोड के लिए नीचे पोस्ट देखें:

Android: एक धागे में टोस्ट


5

लूपर थ्रेड्स को समझना

एक जावा थ्रेड निष्पादन की एक इकाई है जिसे उसके रन () विधि में एक कार्य करने के लिए डिज़ाइन किया गया था और उसके बाद समाप्त: यहां छवि विवरण दर्ज करें

लेकिन एंड्रॉइड में कई उपयोग के मामले हैं जहां हमें थ्रेड को जीवित रखने और उपयोगकर्ता इनपुट / ईवेंट के लिए प्रतीक्षा करने की आवश्यकता होती है। यूआई धागा उर्फMain Thread

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

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

यहां छवि विवरण दर्ज करें

अब यहाँ ध्यान दें, हालांकि मुख्य धागा जावा धागा है फिर भी यह उपयोगकर्ता की घटनाओं को सुनता रहता है और स्क्रीन पर 60 एफपीएस फ्रेम खींचता है और फिर भी यह प्रत्येक चक्र के बाद नहीं मरता है। यह कैसे है?

इसका जवाब है लूपर क्लास : लूपर एक ऐसी क्लास है, जिसका इस्तेमाल किसी थ्रेड को जिंदा रखने और उस थ्रेड पर टास्क को अंजाम देने के लिए एक मैसेज कतार को मैनेज करने के लिए किया जाता है।

डिफ़ॉल्ट रूप से थ्रेड्स में उनके साथ एक संदेश लूप जुड़ा नहीं होता है, लेकिन आप रन विधि में Looper.prepare () कॉल करके एक असाइन कर सकते हैं और फिर Looper.loop () कॉल कर सकते हैं।

लूपर का उद्देश्य एक थ्रेड को जीवित रखना है और Messageगणना करने के लिए इनपुट ऑब्जेक्ट के अगले चक्र की प्रतीक्षा करना है जो अन्यथा निष्पादन के पहले चक्र के बाद नष्ट हो जाएगा।

यदि आप गहरी खुदाई करना चाहते हैं कि लूपर Messageऑब्जेक्ट क्यू को कैसे प्रबंधित करता है तो आप स्रोत कोड पर एक नज़र डाल सकते हैं Looperclass:

https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/os/Looper.java

नीचे एक उदाहरण दिया गया है कि आप कक्षा का उपयोग करके कैसे बना सकते हैं Looper Threadऔर संवाद कर सकते हैंActivityLocalBroadcast

class LooperThread : Thread() {

    // sendMessage success result on UI
    private fun sendServerResult(result: String) {
        val resultIntent = Intent(ServerService.ACTION)
        resultIntent.putExtra(ServerService.RESULT_CODE, Activity.RESULT_OK)
        resultIntent.putExtra(ServerService.RESULT_VALUE, result)
        LocalBroadcastManager.getInstance(AppController.getAppController()).sendBroadcast(resultIntent)
    }

    override fun run() {
        val looperIsNotPreparedInCurrentThread = Looper.myLooper() == null

        // Prepare Looper if not already prepared
        if (looperIsNotPreparedInCurrentThread) {
            Looper.prepare()
        }

        // Create a handler to handle messaged from Activity
        handler = Handler(Handler.Callback { message ->
            // Messages sent to Looper thread will be visible here
            Log.e(TAG, "Received Message" + message.data.toString())

            //message from Activity
            val result = message.data.getString(MainActivity.BUNDLE_KEY)

            // Send Result Back to activity
            sendServerResult(result)
            true
        })

        // Keep on looping till new messages arrive
        if (looperIsNotPreparedInCurrentThread) {
            Looper.loop()
        }
    }

    //Create and send a new  message to looper
    fun sendMessage(messageToSend: String) {
        //Create and post a new message to handler
        handler!!.sendMessage(createMessage(messageToSend))
    }


    // Bundle Data in message object
    private fun createMessage(messageToSend: String): Message {
        val message = Message()
        val bundle = Bundle()
        bundle.putString(MainActivity.BUNDLE_KEY, messageToSend)
        message.data = bundle
        return message
    }

    companion object {
        var handler: Handler? = null // in Android Handler should be static or leaks might occur
        private val TAG = javaClass.simpleName

    }
}

उपयोग :

 class MainActivity : AppCompatActivity() {

    private var looperThread: LooperThread? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // start looper thread
        startLooperThread()

        // Send messages to Looper Thread
        sendMessage.setOnClickListener {

            // send random messages to looper thread
            val messageToSend = "" + Math.random()

            // post message
            looperThread!!.sendMessage(messageToSend)

        }   
    }

    override fun onResume() {
        super.onResume()

        //Register to Server Service callback
        val filterServer = IntentFilter(ServerService.ACTION)
        LocalBroadcastManager.getInstance(this).registerReceiver(serverReceiver, filterServer)

    }

    override fun onPause() {
        super.onPause()

        //Stop Server service callbacks
     LocalBroadcastManager.getInstance(this).unregisterReceiver(serverReceiver)
    }


    // Define the callback for what to do when data is received
    private val serverReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val resultCode = intent.getIntExtra(ServerService.RESULT_CODE, Activity.RESULT_CANCELED)
            if (resultCode == Activity.RESULT_OK) {
                val resultValue = intent.getStringExtra(ServerService.RESULT_VALUE)
                Log.e(MainActivity.TAG, "Server result : $resultValue")

                serverOutput.text =
                        (serverOutput.text.toString()
                                + "\n"
                                + "Received : " + resultValue)

                serverScrollView.post( { serverScrollView.fullScroll(View.FOCUS_DOWN) })
            }
        }
    }

    private fun startLooperThread() {

        // create and start a new LooperThread
        looperThread = LooperThread()
        looperThread!!.name = "Main Looper Thread"
        looperThread!!.start()

    }

    companion object {
        val BUNDLE_KEY = "handlerMsgBundle"
        private val TAG = javaClass.simpleName
    }
}

क्या हम इसके बजाय Async task या Intent Services का उपयोग कर सकते हैं?

  • Async कार्य पृष्ठभूमि में एक छोटा ऑपरेशन करने और UI थ्रेड पर प्रोग्रेस और परिणाम देने के लिए डिज़ाइन किए गए हैं। Async कार्य की सीमाएँ होती हैं जैसे कि आप 128 से अधिक Async कार्य नहीं कर सकते हैं और ThreadPoolExecutorकेवल 5 Async कार्य करने देंगे ।

  • IntentServicesथोड़ी लंबी अवधि के लिए पृष्ठभूमि कार्य करने के लिए भी डिज़ाइन किया गया है और आप इसके LocalBroadcastसाथ संवाद करने के लिए उपयोग कर सकते हैं Activity। लेकिन कार्य निष्पादन के बाद सेवाएँ नष्ट हो जाती हैं। यदि आप इसे लंबे समय तक चालू रखना चाहते हैं तो आपको इसकी तरह हेक करने की आवश्यकता है while(true){...}

लूपर थ्रेड के लिए अन्य सार्थक उपयोग के मामले:

  • 2 तरह से सॉकेट संचार के लिए उपयोग किया जाता है जहां सर्वर क्लाइंट सॉकेट को सुनता रहता है और पावती लिखता है

  • पृष्ठभूमि में बिटमैप प्रसंस्करण। लूप थ्रेड के लिए छवि url पास करें और यह फ़िल्टर प्रभाव लागू करेगा और इसे टेम्परेरी रोरी स्थान में संग्रहीत करेगा और फिर छवि का अस्थायी मार्ग प्रसारित करेगा।


4

इस उत्तर का सवाल से कोई लेना-देना नहीं है, लेकिन लूपर के उपयोग और लोगों द्वारा सभी उत्तरों में जिस तरह से हैंडलर और लूपर बनाया गया है, वह सादा बुरा व्यवहार है (कुछ स्पष्टीकरण हालांकि सही हैं), मुझे यह पोस्ट करना होगा:

HandlerThread thread = new HandlerThread(threadName);
thread.start();
Looper looper = thread.getLooper();
Handler myHandler = new Handler(looper);

और पूर्ण कार्यान्वयन के लिए


3

किसी सेवा में कई डाउन या अपलोड आइटम को हैंडल करना एक बेहतर उदाहरण है।

Handlerऔर AsnycTaskअक्सर यूआई (थ्रेड) और वर्कर थ्रेड या क्रियाओं में देरी के बीच ईवेंट्स / मैसेजेस को प्रचारित करने के लिए उपयोग किया जाता है । इसलिए वे यूआई से अधिक संबंधित हैं।

एक थ्रेड संबंधित कतार Looper( रनवेबल्स, फ्यूचर्स ) को बैकग्राउंड में एक थ्रेड से संबंधित कतार में रखता है - यहां तक ​​कि कोई उपयोगकर्ता इंटरैक्शन या एक प्रदर्शित यूआई के साथ (ऐप कॉल के दौरान पृष्ठभूमि में एक फ़ाइल डाउनलोड करता है)।


1

लूपर क्या है?

DOCS से

Looper

Looperक्लास एक के लिए एक मैसेज लूप चलाता था thread। डिफ़ॉल्ट रूप से थ्रेड्स में एक संदेश लूप नहीं होता है जो उनके साथ जुड़ा हुआ है; एक बनाने के लिए, prepare()थ्रेड में कॉल करें जो लूप को चलाने के लिए है, और फिर loop()लूप बंद होने तक इसे संदेशों को संसाधित करने के लिए है।

  • एक Looperसंदेश हैंडलिंग लूप है:
  • लूपर का एक महत्वपूर्ण चरित्र यह है कि यह थ्रेड के साथ जुड़ा हुआ है जिसके भीतर लूपर बनाया गया है
  • लूपर वर्ग एक रखता है MessageQueue, जिसमें एक सूची संदेश होता है। लूपर का एक महत्वपूर्ण चरित्र यह है कि यह थ्रेड के साथ जुड़ा हुआ है जिसके भीतर लूपर बनाया गया है।
  • Looperनाम इसलिए दिया है क्योंकि यह पाश को लागू करता है - अगले काम लेता है, वह निष्पादित तो अगले एक और इतने पर ले जाता है। Handlerहैंडलर कहा जाता है क्योंकि किसी एक बेहतर नाम का आविष्कार नहीं कर सकता
  • एंड्रॉइड Looperएक एंड्रॉइड यूजर इंटरफेस के भीतर जावा क्लास है जो एक साथ यूटर ईवेंट को बटन क्लिक, स्क्रीन रिडर्व और ओरिएंटेशन स्विच करने के लिए हैंडलर क्लास के साथ होता है।

यह काम किस प्रकार करता है?

यहां छवि विवरण दर्ज करें

लूपर बनाना

एक धागा मिलता है Looperऔर उसके चलने के बाद MessageQueueकॉल करके Looper.prepare()Looper.prepare()कॉलिंग थ्रेड की पहचान करता है, एक लूपर और MessageQueueऑब्जेक्ट बनाता है और थ्रेड को संबद्ध करता है

नमूना कोड

class MyLooperThread extends Thread {

      public Handler mHandler; 

      public void run() { 

          // preparing a looper on current thread  
          Looper.prepare();

          mHandler = new Handler() { 
              public void handleMessage(Message msg) { 
                 // process incoming messages here
                 // this will run in non-ui/background thread
              } 
          }; 

          Looper.loop();
      } 
  }

अधिक जानकारी के लिए नीचे पोस्ट देखें


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