অ্যান্ড্রয়েড বেসিক: ইউআই থ্রেডে চলমান কোড


450

ইউআই থ্রেডে চলমান কোডের দৃষ্টিতে, এর মধ্যে কোনও পার্থক্য রয়েছে:

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

আমার প্রশ্নটি স্পষ্ট করার জন্য: আমার ধারণা এই পরিষেবাগুলি কোনও পরিষেবা থ্রেড থেকে, সাধারণত শ্রোতা থেকে কল করা হয়েছিল। আমিও অনুমান করেছি যে অ্যাসিনটাস্কের ডইনব্যাকগ্রাউন্ড () ফাংশন বা প্রথম দুটি স্নিপেটের আগে ডাকা একটি নতুন টাস্ক (...) এ কাজ করার জন্য একটি ভারী কাজ রয়েছে। যাইহোক, AsyncTask এর onPostExecute () ইভেন্টের সারির শেষে রাখা হচ্ছে, তাই না?
লুকি

উত্তর:


288

এগুলির কোনওটিই হুবহু এক নয়, যদিও তাদের সবার একই নেট ইফেক্ট থাকবে।

প্রথম এবং দ্বিতীয় মধ্যে পার্থক্য যে আপনি যদি হতে ঘটতে হয় উপর যখন কোড নির্বাহ প্রধান কর্মক্ষেত্র থ্রেড, প্রথম এক ( runOnUiThread()) চালানো হবে Runnableঅবিলম্বে। দ্বিতীয়টি ( post()) সর্বদা রাখেRunnable ইভেন্টের সারিটির শেষে , এমনকি আপনি ইতিমধ্যে মূল অ্যাপ্লিকেশন থ্রেডে থাকলেও।

তৃতীয়টি, আপনি ধরে নিচ্ছেন যে কোনও উদাহরণ তৈরি করুন এবং সম্পাদন করুন BackgroundTask, থ্রেড পুলের বাইরে একটি থ্রেড ধরতে অনেক সময় নষ্ট করবে doInBackground(), অবশেষে এটির পরিমাণের কি করার আগে একটি ডিফল্ট নো-ওপিকে চালিত করতে post()। এটি তিনজনের মধ্যে এখন পর্যন্ত সবচেয়ে কম দক্ষ। ব্যবহারের AsyncTaskযদি আপনি আসলে ব্যবহারের জন্য না শুধু একটি ব্যাকগ্রাউন্ড থ্রেড তো কাজই নেই onPostExecute()


27
এছাড়াও নোট করুন যে AsyncTask.execute()আপনাকে যেভাবেই ইউআই থ্রেড থেকে কল করা দরকার, যা ইউআই থ্রেডে কেবল চলমান কোড ব্যবহারের ক্ষেত্রে এই অপশনটিকে অকার্যকর করে তোলে যদি না আপনি আপনার সমস্ত পটভূমি কাজ না করে doInBackground()এবং AsyncTaskসঠিকভাবে ব্যবহার না করেন।
কাবুকো

@ কাবুকো কীভাবে আমি AsyncTaskইউআই থ্রেড থেকে কল করছি তা পরীক্ষা করতে পারি ?
নিল গালিয়াসকারভ

@NeilGaliaskarov একটি কঠিন বিকল্প মত এই দেখায়: stackoverflow.com/a/7897562/1839500
ডিক লুকাস

1
@ নীলগালিয়াসকারভboolean isUiThread = (Looper.getMainLooper().getThread() == Thread.currentThread());
নিষেধাজ্ঞাগুলিচালিত

1
@ নীলগালিয়াস্কারভ এম এর ব্যবহারের চেয়ে বড় বা তার সমান সংস্করণগুলির জন্যLooper.getMainLooper().isCurrentThread
বালু সংগীম

251

আমি এইচপিপির মন্তব্য থেকে একটি পছন্দ করি , এটি কোনও পরামিতি ছাড়াই যে কোনও জায়গায় ব্যবহার করা যেতে পারে:

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
আপনার এই বিষয়ে সতর্ক হওয়া উচিত। কারণ আপনি যদি অ ইউআই থ্রেডে হ্যান্ডলার তৈরি করেন তবে আপনি নন ইউআই থ্রেডে বার্তা পোস্ট করবেন। থ্রেডে এটি তৈরি করা হয়েছে সেখানে ডিফল্ট পোস্ট বার্তা দ্বারা একটি হ্যান্ডলার।
লুজপ

107
প্রধান UI 'তে থ্রেড না সঞ্চালনের জন্য new Handler(Looper.getMainLooper()).post(r), যা পছন্দের পদ্ধতিতে হয় Looper.getMainLooper()তোলে প্রধান করার জন্য একটি স্ট্যাটিক কল, যেহেতু postOnUiThread()এর একটি দৃষ্টান্ত থাকা আবশ্যক MainActivityসুযোগ।
এইচপিপি

1
@ এইচপিপি আমি এই পদ্ধতিটি জানতাম না, যখন আপনার অ্যাক্টিভিটি না থাকে বা না দেখায় এমন দুর্দান্ত উপায় হবে। দুর্দান্ত কাজ! আপনাকে অনেক ধন্যবাদ!
সালফকেইন

