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




multithreading android-looper (6)

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


आप बेहतर समझ सकते हैं कि लूपर जीयूआई ढांचे के संदर्भ में क्या है। लूपर 2 चीजें करने के लिए किया जाता है।

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

2) लूपर एक कतार प्रदान करता है जहां काम करने के लिए काम किया जाता है, जिसे जीयूआई ढांचे में भी जरूरी है।

जैसा कि आप जानते हैं, जब कोई एप्लिकेशन लॉन्च किया जाता है, तो सिस्टम "मुख्य" नामक एप्लिकेशन के लिए निष्पादन का धागा बनाता है, और एंड्रॉइड एप्लिकेशन सामान्य रूप से "मुख्य धागे" डिफ़ॉल्ट रूप से एक थ्रेड पर पूरी तरह से चलते हैं। लेकिन मुख्य धागा कुछ गुप्त, विशेष धागा नहीं है । यह केवल थ्रेड के समान सामान्य थ्रेड है जो आप 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();
    }
}

अब, आइए एंड्रॉइड ऐप पर इस सरल सिद्धांत को लागू करें। यदि एंड्रॉइड ऐप सामान्य थ्रेड पर चलता है तो क्या होगा? एक धागा जिसे "मुख्य" या "यूआई" कहा जाता है या जो भी आपका आवेदन शुरू करता है, और सभी यूआई खींचता है। तो, पहली स्क्रीन उपयोगकर्ताओं को प्रदर्शित की जाती है। तो अब क्या? मुख्य धागा समाप्त हो जाता है? नहीं, यह नहीं होना चाहिए। इसे तब तक इंतजार करना चाहिए जब तक उपयोगकर्ता कुछ नहीं करते, है ना? लेकिन हम इस व्यवहार को कैसे प्राप्त कर सकते हैं? खैर, हम 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);
        ...
    }
}

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


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

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

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


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

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

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


एक Looper में एक synchronized किया गया संदेश क्यूई है जिसका उपयोग कतार पर रखे संदेशों को संसाधित करने के लिए किया जाता है।

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

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

prepare() Looper रूप में वर्तमान Thread करता है। prepare() static विधि है जो नीचे दिखाए गए ThreadLocal वर्ग का उपयोग करती है।

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

Looper को कई चरणों के माध्यम से Thread में प्रोग्राम किया जा सकता है

  1. Thread बढ़ाएं

  2. Looper रूप में थ्रेड को प्रारंभ करने के लिए Looper.prepare() पर कॉल करें

  3. इनकमिंग संदेशों को संसाधित करने के लिए एक या अधिक Handler बनाएं

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

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

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

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

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

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


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

तो एक PipeLine Thread एक धागा है जो Handler माध्यम से अन्य धागे से अधिक कार्यों को स्वीकार कर सकता है।

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

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

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

एंड्रॉइड गेट्स: लूपर और हैंडलर के लिए परिचय





android-looper