Android मूल बातें: UI थ्रेड में कोड चल रहा है


450

UI थ्रेड में कोड चलाने के दृष्टिकोण में, क्या कोई अंतर है:

MainActivity.this.runOnUiThread(new Runnable() {
    public void run() {
        Log.d("UI thread", "I am the UI thread");
    }
});

या

MainActivity.this.myView.post(new Runnable() {
    public void run() {
        Log.d("UI thread", "I am the UI thread");
    }
});

तथा

private class BackgroundTask extends AsyncTask<String, Void, Bitmap> {
    protected void onPostExecute(Bitmap result) {
        Log.d("UI thread", "I am the UI thread");
    }
}

मेरे प्रश्न को स्पष्ट करने के लिए: मेरा मानना ​​था कि उन कोड को सेवा थ्रेड से बुलाया गया था, आमतौर पर एक श्रोता। मेरा यह भी मानना ​​था कि पहले दो स्निपेट से पहले कॉल किए गए असिनटैस्क या एक नए टास्क (...) में DoInBackground () फ़ंक्शन को पूरा करने के लिए एक भारी काम है। वैसे भी AsyncTask के onPostExecute () को इवेंट कतार के अंत में रखा जा रहा है, है ना?
लूकी

जवाबों:


288

उनमें से कोई भी ठीक समान नहीं हैं, हालांकि वे सभी समान प्रभाव डालेंगे।

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

तीसरा, जो आप मानते हैं कि आप एक उदाहरण बनाते हैं और उस पर अमल BackgroundTaskकरते हैं, एक थ्रेड पूल से एक थ्रेड को बाहर निकालने में बहुत समय बर्बाद होगा, एक डिफ़ॉल्ट नो-ऑप को निष्पादित करने के लिए doInBackground(), इससे पहले कि क्या मात्रा में ए post()। यह अब तक तीनों में से सबसे कम कुशल है। उपयोग करें AsyncTaskयदि आपके पास वास्तव में पृष्ठभूमि थ्रेड में काम करना है, न कि केवल उपयोग के लिए onPostExecute()


27
यह भी ध्यान दें कि AsyncTask.execute()आपको वैसे भी यूआई थ्रेड से कॉल करने की आवश्यकता होती है, जो कि बैकग्राउंड थ्रेड से यूआई थ्रेड पर बस चल रहे कोड के उपयोग के मामले में इस विकल्प को बेकार कर देता है जब तक कि आप अपने सभी बैकग्राउंड को काम में नहीं ले जाते हैं doInBackground()और AsyncTaskठीक से उपयोग नहीं करते हैं।
काबूको

@kabuko मैं कैसे जांच सकता हूं कि मैं AsyncTaskUI थ्रेड से कॉल कर रहा हूं ?
नील गालिसैक्रम

@NeilGaliaskarov यह एक ठोस विकल्प की तरह दिखता है: stackoverflow.com/a/7897562/1839500
डिक लुकास

1
@ नीलग्लासकेरोवboolean isUiThread = (Looper.getMainLooper().getThread() == Thread.currentThread());
प्रतिबंध-

1
@NeilGaliaskarov से अधिक संस्करणों के लिए या M उपयोग के बराबर हैLooper.getMainLooper().isCurrentThread
बालू संगम

252

मुझे एचपीपी टिप्पणी पसंद है , इसका उपयोग बिना किसी पैरामीटर के कहीं भी किया जा सकता है:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Log.d("UI thread", "I am the UI thread");
    }
});

2
यह कितना कारगर है? क्या यह अन्य विकल्पों के समान है?
इमैनुएलमेस

59

उपयोग करने का चौथा तरीका है Handler

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // Code here will run in UI thread
    }
});

56
आपको इससे सावधान रहना चाहिए। क्योंकि यदि आप एक गैर UI थ्रेड में एक हैंडलर बनाते हैं तो आप गैर यूआई थ्रेड को संदेश पोस्ट करेंगे। एक हैंडलर डिफ़ॉल्ट पोस्ट मैसेज को थ्रेड जहां यह बनाया जाता है।
लूजोप

108
मुख्य UI थ्रेड को निष्पादित करने के लिए new Handler(Looper.getMainLooper()).post(r), जो पसंदीदा तरीका है क्योंकि Looper.getMainLooper()मुख्य के लिए एक स्थिर कॉल करता है, जबकि गुंजाइश में postOnUiThread()एक उदाहरण होना चाहिए MainActivity
एचपीपी

1
@HPP मैं इस विधि को नहीं जानता था, जब आपके पास न ही कोई गतिविधि होगी और न ही कोई दृश्य होगा। बहुत अच्छा काम करता है! बहुत बहुत बहुत धन्यवाद!
१२:

@lujop वही onync के साथ मामला है। AsyncTask की कॉल बैक विधि।
श्रीकांत करुमनघाट

18

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

TextViewUpdater textViewUpdater = new TextViewUpdater();
Handler textViewUpdaterHandler = new Handler(Looper.getMainLooper());
private class TextViewUpdater implements Runnable{
    private String txt;
    @Override
    public void run() {
        searchResultTextView.setText(txt);
    }
    public void setText(String txt){
        this.txt = txt;
    }

}

इसे इस तरह से कहीं से भी इस्तेमाल किया जा सकता है:

