অনেক অ্যাপের শুরুতেই একটা Splash Screen দেখানো হয়। আমরা যখন অ্যান্ড্রয়েড অ্যাপ ডেভেলপমেন্ট শেখা শুরু করি তখন স্প্ল্যাশ স্ক্রিন ইমপ্লিমেন্ট করা একটা এক্সাইটিং কাজ মনে হয়। অন্তত আমার ক্ষেত্রে হয়েছিল। স্প্যাশ স্ক্রিন শো করা শেখানোর জন্য বেশির ভাগ ট্রেইনিং বা টিউটোরিয়ালে সাধারণত Thread ব্যবহার করা হয়। জাভা থ্রেডের মাধ্যমে ২/৩ সেকেন্ড সময় sleep করে রাখা হয় বা এক্সিকিউশন বন্ধ রাখা হয়। এই নির্দিষ্ট সময় (২/৩ সেকেন্ড) পর MainActivity বা অন্য কোনো activity চালু করা হয়। এটা ইম্প্লিমেন্ট করা খুব সহজ। গুগল করলেই এর রেডি কোড পাওয়া যায়। Splash Activity এর onCreate() মেথডে এই কোড কপি-পেস্ট করলেই কাজ হয়। অনেক পরে জেনেছি এটা আসলে স্প্ল্যাশ স্ক্রিন দেখানোর সঠিক পদ্ধতি নয়। সঠিক ও বেঠিক উভয় পদ্ধতি নিয়ে আলোচনা করা হবে এই লেখায়।
Problem
App এর শুরুতে একটা Splash screen দেখাতে হবে। এই স্ক্রিনের মাঝে অ্যাপের লোগো দেখাতে হবে। বাকি ব্যাকগ্রাউন্ডে একটা কালার দেখাতে হবে। আপাতত কালার হিসাবে সেট করা যেতে পারে purple color. Splash screen দেখানোর পরে MainActivity স্টার্ট করতে হবে। MainActivity এর মাঝে Hello world! টেক্সট লেখা থাকবে। MainActivity তে থাকা অবস্থায় সেটের ব্যাক বাটন ক্লিক করলে অ্যাপ ক্লোজ হয়ে যাবে (শুরুতে শো করা স্প্যাশ স্ক্রিন আবার শো করবে না)।
Solution: Android Splash Screen Implementation
অন্যান্য প্রবলেম সলভিংয়ের মত এই প্রবলেমটাও কয়েক ভাবে সলভ করা যায়। প্রবলেমের ধরণ দেখে আমরা সিদ্ধান্ত নিই কোন ওয়েতে সলভ করব। নিচে Android Splash Screen শো করানোর তিনটা implementation দেখানো হলো।
এটা আমাদের সবার পরিচিত পদ্ধতিতে স্প্যাশ স্ক্রিন ইমপ্লিমেন্টেশন। এই পদ্ধতিতে SplashScreenActivity এর onCreate() মেথডের ভিতর একটা থ্রেডের মাধ্যমে স্প্ল্যাশ স্ক্রিন শো করানো হয়।
![Android Splash Screen Implementation in Best way](https://i0.wp.com/hellohasan.com/wp-content/uploads/2018/07/01.Android-Splash-Screenworst-implementation.gif?resize=268%2C476&ssl=1)
উপরের আউটপুট আনার জন্য আমরা নিচের কোডটা লিখতে পারি। আর নিচের কোডটা কমবেশি আমাদের সকলেরই পরিচিত। এখানে onCreate() এর ভিতরে একটা থ্রেডের মাধ্যমে পরের activity-তে যাওয়ার কাজটাকে ৩ সেকেন্ড delay করানো হচ্ছে। Delayed time এর পর MainActivity কল করা হয়েছে।
public class SplashScreenActivity extends AppCompatActivity { private static int SPLASH_TIME_OUT = 3000; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash_screen); new Handler().postDelayed(new Runnable() { @Override public void run() { // This method will be executed once the timer is over // Start your app main activity Intent i = new Intent(SplashScreenActivity.this, MainActivity.class); startActivity(i); // close this activity finish(); } }, SPLASH_TIME_OUT); } }
উপরের GIF image-টা একটু খেয়াল করলে দেখা যাবে অ্যাপটা রান করার পর একটা সাদা স্ক্রিন দেখা যাচ্ছে। এরপর স্প্ল্যাশ স্ক্রিন দেখানো হচ্ছে। এরপর ওপেন হচ্ছে MainActivity. স্প্ল্যাশ স্ক্রিন আর মেইন অ্যাক্টিভিটি আমাদের expected output. কিন্তু অ্যাপ রান হবার পর সাদা স্ক্রিনটা কোথা থেকে আসছে? কেনই বা এটা শো হচ্ছে? আমরা তো এমন কোনো সাদা স্ক্রিন শো করানোর জন্য কোড উপরের code block এ লিখি নাই! তাহলে কোথা থেকে এই সাদা স্ক্রিনটা আসলো?
Android blank screen problem before launcher activity
একটা অ্যাপ যখন প্রথমবারের মত রান হয় অথবা রিসেন্ট ইউজ করা অ্যাপের লিস্ট ক্লিন করার পর যখন কোনো অ্যাপ নতুন করে রান করা হয় তখন cold boot এর মাধ্যমে অ্যাপটা রান হয়। এ সময় অ্যাপ রান হয়ে ইউজ্যাবল স্টেটে আসতে খানিকটা সময় নিয়ে থাকে। ডিভাইসের কনফিগারেশন ভাল হলে এই কোল্ড বুট টাইম কম হতে পারে।
অ্যাপ launch করার পর থেকে SplashScreenActivity এর onCreate() মেথড কল হবার মাঝে ২-৩ সেকেন্ড সময় লাগতে পারে। এসময় ডিফল্ট ব্যাকগ্রাউন্ড হিসাবে সাদা একটা স্ক্রিন শো হয়ে থাকে। এরপর যখন onCreate() কল হয় তখন আমাদের ডিজাইন করা UI তিন সেকেন্ডের জন্য শো করানো হয়। তিন সেকেন্ড পর MainActivity-কে স্টার্ট করা হয় এবং SplashScreenActivity-কে finish করা হয়।
তাহলে এই blank screen যেন শো না করে তার সলিউশন কী? সলিউশনের জন্য দেখতে হবে পরের দুটি implementation.
2. Android Splash Screen Implementation – Good way (sometimes best way)
প্রথম পদ্ধতির সাথে এই পদ্ধতির আউটপুটের পার্থক্য নিচের ছবির মাধ্যমে পরিষ্কার হয়ে যাবে। নিচের GIF image এ দেখা যাচ্ছে অ্যাপ launch করার পর instant আমাদের Splash screen শো করেছে। এরপর MainActivity শো করেছে। আগেরবারের মত একটা সাদা স্ক্রিন এখানো দেখায় নি।
![Android Splash Screen Implementation in Best way](https://i0.wp.com/hellohasan.com/wp-content/uploads/2018/07/02.Android-Splash-Screengood-implementation.gif?resize=276%2C490&ssl=1)
এই ইমপ্লিমেন্টেশনেও আগের মত আলাদা একটা activity থাকবে Splash screen দেখানোর জন্য। কিন্তু আগের মত করে আমরা সময় নির্দিষ্ট করে delay করাবো না। Cold boot এর জন্য যতক্ষণ সময় প্রয়োজন ঠিক ততক্ষণই আমরা স্প্ল্যাশ স্ক্রিন শো করাবো। ২/৩ সেকেন্ডের মধ্যে যখন onCreate() কল হবে তখন আমরা MainActivity ওপেন করব আর স্প্ল্যাশ অ্যাক্টিভিটি ফিনিশ করব।
প্রথম পদ্ধতিতে একটা সাদা স্ক্রিন দেখাত কারণ onCreate() কল হবার জন্য কয়েক সেকেন্ড সময় লাগে। তারমানে আমাদের স্প্ল্যাশ স্ক্রিন দেখানোর কাজটা onCreate() এর ভিতর রাখা যাবে না।
যখন কোনো অ্যাক্টিভিটি কল হয় তখন Android OS প্রথমে খুঁজে দেখে মেনিফেস্টে ঐ অ্যাক্টিভিটির জন্য কোনো থিম সেট করে দেয়া আছে কিনা। যদি কোনো থিম সেট করা থাকে তাহলে থিমটা প্রথমে লোড হয় এবং সেটা স্ক্রিনে সেটা শো করে। এরপর অ্যাক্টিভিটি লাইফসাইকেলের অন্যান্য মেথড সহ onCreate() মেথড কল। এই ট্রিকটা কাজে লাগিয়ে আমরা স্প্ল্যাশ স্ক্রিনের প্রবলেমটা সলভ করতে পারি।
যেহেতু মেনিফেস্টের থিমটা সর্বপ্রথম লোড হয় তাই আমরা AndroidManifest.xml ফাইলে SplashScreenActivity এর জন্য একটা custom theme সেট করব। সেই থিমে বলা থাকবে আমরা ব্যাকগ্রাউন্ড কালারে কী দেখাতে চাই, স্ক্রিনের মাঝে কোন লোগো শো করাতে চাই ইত্যাদি। আর এই কাস্টম থিমটা রাখব values ফোল্ডারের styles.xml ফাইলে। নিয়ম অনুযায়ী যখন অ্যাপের launcher activity অর্থাৎ SplashScreenActivity কল হবে তখন মুহূর্তের মধ্যে কাস্টম থিমের ডিজাইনটা শো হবে। এরপর onCreate() কল হতে ২ সেকেন্ড সময় লাগুক বা ৩ সেকেন্ড লাগুক সেটা আমাদের চিন্তার বিষয় না। আমরা onCreate() এর ভিতর জাস্ট বলে দিব MainActivity কল করার জন্য। যেহেতু আমাদের কাঙ্খিত স্প্ল্যাশ স্ক্রিন থিম থেকেই লোড করানো হয়েছে তাই onCreate() এর ভিতরে setContentView() মেথড কল করে কোনো xml layout লোড করাতে হবে না।
মেনিফেস্টের কোডটা নিচে দেয়া হলোঃ
<activity android:name=".SplashScreenActivity" android:theme="@style/AppTheme.Launcher"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
দ্বিতীয় লাইনে সেট করা কাস্টম থিমের কোড নিম্নরূপঃ
<style name="AppTheme.Launcher"> <item name="android:windowBackground">@drawable/launcher_screen_with_logo</item> <item name="android:windowNoTitle">true</item> <item name="android:windowActionBar">false</item> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item> </style>
প্রথম আইটেমে থাকা windowBackground এর ভ্যালু হিসাবে সেট করা হয়েছে একটা drawable xml resource. এটাও কাস্টম করে বানানো। গিটহাবে থাকা প্রজেক্টের launcher_screen_with_logo.xml নামের একটা ফাইল drawable ফোল্ডারে পাবেন। এই drawable resource টি নিচে দেয়া হলোঃ (গিটহাবের লিংক লেখার শেষে দেয়া হবে)
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"> <item android:drawable="@android:color/holo_purple" /> <item> <bitmap android:gravity="center" android:src="@drawable/app_logo" /> </item> </layer-list>
প্রথম আইটেমে ব্যাকগ্রাউন্ড কালার সেট করা হয়েছে আর দ্বিতীয় আইটেমের মাধ্যমে স্ক্রিনের মাঝখানে অ্যাপের লোগো সেট করা হয়েছে। লোগোটা drawable folder এ আগে থেকে রেখে দিয়েছি।
সর্বশেষ বাকি থাকল SplashScreenActivity ক্লাসের কোড। নিচে সেটা দেয়া হলোঃ
public class SplashScreenActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); startActivity(new Intent(SplashScreenActivity.this, MainActivity.class)); finish(); } }
দেখেন! onCreate() এর ভিতরে setContentView() দিয়ে কোনো xml layout শো করানো হচ্ছে না। super.onCreate() কলের পর সিমপ্লি পরের অ্যাক্টিভিটি লোড করানো হয়েছে। অ্যাপ লঞ্চ করার পর কোনো ডিভাইসে যদি onCreate() পর্যন্ত আসতে ২ সেকেন্ড সময় নেয় তাহলে আমাদের কাস্টম থিমটা ২ সেকেন্ড শো করবে। এরপর onCreate() এর ভিতর ঢুকে MainActivity স্টার্ট করবে। আবার কোনো ডিভাইসে যদি লঞ্চ করার পর ৫ সেকেন্ড লাগে তাহলে ৫ সেকেন্ড স্প্ল্যাশ শো করবে। আমরা অযথা কয়েক সেকেন্ড ফিক্সড করে দিয়ে রাখছি না। ব্যস! আমাদের স্প্ল্যাশ স্ক্রিন ইমপ্লিমেন্ট করা শেষ! মনে হতে পারে মহা ঝামেলা করে কেন কাজটা করব? এটা করে কী লাভ? লাভ হচ্ছে আনন্দ পাওয়া। একটা কাজ ঠিকঠাক মতে করার আনন্দ আর জোড়াতালি দিয়ে করার আনন্দের মধ্যে পার্থক্য আছে। “কুনো মতে কাম হইলেই হইছে” নীতিতে বিশ্বাসীদের ব্যাপারে অবশ্য অন্য হিসাব!
3. Android Splash Screen Implementation – Best way
![Android Splash Screen Implementation in Best way](https://i0.wp.com/hellohasan.com/wp-content/uploads/2018/07/03.Android-Splash-Screenbest-implementation.gif?resize=259%2C460&ssl=1)
দ্বিতীয় আর তৃতীয় ইমপ্লিমেন্টেশনের ক্ষেত্রে আউটপুটে কোনো পার্থক্য চোখে পড়বে না। সাধারন কেসে উভয় ইমপ্লিমেন্টেশনের আউটপুট একই আসবে। পার্থক্য কিছুটা হতে পারে অ্যাপের সাইজে। কারণ এই ইমপ্লিমেন্টেশনে আমরা স্প্ল্যাশ স্ক্রিনের জন্য আলাদা কোনো অ্যাক্টিভিটি ব্যবহার করব না। তাই সাইজ অল্প কিছু হলেও কম হবে।
এই পদ্ধতির ইমপ্লিমেন্টেশনের আইডিটা বলছি। আগের পদ্ধতির মত এখানেও মেনিফেস্ট থেকে থিম সেট করে দেয়া হবে। কিন্তু সেটা SplashScreenActivity এর জন্য থিম নয়। AppTheme.Launcher থিমটি সেট করব এবার MainActivity এর জন্য। আর MainActivity হবে আমাদের launcher activity. তাহলে অ্যাপ লঞ্চ করলে MainActivity প্রথমে ওপেন হবে। যেহেতু MainActivity এর মেনিফেস্টে কাস্টম থিম সেট করে দেয়া হয়েছে তাই শুরুতেই স্প্যাশ স্ক্রিন শো করবে। এরপর যখন MainActivity এর onCreate() কল হবে তখন super.onCreate() কল করার আগেই MainActivity এর original theme টা সেট করে দিতে হবে setTheme() মেথড কল করার মাধ্যমে। এরপর super.onCreate() কল হবে। এরপর যথারীতি setContentView() মেথড কল করে xml layout লোড করানো হবে। এরপর বাকি কাজ MainActivity এর আগের মতই হবে।
ট্রিকি পার্ট হচ্ছে MainActivity এর onCreate() এর ভিতর প্রথম লাইনে MainActivity এর জন্য থিম সেট করা। সাধারণত আমরা AppTheme থিমটা সেট করে থাকি। তাহলে অ্যাপ লঞ্চ করার পর মেনিফেস্টের থিম শো করলেও যখন OnCreate() successfully কল হয় তখন আবার অ্যাপের মেইন থিম লোড করানো হয়।
এখানে AndroidManifest.xml, styles.xml, drawable resource সবগুলো কোডই দ্বিতীয় নিয়মের মত। পার্থক্য শুধু হবে MainActivity এর onCreate() এর প্রথম লাইনে। এই পার্থক্যটুকু নিচে দেখানো হলোঃ
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.AppTheme); //set original AppTheme super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //TODO: add your MainActivity code here } }
আপনি Android Studio তে কোনো প্রোজেক্ট ওপেন করলে styles.xml ফাইলে AppTheme নামের একটা থিম বাই ডিফল্ট ক্রিয়েট হয়ে যাবে। সেই থিমটাই onCreate() এর ভিতর প্রথম লাইনে সেট করা হয়েছে।
Conclusion
আমাদের উচিত প্রথমটা বাদ দিয়ে পরের দুইটার যে কোনো একটা বেছে নেয়া। কখনো কখনো তৃতীয় পদ্ধতির তুলনায় দ্বিতীয় পদ্ধতি বেশি appropriate হবে। যেমনঃ যদি আপনার অ্যাপে MainActivity অ্যাপের যে কোনো জায়গা থেকে আবার কল হবার সম্ভাবনা থাকে তাহলে তৃতীয় পদ্ধতি ব্যবহার করা ঠিক হবে না। ধরা যাক একটা ই-কমার্স অ্যাপের HomeActivity হচ্ছে launcher activity. আপনি তৃতীয় পদ্ধতি অনুসরণ করে HomeActivity এর মেনিফেস্টে স্প্ল্যাশ স্ক্রিনের জন্য থিম সেট করেছেন। তো হোম পেজ থেকে কোনো একটা প্রোডাক্ট সিলেক্ট করে ডিটেইলস পেজে গেলেন। এই অবস্থায় যদি আপনার কোনো কারণে দরকার হয় আবার হোম অ্যাক্টিভিটিকে কল করার। তখন হোম অ্যাক্টিভিটি কল করলে স্প্ল্যাশ স্ক্রিন প্রথমে শো করবে। এরপর হোম স্ক্রিনের UI শো করবে। তাই এরকম ইউজ কেস থাকলে দ্বিতীয় পদ্ধতিটি সেফ। সেক্ষেত্রে স্প্ল্যাশ স্ক্রিন একাধিক বার সামনে আসার চান্স থাকবে না। কিন্তু আপনার হোম অ্যাক্টিভিটি পরবর্তীতে আর কল হবার চান্স না থাকলে তৃতীয় পদ্ধতিটি ব্যবহার করাই ভাল।
আবার আপনি যদি স্প্ল্যাশ দেখানোর পর কোনো কন্ডিশনের উপর বেজ করে কোন অ্যাক্টিভিটি ওপেন করবেন সেই ডিসিশন নিতে চান সেক্ষেত্রেও দ্বিতীয় পদ্ধতি আপনার কাজকে সহজ করে দিবে। দুই ভাবেই প্র্যাক্টিস করতে পারেন। এরপর যখন যেটা স্যুট করবে তখন সেটা ইউজ করলেন।
প্রোজেক্টগুলোর সম্পূর্ণ সোর্সকোড পাওয়া যাবে আমার গিটহাব রিপোজিটরিতে।
লেখাটি সময় নিয়ে পড়ার জন্য ধন্যবাদ। কোথাও কোনো ভুলত্রুটি চোখে পড়লে কষ্ট করে কমেন্ট করে জানাবেন। আমি ঠিক করে দিব ইনশাআল্লাহ। এছাড়াও লেখাটি সম্পর্কে আপনার যে কোনো মন্তব্য বা পরামর্শ একান্ত কাম্য।
খুব সুন্দর একটা জিনিস শিখলাম দাদা । ধন্যবাদ ।
You are most welcome…
Thank you very much vaiya…
You are most welcome…
spni-kit ব্যবহার করে good/ best way apply কিভাবে করব। অনেক ট্রাই করলাম হল না। আপনি একটু বলে দিলে বা দেখালে উপক্রিত হতাম।
how I can implement spin-kit for animated progress in splash screen good/best way? I have tried many times, failed. if you kindly help me…pls
I loved it bro, thanks and bring more like it
Thank you for your feedback.