Post updated on 2nd August, 2017 at 06:58 am
অ্যান্ড্রয়েড অ্যাপ ডেভেলপমেন্টের সময় কখনো কখনো দরকার হতে পারে Count Down Timer এর ফিচারটি। কোন রকম ঝামেলা ছাড়াই কয়েক লাইনের কোডের মাধ্যমে এই টাইমারটি বানানো যায়। Thread/Runnable ব্যবহার না করে এই পোস্টে দেখাবো Android এর CountDownTimer ক্লাসের মাধ্যমে টাইমার বানানোর প্রকৃয়া।
CountDownTimer Abstract Class
CountDownTimer একটি অ্যাবস্ট্রাক্ট ক্লাস। এই ক্লাসটি inherit করা হয়েছে Object ক্লাস থেকে। আমাদের উদ্দেশ্য হচ্ছে ১ মিনিট সময়ের জন্য একটা কাউন্ট ডাউন টাইমার বানানো। স্ক্রিনে থাকবে টাইমার (TextView) ও Start, Cancel বাটন।
জাভা ক্লাসে CountDownTimer ক্লাসের একটা অবজেক্ট initiate করছি এই ভাবে:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); countDownTextView = (TextView) findViewById(R.id.countDownTimerTextView); int minutes = 1; int milliseconds = minutes * 60 * 1000; countDownTimer = new CountDownTimer(milliseconds, 1000) { @Override public void onTick(long millisUntilFinished) { countDownTextView.setText(String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(millisUntilFinished), TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished), TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished)))); } @Override public void onFinish() { countDownTextView.setText("Time Up!"); } }; }
Constructor এ আর্গুমেন্ট হিসাবে পাস করছি মোট সময় (যত সময় ধরে টাইমার চলবে) ও কত সময় পরপর টাইমারের ডিজিট চেঞ্জ হবে সেটা মিলিসেকেন্ড এককে। 1000 মিলিসেকেন্ডে এক সেকেন্ড। দ্বিতীয় আর্গুমেন্টে পাঠানো হচ্ছে 1000 মিলিসেকেন্ড, অর্থাৎ প্রতি ১ সেকেন্ড পরপর আমাদের টাইমারের ডেটা চেঞ্জ হবে।
এতক্ষনে হয়ত মনে প্রশ্ন চলে এসেছে যে “abstract class এর তো কোন অবজেক্ট বানানো যায় না। তাহলে এখানে অবজেক্ট বানানোর চেষ্টা নিচ্ছি কিভাবে?”
প্রশ্নটা ভাল। আসলে আমরা এখানে abstract class এর object বানাচ্ছি না। CountDownTimer countDownTimer = new CountDownTimer(milliseconds, 1000) {…} এর মাধ্যমে জাস্ট অবজেক্ট ক্রিয়েট হচ্ছে না। অবজেক্ট বানানোর সময় কিন্তু আমরা {…} এই অংশটুকু লিখি না।
তাহলে অ্যাবস্ট্রাক্ট ক্লাস কিভাবে ব্যবহার করা যায়? এই ক্লাসকে অন্য কোন ক্লাস inherit করে ব্যবহার করতে পারে। যদি abstract class এর মধ্যে এক বা একাধিক abstract method থাকে তাহলে ঐ মেথডগুলোকে Override করতে হবে। লক্ষ্য করে দেখুন, {…} এর ভিতরে আমি ২টি মেথড Override করেছি। onTick() এর কাজ হচ্ছে নির্দিষ্ট সময় পরপর টাইমারের মান আপডেট করা আর onFinish() এর কাজ হচ্ছে সময় শেষ হলে কী ঘটবে সেটা ম্যানেজ করা।
তো উপরের আলোচনায় দেখলাম abstract class এর সরাসরি object বানানো যায় না, বরং অন্য একটা ক্লাসের মধ্যে inherit করতে হয়। তাহলে আমরা এই ইনহেরিটের কাজটা করলাম কোথায়?
আপাত দৃষ্টিতে মনে হচ্ছে যে সরাসরি countDownTimer টি বানানো হয়েছে CountDownTimer ক্লাসের constructor এর মাধ্যমে। আসলে ঘটনা সেরকম নয়। new CountDownTimer(milliseconds, 1000) {…} এর মাধ্যমে মূলত CountDownTimer এর একটা anonymous subclass বানানো হয়েছে। এরপর সেই সাব-ক্লাসের একটা অবজেক্টকে রেফারেন্স করছে countDownTimer অবজেক্টটি। অর্থাৎ,
countDownTimer সত্যিকারার্থে CountDownTimer ক্লাসের অবজেক্ট নয়। এটি CountDownTimer abstract class এর একটা anonymous subclass এর object.
এভাবে anonymous class ব্যবহার না করে আলাদা ক্লাস বানিয়েও কাজটা করা যায়। ক্লাসটা হতে পারে এমন:
class MyTimerClass extends CountDownTimer{ @Override public void onTick(long millisUntilFinished){…} @Override public void onFinish(){...} }
এতক্ষন অবজেক্টটা ঠিকঠাক মত বানালাম। এখন টাইমারটা চালু বন্ধের কাজ করব বাটন ক্লিকের ইভেন্টে:
public void buttonAction(View view) { if(view.getId() == R.id.startButton) countDownTimer.start(); else if(view.getId() == R.id.cancelButton) countDownTimer.cancel(); }
সতর্কতা:
Activity তে এই পর্যন্ত করলেই দেখেছি ঠিকঠাক কাজ করে। কিন্তু Fragment এ কাজ করার সময় দেখেছি টাইমার চলা অবস্থায় Fragment-টি ক্লোজ করে দিলে বা ঐ fragment থেকে অন্য ফ্রেগমেন্টে গেলে App crash করে। কারণ তখনো onTick() মেথড textView.setText() করার চেষ্টা করে। তাই fragment এ ব্যবহার করার সময় onStop() স্টেটে টাইমারের countDownTimer.cancel() মেথডটি কল করে নিতে হবে। যেন destroyed fragment এ setText() করার চেষ্টা না করতে পারে।
পুরো প্রজেক্টটি পাওয়া যাবে আমার গিটহাব রিপোজিটরিতে।
পোস্টটি পড়ার জন্য ধন্যবাদ। কোন অসঙ্গতি চোখে পড়লে বা কোন মতামত থাকলে কমেন্ট করে জানাতে পারেন।