textViewUpdater.setText("Hello");
        textViewUpdaterHandler.post(textViewUpdater);

7
जीसी और वस्तु निर्माण का उल्लेख करने के लिए +1। फिर भी, मैं जरूरी नहीं मानता The best solutions are always the ones that try to mitigate memory hog। इसके लिए कई अन्य मानदंड हैं best, और इसकी थोड़ी सी गंध है premature optimization। यही है, जब तक आप जानते हैं कि आप इसे पर्याप्त रूप से नहीं बुला रहे हैं, तब बनाई गई वस्तुओं की संख्या एक मुद्दा है (दस हजार अन्य तरीकों की तुलना में जिसमें आपका ऐप शायद कचरा पैदा कर रहा है।), क्या हो सकता bestहै कि सबसे सरल (आसान समझने के लिए) लिखें। ) कोड, और किसी अन्य कार्य के लिए आगे बढ़ें।
टूलमेकर

2
Btw, textViewUpdaterHandlerबेहतर तरह कुछ नामित किया जाएगा uiHandlerया mainHandler, क्योंकि यह मुख्य यूआई धागा के लिए किसी भी पद के लिए आम तौर पर उपयोगी है; यह आपके TextViewUpdater वर्ग से बिल्कुल भी जुड़ा हुआ नहीं है। मैं इसे उस कोड के बाकी हिस्सों से दूर ले जाऊंगा, और यह स्पष्ट कर दूंगा कि इसे कहीं और इस्तेमाल किया जा सकता है ... बाकी कोड संदिग्ध है, क्योंकि गतिशील रूप से एक वस्तु बनाने से बचने के लिए, आप तोड़ते हैं कि एक कॉल में क्या हो सकता है दो कदम setTextऔर post, जो एक लंबे समय तक रहने वाली वस्तु पर निर्भर करते हैं जो आप एक अस्थायी के रूप में उपयोग करते हैं। अनावश्यक जटिलता, और धागा-सुरक्षित नहीं। बनाए रखना आसान नहीं है।
टूलमेकरसैट

यदि आपके पास वास्तव में ऐसी स्थिति है, जहां इसे इतनी बार कहा जाता है कि यह कैशिंग के लायक है uiHandlerऔर textViewUpdaterफिर, public void setText(String txt, Handler uiHandler)विधि लाइन को बदलकर और जोड़कर अपनी कक्षा में सुधार करें uiHandler.post(this); तो कॉलर एक चरण में कर सकता है textViewUpdater.setText("Hello", uiHandler);:। फिर भविष्य में, यदि थ्रेड को सुरक्षित रखने की आवश्यकता होती है, तो विधि अपने बयानों को एक लॉक ऑन के अंदर लपेट सकती है uiHandler, और कॉलर अपरिवर्तित रहता है।
टूलमेकर

मुझे पूरा यकीन है कि आप केवल एक बार रननेबल चला सकते हैं। जो आपके विचार को बिल्कुल तोड़ देते हैं, जो कुल मिलाकर अच्छा है।
नटिव

@ नेटिव नोप, रननेबल को कई बार चलाया जा सकता है। एक धागा नहीं कर सकता।
Zbyszek

8

Android P के रूप में आप उपयोग कर सकते हैं getMainExecutor():

getMainExecutor().execute(new Runnable() {
  @Override public void run() {
    // Code will run on the main thread
  }
});

से Android डेवलपर डॉक्स :

एक एक्सेक्यूटर लौटाएं जो इस संदर्भ से जुड़े मुख्य थ्रेड पर संलग्न कार्यों को चलाएगा। यह आवेदन घटकों (गतिविधियों, सेवाओं, आदि) को कॉल भेजने के लिए उपयोग किया जाने वाला धागा है।

से CommonsBlog :

आप एक्सेक्यूटर पाने के लिए getMainExecutor () को Context पर कॉल कर सकते हैं जो मुख्य एप्लिकेशन थ्रेड पर अपनी नौकरियों को निष्पादित करेगा। इसे पूरा करने के अन्य तरीके हैं, लूपर और एक कस्टम एक्ज़ीक्यूटर कार्यान्वयन का उपयोग करते हैं, लेकिन यह सरल है।


7

यदि आपको Fragment में उपयोग करने की आवश्यकता है तो आपको उपयोग करना चाहिए

private Context context;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.context = context;
    }


    ((MainActivity)context).runOnUiThread(new Runnable() {
        public void run() {
            Log.d("UI thread", "I am the UI thread");
        }
    });

के बजाय

getActivity().runOnUiThread(new Runnable() {
    public void run() {
        Log.d("UI thread", "I am the UI thread");
    }
});

क्योंकि पेजर के टुकड़े जैसी कुछ स्थिति में अशक्त सूचक अपवाद होगा


1

हाय दोस्तों यह एक बुनियादी सवाल किसी भी दूर मैं बता रहा है

हैंडलर का उपयोग करें

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // Code here will run in UI thread
    }
});

क्या कोई कारण है कि आपने runOnUiThread पर सामान्य उद्देश्य हैंडलर का उपयोग करना चुना?
thePartyTurtle

यह दे देगा java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()अगर यह UI थ्रेड से नहीं कहा जाता है।
Roc Boronat
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.