दूसरे धागे से मुख्य धागे में कोड चल रहा है


326

एक Android सेवा में मैंने कुछ पृष्ठभूमि कार्य करने के लिए थ्रेड बनाए हैं।

मेरे पास एक ऐसी स्थिति है जहां एक धागे को मुख्य धागे की संदेश कतार पर कुछ कार्य पोस्ट करने की आवश्यकता होती है, उदाहरण के लिए Runnable

क्या Handlerमुख्य धागा और पोस्ट करने का एक तरीका है Message/ Runnableयह मेरे अन्य धागे से है?

धन्यवाद,


2
आप कस्टम प्रसारण रिसीवर का भी उपयोग कर सकते हैं .... मेरा उत्तर यहां देखें, [इनर ब्रॉडकास्ट रिसीवर] [1] [१]: stackoverflow.com/a/22541324/1881527
मेलबर्न लोप्स

बहुत तरीके हैं। अपने उत्तर में डेविड के उत्तर और डेज़ाइकी की टिप्पणी के अलावा, (3) आप एक ब्रॉडकास्ट रिसीवर का उपयोग कर सकते हैं, या (4) सर्विस शुरू करने के लिए उपयोग किए जाने वाले इंटेंट के अतिरिक्त में हैंडलर को पास कर सकते हैं, और फिर गेटआईंटेंट का उपयोग करके सेवा के अंदर मुख्य थ्रेड के हैंडवाइवर को पुनः प्राप्त कर सकते हैं ( ) .getExtras ()।
अशोक बिजॉय देबनाथ

2
@ sazzad-hissain-khan, 2012 के इस सवाल का टैग ज्यादातर जावा में कोटलिन टैग के साथ क्यों दिया गया?
Tenfour04

जवाबों:


617

नोट: इस उत्तर पर इतना ध्यान गया है, कि मुझे इसे अद्यतन करने की आवश्यकता है। चूंकि मूल उत्तर पोस्ट किया गया था, @dzeikei की टिप्पणी ने मूल उत्तर के रूप में लगभग ध्यान दिया है। तो यहाँ 2 संभावित समाधान हैं:

1. यदि आपके बैकग्राउंड थ्रेड में किसी Contextऑब्जेक्ट का संदर्भ है :

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

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. यदि आपके बैकग्राउंड थ्रेड में Contextऑब्जेक्ट नहीं है (या जरूरत है)

(@dzeikei द्वारा सुझाया गया):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

1
धन्यवाद डेविड यह मेरे लिए काम करता है, एक और बात अगर आप मेरी मदद कर सकते हैं, अगर मैं हैंडलर बढ़ाता हूं और हैंडल संभालता हूं () क्या यह मुख्य थ्रेड को अपने संदेशों को संभालने से रोक देगा? कि .. curosity में से केवल एक सवाल है
अहमद

2
यदि आप उपखंड Handler(या Handler.Callbackइंटरफ़ेस का उपयोग करते हैं ) तो आपकी handleMessage()विधि केवल उन संदेशों के लिए कॉल की जाएगी जिन्हें आपके हैंडलर का उपयोग करके पोस्ट किया गया है। संदेशों को पोस्ट / प्रोसेस करने के लिए मुख्य थ्रेड एक अलग हैंडलर का उपयोग कर रहा है ताकि कोई विवाद न हो।
डेविड वासर

205
मेरा मानना ​​है कि आपको संदर्भ की आवश्यकता नहीं होगी यदि आप उपयोग करते हैंHandler mainHandler = new Handler(Looper.getMainLooper());
dzeikei

6
मामूली बिंदु; आपका कोड वह स्थान नहीं है जहाँ ... वर्तमान में है। यह होना चाहिएnew Runnable(){@Override public void run() {....}};
रिचर्ड टिंगल

1
@ सागरदेवगंगा एक अलग सवाल पूछने के लिए यह सही जगह नहीं है। कृपया एक असंबंधित उत्तर के लिए एक टिप्पणी नहीं, एक नया प्रश्न पोस्ट करें। आपको इस तरह से बेहतर और तेज़ प्रतिक्रिया मिलेगी।
डेविड वासर

138

