আমি এর জন্য অফিসিয়াল অ্যানড্রইড ডকুমেন্টেশন / গাইড পরীক্ষা করেছি Looper
, Handler
এবং MessageQueue
। তবে আমি তা পেলাম না। আমি অ্যান্ড্রয়েডে নতুন এবং এই ধারণাগুলি নিয়ে খুব বিভ্রান্ত হয়ে পড়েছি।
উত্তর:
এ Looper
হ'ল একটি বার্তা হ্যান্ডলিং লুপ: এটি একটি থেকে আইটেমগুলি পড়ে এবং প্রক্রিয়া করে MessageQueue
। Looper
শ্রেণী সাধারণত একটি সাথে ব্যবহার করা হয় HandlerThread
(একটি উপশ্রেণী Thread
)।
এ Handler
হ'ল একটি ইউটিলিটি ক্লাস যা থ্রেডে Looper
বার্তা এবং Runnable
অবজেক্ট পোস্ট করে —মেনলি সাথে ইন্টারঅ্যাক্ট করতে সহায়তা করে MessageQueue
। যখন একটি Handler
তৈরি করা হয়, এটি নির্দিষ্ট Looper
(এবং সম্পর্কিত থ্রেড এবং বার্তা সারি) এর সাথে আবদ্ধ ।
সাধারণ ব্যবহারে আপনি একটি তৈরি এবং শুরু করেন HandlerThread
, তারপরে এমন কোনও Handler
বস্তু (বা অবজেক্টস) তৈরি করুন যার মাধ্যমে অন্যান্য থ্রেডগুলি HandlerThread
উদাহরণের সাথে ইন্টারঅ্যাক্ট করতে পারে । Handler
যখন চলমান তৈরি করতে হবে HandlerThread
, একবার নির্মিত সেখানে কি থ্রেড ব্যবহার করতে পারেন কোন সীমাবদ্ধতা নেই যদিও Handler
এর পূর্বপরিকল্পনা পদ্ধতি ( post(Runnable)
, ইত্যাদি)
আপনার অ্যাপ্লিকেশন উদাহরণটি তৈরি হওয়ার আগে একটি অ্যান্ড্রয়েড অ্যাপ্লিকেশনে মূল থ্রেড (ওরফে ইউআই থ্রেড) হ্যান্ডলার থ্রেড হিসাবে সেট আপ করা হয়।
বর্গ ডক্স ছাড়াও সেখানে এই সব একটি চমৎকার আলোচনা করেন এখানে ।
পিএস উপরে উল্লিখিত সমস্ত ক্লাস প্যাকেজে রয়েছে android.os
।
MessageQueue
রাষ্ট্র করে একটি MessageQueue
একটি হল " নিম্ন স্তরের বর্গ বার্তা তালিকা অধিষ্ঠিত একটি দ্বারা প্রেষিত করা Looper
। "
এটি সর্বজনবিদিত যে অ্যান্ড্রয়েডের মূল থ্রেড ছাড়া অন্য থ্রেড থেকে সরাসরি ইউআই উপাদান আপডেট করা অবৈধ । এই অ্যান্ড্রয়েড ডকুমেন্টটি ( ইউআই থ্রেডে ব্যয়বহুল অপারেশন পরিচালনা করা ) অনুসরণ করার পদক্ষেপগুলির পরামর্শ দেয় যদি আমাদের কিছু ব্যয়বহুল কাজ করার জন্য আলাদা থ্রেড শুরু করতে হয় এবং ইউআই সম্পন্ন হওয়ার পরে আপডেট করতে হয়। মূল থ্রেডের সাথে যুক্ত একটি হ্যান্ডলার অবজেক্ট তৈরি করা এবং উপযুক্ত সময়ে এটিতে একটি রান্নেবল পোস্ট করা ধারণা । এই সময় আহবান করা হবে মূল থ্রেড । এই প্রক্রিয়াটি লুপার এবং হ্যান্ডলারের ক্লাসগুলির সাথে প্রয়োগ করা হয় ।Runnable
Looper
বর্গ একটি বজায় রাখে MessageQueue , যা একটি তালিকা রয়েছে বার্তা । লুপারের একটি গুরুত্বপূর্ণ চরিত্রটি এটি থ্রেডের সাথে সম্পর্কিত যা এটি Looper
তৈরি করা হয় । এই সমিতিটি চিরকালের জন্য রাখা হয় এবং ভাঙা বা পরিবর্তন করা যায় না। আরও মনে রাখবেন যে একটি থ্রেড একের বেশি সংযুক্ত হতে পারে নাLooper
। এই সংস্থার গ্যারান্টি হিসাবে, Looper
থ্রেড-লোকাল স্টোরেজে সঞ্চয় করা হয় এবং এটি সরাসরি এটির নির্মাণকারীর মাধ্যমে তৈরি করা যায় না। এটি তৈরির একমাত্র উপায় হ'ল প্রস্তুত স্থির পদ্ধতিটি কল করা Looper
। পদ্ধতি প্রস্তুত প্রথম থ্রেডলোকাল পরীক্ষা করেইতিমধ্যে থ্রেডের সাথে কোনও লুপার যুক্ত নেই তা নিশ্চিত করার জন্য বর্তমান থ্রেডের। পরীক্ষার পরে, একটি নতুন Looper
তৈরি করা হয় এবং এতে সংরক্ষণ করা হয় ThreadLocal
। তৈরি করার পরে Looper
, আমরা নতুন বার্তাগুলির জন্য এটি পরীক্ষা করতে লুপ পদ্ধতিটি কল করতে পারি এবং Handler
সেগুলি মোকাবেলা করতে পারি।
নামটি ইঙ্গিত করে, Handler
ক্লাসটি প্রধান থ্রেডের বার্তাগুলি পরিচালনা করার (যোগ করা, অপসারণ, প্রেরণ) জন্য প্রধানত দায়ী MessageQueue
। একটি Handler
উদাহরণও একটি থ্রেডের সাথে আবদ্ধ। হ্যান্ডলার এবং থ্রেড মধ্যে বাঁধাই মাধ্যমে অর্জিত হয় Looper
এবং MessageQueue
। একজন Handler
হয় সবসময় আবদ্ধ একটি Looper
, এবং পরবর্তীকালে আবদ্ধ যুক্ত থ্রেড সঙ্গে Looper
। বিপরীতে Looper
, একাধিক হ্যান্ডলার দৃষ্টান্ত একই থ্রেডের সাথে আবদ্ধ হতে পারে। যখনই আমরা পোস্ট বা যেকোন পদ্ধতিতে একসাথে কল করি তখন সম্পর্কিতটিতে Handler
একটি নতুন বার্তা যুক্ত হয় MessageQueue
। বার্তাটির লক্ষ্য ক্ষেত্রটি বর্তমান Handler
উদাহরণে সেট করা আছে । যখনLooper
এই বার্তাটি পেয়েছে, এটি বার্তার টার্গেট ফিল্ডে প্রেরণ -বার্তা প্রেরণ করে, যাতে বার্তাটি হ্যান্ডলারের উদাহরণটিতে ফিরে আসে তবে সঠিক থ্রেডে। মধ্যে সম্পর্ক Looper
, Handler
এবং MessageQueue
নিচে দেখানো হল:
লুপার দিয়ে শুরু করা যাক। লুপার কী তা আপনি যখন বুঝতে পারবেন তখন লুপার, হ্যান্ডলার এবং মেসেজকিউয়ের মধ্যে সম্পর্কটি আরও সহজেই বুঝতে পারবেন। এছাড়াও আপনি জিওআই কাঠামোর প্রসঙ্গে লুপারটি কী তা আরও ভালভাবে বুঝতে পারবেন। লুপার 2 টি জিনিস করা হয়।
1) লুপার একটি সাধারণ থ্রেডকে রূপান্তরিত করে , যা এর run()
পদ্ধতিটি ফিরে আসার সাথে সাথে শেষ হয়, অ্যান্ড্রয়েড অ্যাপ চলমান অবধি অবিচ্ছিন্নভাবে চলতে থাকে , যা জিইউআই কাঠামোর মধ্যে প্রয়োজন (প্রযুক্তিগতভাবে, run()
পদ্ধতিটি ফিরে আসার পরে এটি বন্ধ হয়ে যায় But তবে আমি কী বলতে চাইছিলাম তা স্পষ্ট করে বলি, নিচে).
২) লুপার একটি সারি সরবরাহ করে যেখানে কাজগুলি করা হবে এবং জিইউআই কাঠামোর ক্ষেত্রেও এটি প্রয়োজনীয়।
আপনি যেমন জানেন যে কোনও অ্যাপ্লিকেশন চালু হওয়ার সময়, সিস্টেমটি অ্যাপ্লিকেশনটির জন্য মৃত্যুর জন্য একটি থ্রেড তৈরি করে, যাকে "প্রধান" বলা হয় এবং অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলি সাধারণত একটি মূল থ্রেডে ডিফল্টভাবে "মূল থ্রেড" তে পুরোপুরি সঞ্চালিত হয়। তবে মূল থ্রেড কিছু গোপন নয়, বিশেষ থ্রেড । এটি কেবলমাত্র একটি সাধারণ থ্রেড যা আপনি new Thread()
কোড দিয়েও তৈরি করতে পারেন , যার অর্থ এটির run()
পদ্ধতিটি ফিরে আসলে এটি বন্ধ হয়ে যায় ! নীচের উদাহরণ সম্পর্কে চিন্তা করুন।
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();
}
}
এখন, আসুন এই সহজ নীতিটি অ্যান্ড্রয়েড অ্যাপে প্রয়োগ করুন apply কোনও অ্যান্ড্রয়েড অ্যাপ্লিকেশন যদি কোনও থ্রেডে চালিত হয় তবে কী হবে? "মূল" বা "ইউআই" বা যা প্রয়োগ প্রয়োগ শুরু করে এবং সমস্ত ইউআই আঁকতে একটি থ্রেড। সুতরাং, প্রথম পর্দা ব্যবহারকারীদের প্রদর্শিত হয়। এখন কি? মূল থ্রেড কি শেষ? না, এটা করা উচিত নয়। ব্যবহারকারীদের কিছু না করা পর্যন্ত এটি অপেক্ষা করা উচিত, তাই না? তবে কীভাবে আমরা এই আচরণ অর্জন করতে পারি? ঠিক আছে, আমরা চেষ্টা করতে পারি Object.wait()
বা এর সাথেThread.sleep()
। উদাহরণস্বরূপ, মূল থ্রেডটি প্রথম স্ক্রিন প্রদর্শন করার জন্য প্রাথমিক কাজটি শেষ করে এবং ঘুমায়। এটি জাগ্রত হয়, যার অর্থ বাধাগ্রস্ত হয়, যখন করার কোনও নতুন কাজ আনতে হবে। এখন পর্যন্ত এত ভাল, তবে এই মুহুর্তে আমাদের একাধিক কাজ ধরে রাখতে একটি সারির মতো ডেটা কাঠামো দরকার। কোনও ব্যবহারকারী যখন সিরিয়ালি পর্দা স্পর্শ করে তখন কোনও কেস সম্পর্কে চিন্তা করুন এবং কোনও কাজ শেষ হতে আরও বেশি সময় নেয়। সুতরাং, ফার্স্ট-ইন-ফার্স্ট-আউট পদ্ধতিতে কাজগুলি ধরে রাখতে আমাদের একটি ডেটা কাঠামো থাকা দরকার। এছাড়াও, আপনি কল্পনাও করতে পারেন, আন্তঃ-বিঘ্নিত ব্যবহার করে সর্বদা চলমান-প্রক্রিয়া-কাজ-কখন-আগত থ্রেড কার্যকর করা সহজ নয় এবং জটিল এবং প্রায়শই অবিস্মরণীয় কোডের দিকে নিয়ে যায়। আমরা বরং এই ধরনের কাজের জন্য একটি নতুন প্রক্রিয়া তৈরি চাই, এবং যে কি Looper সব হয় । Looper বর্গ অফিসিয়াল ডকুমেন্টবলে, "ডিফল্টভাবে থ্রেডগুলির সাথে একটি বার্তা লুপ থাকে না" এবং লুপার একটি ক্লাস "থ্রেডের জন্য বার্তা লুপ চালানোর জন্য ব্যবহৃত হয়"। এর অর্থ কী তা আপনি বুঝতে পারবেন।
হ্যান্ডলার এবং বার্তা কিউতে সরানো যাক। প্রথমত, বার্তা কিউ হ'ল আমি উপরে বর্ণিত সারি is এটি একটি লুপারের অভ্যন্তরে থাকে এবং এটিই। আপনি এটি লুপার শ্রেণীর উত্স কোড দিয়ে পরীক্ষা করতে পারেন । লুপার শ্রেণিতে মেসেজকিউয়ের একটি সদস্য ভেরিয়েবল রয়েছে।
তাহলে, হ্যান্ডলার কী? যদি একটি সারি থাকে, তবে এমন একটি পদ্ধতি থাকা উচিত যা আমাদের সারিটিতে একটি নতুন টাস্ক তৈরি করতে সক্ষম করবে, তাই না? হ্যান্ডলার এটিই করেন। আমরা বিভিন্ন post(Runnable r)
পদ্ধতি ব্যবহার করে একটি নতুন টাস্ককে একটি কাতারে (মেসেজকিউ) তৈরি করতে পারি । এটাই. এটি লুপার, হ্যান্ডলার এবং মেসেজকিউ সম্পর্কে।
আমার শেষ কথাটি, সুতরাং মূলত লুপার একটি শ্রেণি যা জিইউআই কাঠামোর মধ্যে ঘটে এমন একটি সমস্যা সমাধানের জন্য তৈরি। তবে এই ধরণের চাহিদা অন্যান্য পরিস্থিতিতেও ঘটতে পারে। প্রকৃতপক্ষে এটি মাল্টি থ্রেড অ্যাপ্লিকেশনগুলির জন্য একটি সুন্দর বিখ্যাত প্যাটার্ন এবং ডগ লি দ্বারা "জাভাতে সমবর্তী প্রোগ্রামিং" এ আপনি এটি সম্পর্কে আরও শিখতে পারেন (বিশেষত, ৪.১.৪ অধ্যায়ের "কর্মী থ্রেডস সহায়ক হবে)। এছাড়াও, আপনি কল্পনা করতে পারেন এই ধরণের প্রক্রিয়াটি অ্যান্ড্রয়েড কাঠামোর ক্ষেত্রে অনন্য নয়, তবে সমস্ত জিইউআই ফ্রেমওয়ার্কগুলির সাথে এর কিছুটা মিল প্রয়োজন হতে পারে। আপনি জাভা সুইং ফ্রেমওয়ার্কে প্রায় একই পদ্ধতি আবিষ্কার করতে পারেন।
MessageQueue
: এটি একটি নিম্ন-স্তরের শ্রেণী যা দ্বারা প্রেরণ করা বার্তাগুলির তালিকা ধারণ করে Looper
। বার্তাগুলি সরাসরি একটিতে যুক্ত করা হয় না MessageQueue
, বরং এর Handler
সাথে যুক্ত বস্তুর মাধ্যমে Looper
[[ 3 ]
Looper
: এটি MessageQueue
বার্তাগুলি প্রেরণের জন্য লুপ করে । সারিটি পরিচালনা করার আসল কাজটি সেই Handler
বার্তা দ্বারা পরিচালিত হয় যা বার্তা কাতারে বার্তা পরিচালনা (যুক্ত, অপসারণ, প্রেরণ) জন্য দায়বদ্ধ [[ ২ ]
Handler
: এটি আপনাকে কোনও থ্রেডের সাথে যুক্ত Message
এবং প্রেরণ এবং প্রসেসের অনুমতি দেয় । প্রতিটি হ্যান্ডলারের উদাহরণটি একক থ্রেড এবং সেই থ্রেডের বার্তার সারিটির সাথে সম্পর্কিত [[ 4 ]Runnable
MessageQueue
আপনি যখন একটি নতুন তৈরি করেন Handler
, এটি যে থ্রেডটি তৈরি করছে তার থ্রেড / বার্তা সারিতে আবদ্ধ - সেই দিক থেকে এটি বার্তাগুলি এবং রানবেলগুলি সেই বার্তার কাতারে পৌঁছে দেবে এবং বার্তা সারি থেকে বেরিয়ে আসার সাথে সাথে তাদের সম্পাদন করবে ।
দয়া করে, আরও ভাল বোঝার জন্য নীচের চিত্রটি দেখুন [ 2 ]।
@ K_Anas দ্বারা উত্তরটি প্রসারিত করা, উদাহরণ সহ যেমন এটি বলা হয়েছে
এটি সর্বজনবিদিত যে অ্যান্ড্রয়েডের মূল থ্রেড ছাড়া অন্য থ্রেড থেকে সরাসরি ইউআই উপাদান আপডেট করা অবৈধ।
উদাহরণস্বরূপ যদি আপনি থ্রেড ব্যবহার করে ইউআই আপডেট করার চেষ্টা করেন।
int count = 0;
new Thread(new Runnable(){
@Override
public void run() {
try {
while(true) {
sleep(1000);
count++;
textView.setText(String.valueOf(count));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
).start();
আপনার অ্যাপ্লিকেশন ব্যতিক্রম সহ ক্রাশ হবে।
android.view.ViewRoot $ CalledFromWrongThreadException: কেবলমাত্র মূল থ্রেড যা একটি ভিউ হায়ারার্কি তৈরি করেছে কেবল তার দর্শনগুলিকে স্পর্শ করতে পারে।
অন্য কথায় আপনি ব্যবহার করতে হবে Handler
যা রেফারেন্স রাখে MainLooper
অর্থাত Main Thread
বা UI Thread
এবং কাজের পাস Runnable
।
Handler handler = new Handler(getApplicationContext().getMainLooper);
int count = 0;
new Thread(new Runnable(){
@Override
public void run() {
try {
while(true) {
sleep(1000);
count++;
handler.post(new Runnable() {
@Override
public void run() {
textView.setText(String.valueOf(count));
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
).start() ;