@ লুজপ সেম হ'ল অ্যাসিঙ্কটাস্কের অনপ্রাইসেক্সট কল ব্যাক পদ্ধতির ক্ষেত্রে।
শ্রীকান্ত করুণাঘাট

18

পাম্বারের উত্তর গ্রহণযোগ্য, তবে আমি বারবার নতুন অবজেক্ট তৈরি করার পক্ষে বড় ফ্যান নই। সর্বদা সেরা সমাধানগুলি হ'ল মেমরি হগ প্রশমিত করার চেষ্টা করে। হ্যাঁ, অটো আবর্জনা সংগ্রহ রয়েছে তবে একটি মোবাইল ডিভাইসে মেমরি সংরক্ষণ সেরা অনুশীলনের সীমার মধ্যে পড়ে। নীচের কোডটি একটি পরিষেবাতে একটি টেক্সটভিউ আপডেট করে।

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
বিটিডাব্লু, এর textViewUpdaterHandlerমতো আরও ভাল নামকরণ করা হবে uiHandlerবা mainHandler, যেহেতু এটি সাধারণত কোনও ইউআই থ্রেডে কোনও পোস্টের জন্য কার্যকর; এটি আপনার টেক্সটভিউআপডেটার ক্লাসে মোটেই জড়িত নয়। আমি এটিকে সেই কোডের বাকী অংশ থেকে সরিয়ে নিয়ে গিয়ে পরিষ্কার করে দেব যে এটি অন্য কোথাও ব্যবহার করা যেতে পারে ... বাকী কোডটি সন্দেহজনক, কারণ একটি বস্তুকে গতিশীলভাবে তৈরি করা এড়ানোর জন্য, আপনি যে কোনও একক কল হতে পারে তা ভেঙে ফেলুন দুটি পদক্ষেপ setTextএবং post, যা আপনি একটি অস্থায়ী হিসাবে ব্যবহার করেন যা দীর্ঘকালীন অবজেক্টের উপর নির্ভর করে। অপ্রয়োজনীয় জটিলতা, এবং থ্রেড-নিরাপদ নয়। বজায় রাখা সহজ নয়।
টুলমেকারস্টেভ

আপনি যদি সত্যিই একটি অবস্থা যেখানে এই তাই অনেক বার বলা হয় যে এটা মূল্য ক্যাশে আছে uiHandlerএবং textViewUpdaterতারপর, পরিবর্তিত করে আপনার বর্গ উন্নত public void setText(String txt, Handler uiHandler)এবং পদ্ধতি লাইন যোগ uiHandler.post(this); তখন আহ্বানকারী এক ধাপে করতে পারেন: textViewUpdater.setText("Hello", uiHandler);। তারপরে ভবিষ্যতে, যদি থ্রেড নিরাপদ হওয়া দরকার হয় তবে পদ্ধতিটি তার স্টেটমেন্টগুলিকে একটি লক uiHandlerঅনের মধ্যে গুটিয়ে রাখতে পারে এবং কলার অপরিবর্তিত থাকে।
টুলমেকারস্টেভ

আমি নিশ্চিত যে আপনি একবার চালানো কেবল চালাতে পারবেন। যা একেবারে আপনার ধারণাটি ভঙ্গ করে, যা সামগ্রিকভাবে দুর্দান্ত।
নাটিভ

@ নাটিভ নোপ, চলমানযোগ্য একাধিকবার চালানো যেতে পারে। একটি থ্রেড পারে না।
জেডবাইজেক

8

অ্যান্ড্রয়েড পি হিসাবে আপনি ব্যবহার করতে পারেন getMainExecutor():

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

থেকে Android বিকাশকারী ডক্স :

একজন নির্বাহককে ফিরিয়ে দিন যা এই প্রসঙ্গে যুক্ত মূল থ্রেডে চালিত কাজগুলি চালাবে। এটি অ্যাপ্লিকেশন উপাদানগুলিতে (ক্রিয়াকলাপ, পরিষেবাদি, ইত্যাদি) কল প্রেরণের জন্য ব্যবহৃত থ্রেড।

কমন্সব্লগ থেকে :

একটি এক্সিকিউটার পেতে প্রসঙ্গে আপনি getMainExecutor () কে কল করতে পারেন যা মূল অ্যাপ্লিকেশন থ্রেডে এর কাজগুলি কার্যকর করবে ute এটি সম্পাদন করার অন্যান্য উপায় রয়েছে, লুপার এবং একটি কাস্টম এক্সিকিউটার বাস্তবায়ন ব্যবহার করে তবে এটি সহজ।


7

আপনার যদি খণ্ডে ব্যবহারের প্রয়োজন হয় তবে আপনার ব্যবহার করা উচিত

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

রানঅনউথ্রিস্টের ওপরে সাধারণ উদ্দেশ্য হ্যান্ডলারটি ব্যবহার করার জন্য কেন কোনও কারণ আছে?
ThePartyTurtle

এটি java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()ইউআই থ্রেড থেকে কল না করা হলে এটি দেবে ।
রক বোরোনাত
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.