नीचे दिए गए एक टिप्पणीकार के रूप में सही ढंग से बताया गया है, यह सेवाओं के लिए एक सामान्य समाधान नहीं है, केवल आपकी गतिविधि से लॉन्च किए गए थ्रेड्स के लिए (एक सेवा ऐसा धागा हो सकती है, लेकिन उन सभी में से नहीं है)। सेवा-गतिविधि संचार के जटिल विषय पर कृपया आधिकारिक दस्तावेज़ के पूरे सेवा खंड को पढ़ें - यह जटिल है, इसलिए यह मूल बातें समझने के लिए भुगतान करेगा: http://developer.android.com/guide/compenders/services.html #Notifications

नीचे दी गई विधि सरलतम मामलों में काम कर सकती है।

अगर मैं आपको सही ढंग से समझता हूं कि आपको एप्लिकेशन के GUI थ्रेड में कुछ कोड निष्पादित करने की आवश्यकता है ("मुख्य" थ्रेड नामक कुछ और के बारे में नहीं सोच सकता है)। इसके लिए एक विधि है Activity:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

आशा है कि यह आप के लिए क्या देख रहे हैं।


20
ओपी का कहना है कि वह थ्रेड्स चला रहा है Service। आप उपयोग नहीं कर सकते runOnUiThread()एक में Service। यह उत्तर भ्रामक है और पूछे गए प्रश्न को संबोधित नहीं करता है।
डेविड वासर

31

एक और सरल तरीका है, यदि आपके पास प्रसंग तक पहुँच नहीं है।

1)। मुख्य लूपर से एक हैंडलर बनाएं:

Handler uiHandler = new Handler(Looper.getMainLooper());

2)। एक चल इंटरफ़ेस लागू करें:

Runnable runnable = new Runnable() { // your code here }

3)। UiHandler के लिए अपने Runnable पोस्ट करें:

uiHandler.post(runnable);

यह सब ;-) धागे के साथ मज़े करो, लेकिन उन्हें सिंक्रनाइज़ करने के लिए मत भूलना।


29

यदि आप एक थ्रेड में कोड चलाते हैं, उदाहरण के लिए कुछ कार्रवाई में देरी करते हैं, तो आपको runOnUiThreadसंदर्भ से आह्वान करने की आवश्यकता है । उदाहरण के लिए, यदि आपका कोड MainActivityकक्षा के अंदर है तो इसका उपयोग करें:

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

यदि आपका तरीका मुख्य (UI थ्रेड) या अन्य थ्रेड्स से मंगवाया जा सकता है, तो आपको एक चेक की आवश्यकता है:

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}

7
ओपी का कहना है कि वह थ्रेड्स चला रहा है Service। आप उपयोग नहीं कर सकते runOnUiThread()एक में Service
डेविड वासर

@DavidWasser क्या यह कहीं भी प्रलेखित है? विधि डॉक्स इसके बारे में कुछ भी उल्लेख नहीं करते हैं। डेवलपर
ग्रेग ब्राउन

1
@GregBrown जैसा कि आपने Activityप्रलेखन के लिए अपने लिंक से संकेत दिया है , runOnUiThread()की एक विधि है Activity। यह एक विधि नहीं है Service, इसलिए आप इसका उपयोग नहीं कर सकते। इससे साफ क्या हो सकता है?
डेविड वासर

@ डेविडविशर मेला काफी मुझे यह भी याद नहीं है कि मैंने यह सवाल क्यों पूछा (यह लगभग एक साल पहले पोस्ट किया गया था)।
ग्रेग ब्राउन

24

एक संघनित कोड ब्लॉक इस प्रकार है:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

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

कोटलिन समतुल्य:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

20

कोटलीन संस्करण

जब आप किसी गतिविधि पर हों , तब उपयोग करें

runOnUiThread {
    //code that runs in main
}

जब आपके पास गतिविधि संदर्भ हो , तो mContext का उपयोग करें

mContext.runOnUiThread {
    //code that runs in main
}

जब आप कहीं ऐसे हों , जहां कोई संदर्भ उपलब्ध नहीं है , तो उपयोग करें

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}

यह निश्चित नहीं है कि कोटलिन का कौन सा संस्करण है, लेकिन मुझे ब्रेसिज़ जोड़ना था:runOnUiThread(){...}
वीएक्स

5

अगर आपके पास कोई संदर्भ नहीं है तो सबसे आसान तरीका है, यदि आप RxAndroid का उपयोग कर रहे हैं, तो आप कर सकते हैं:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}


4

एक विधि जो मैं सोच सकता हूं वह यह है:

1) यूआई को सेवा से बांधने दें।
2) एक विधि को बेनकाब करें, जैसे कि नीचे वाला अपने Binderको पंजीकृत करता है Handler:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) यूआई थ्रेड में, सेवा के लिए बाध्य करने के बाद उपरोक्त विधि को कॉल करें:

mBinder.registerHandler(new Handler());

4) अपने कार्य को पोस्ट करने के लिए सेवा के धागे में हैंडलर का उपयोग करें:

mHandler.post(runnable);

3

HandlerThread Android में सामान्य जावा थ्रेड्स का बेहतर विकल्प है।

  1. हैंडलरट्रेड बनाएं और इसे शुरू करें
  2. एक बनाएं हैंडलर साथ Looper HandlerThread से:requestHandler
  3. postएक Runnableकार्य परrequestHandler

से UI थ्रेड के साथ संचार HandlerThread

  1. मुख्य धागे के लिए एक Handlerसाथ बनाएं Looper: responseHandlerऔर handleMessageविधि को ओवरराइड करें
  2. अंदर Runnableअन्य थ्रेड (का कार्य HandlerThreadइस मामले में), फोन sendMessageपरresponseHandler
  3. इस sendMessageपरिणाम handleMessageमें शामिल हैं responseHandler
  4. से गुण प्राप्त करें Messageऔर इसे संसाधित, अद्यतन यूआई

उदाहरण : TextViewवेब सेवा से प्राप्त डेटा के साथ अद्यतन । चूंकि HandlerThreadनेटवर्क ऑपरेशन के लिए बनाई गई गैर-यूआई थ्रेड पर वेब सेवा को लागू किया जाना चाहिए । एक बार जब आप वेब सेवा से सामग्री प्राप्त कर लेते हैं, तो अपने मुख्य थ्रेड (UI थ्रेड) हैंडलर को संदेश भेजें और यह Handlerमैसेज को हैंडल करेगा और यूआई को अपडेट करेगा।

नमूना कोड:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

उपयोगी लेख:

handlerthreads और क्यों में आप चाहिए होने वाली का उपयोग कर-उन्हें-इन-अपने-android-क्षुधा

android-looper-हैंडलर-handlerthread-मैं


2

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

जावा (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

Kotlin:

this.runOnUiThread {
     //your main thread code
}

1

इस विधि का पालन करें। इस तरह से आप यूआई को बैकग्राउंड थ्रेड से अपडेट कर सकते हैं। runOnUiThread मुख्य (UI) थ्रेड पर काम करते हैं। मुझे लगता है कि यह कोड स्निपेट कम जटिल और आसान है, खासकर शुरुआती लोगों के लिए।

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

एक सेवा के मामले में

oncreate में एक हैंडलर बनाएं

 handler = new Handler();

तो इसे इस तरह का उपयोग करें

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }

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


1

तो सबसे आसान काम करना है:

import android.os.AsyncTask
import android.os.Handler
import android.os.Looper

object Dispatch {
    fun asyncOnBackground(call: ()->Unit) {
        AsyncTask.execute {
            call()
        }
    }

    fun asyncOnMain(call: ()->Unit) {
        Handler(Looper.getMainLooper()).post {
            call()
        }
    }
}

और बाद में:

Dispatch.asyncOnBackground {
    val value = ...// super processing
    Dispatch.asyncOnMain { completion(value)}
}

0
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

यह बिना किसी समस्या के सेवा वर्ग में भी काम कर सकता है।


हालांकि यह कोड उस प्रश्न का उत्तर दे सकता है जो आप अभी भी कुछ व्याख्यात्मक वाक्य जोड़ने पर विचार कर सकते हैं क्योंकि इससे अन्य उपयोगकर्ताओं के लिए आपके उत्तर का मूल्य बढ़ जाता है!
एमबीटी

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