Activity ক্লাস একটি অ্যান্ড্রয়েড অ্যাপের অত্যন্ত গুরুত্বপূর্ণ উপাদান, এবং অ্যাক্টিভিটিগুলো যেভাবে চালু ও গঠিত হয় তা প্ল্যাটফর্মটির অ্যাপ্লিকেশন মডেলের একটি মৌলিক অংশ। অন্যান্য প্রোগ্রামিং প্যারাডাইমের মতো নয়, যেখানে অ্যাপগুলো main মেথডের মাধ্যমে চালু করা হয়, অ্যান্ড্রয়েড সিস্টেম একটি Activity ইনস্ট্যান্সে কোড শুরু করে তার লাইফসাইকেলের নির্দিষ্ট পর্যায়গুলোর সাথে সঙ্গতিপূর্ণ বিশেষ কলব্যাক মেথডগুলোকে কল করার মাধ্যমে।
এই ডকুমেন্টটি অ্যাক্টিভিটিজ-এর ধারণাটি উপস্থাপন করে এবং এরপর সেগুলো নিয়ে কীভাবে কাজ করতে হয় সে সম্পর্কে কিছু প্রাথমিক নির্দেশনা প্রদান করে। আপনার অ্যাপের আর্কিটেকচার তৈরির সেরা পদ্ধতিগুলো সম্পর্কে অতিরিক্ত তথ্যের জন্য, ‘গাইড টু অ্যাপ আর্কিটেকচার’ দেখুন।
কার্যকলাপের ধারণা
মোবাইল অ্যাপের অভিজ্ঞতা ডেস্কটপ অ্যাপের থেকে এই কারণে আলাদা যে, অ্যাপটির সাথে ব্যবহারকারীর মিথস্ক্রিয়া সবসময় একই জায়গা থেকে শুরু হয় না। বরং, ব্যবহারকারীর যাত্রা প্রায়শই অনির্দিষ্টভাবে শুরু হয়। উদাহরণস্বরূপ, আপনি যদি আপনার হোম স্ক্রিন থেকে একটি ইমেল অ্যাপ খোলেন, তাহলে আপনি ইমেলগুলোর একটি তালিকা দেখতে পারেন। এর বিপরীতে, আপনি যদি এমন একটি সোশ্যাল মিডিয়া অ্যাপ ব্যবহার করেন যা পরে আপনার ইমেল অ্যাপটি চালু করে, তাহলে আপনি সরাসরি ইমেল লেখার জন্য ইমেল অ্যাপের স্ক্রিনে চলে যেতে পারেন।
Activity ক্লাসটি এই প্যারাডাইমকে সহজতর করার জন্য ডিজাইন করা হয়েছে। যখন একটি অ্যাপ অন্য একটি অ্যাপকে কল করে, তখন কলকারী অ্যাপটি সম্পূর্ণ অ্যাপটিকে কল না করে, অন্য অ্যাপটির একটি অ্যাক্টিভিটিকে কল করে। এইভাবে, অ্যাক্টিভিটিটি ব্যবহারকারীর সাথে একটি অ্যাপের ইন্টারঅ্যাকশনের প্রবেশদ্বার হিসেবে কাজ করে। আপনি Activity ক্লাসের একটি সাবক্লাস হিসেবে একটি অ্যাক্টিভিটি ইমপ্লিমেন্ট করেন।
অ্যাক্টিভিটি সেই উইন্ডোটি সরবরাহ করে যেখানে অ্যাপটি তার ইউজার ইন্টারফেস (UI) অঙ্কন করে। এই উইন্ডোটি সাধারণত স্ক্রিন জুড়ে থাকে, তবে এটি স্ক্রিনের চেয়ে ছোটও হতে পারে এবং অন্যান্য উইন্ডোর উপরে ভাসমান থাকতে পারে।
সাধারণত, একটি অ্যাপের একটি অ্যাক্টিভিটিকে প্রধান অ্যাক্টিভিটি হিসেবে নির্দিষ্ট করা হয়, যা ব্যবহারকারী অ্যাপটি চালু করলে প্রথম স্ক্রিন হিসেবে প্রদর্শিত হয়। আধুনিক কম্পোজ অ্যাপগুলিতে, এটিই একমাত্র প্রয়োজনীয় অ্যাক্টিভিটি, কারণ এটি কোনো ভিউ হায়ারার্কির মালিক না হয়ে একটি একক-অ্যাক্টিভিটি আর্কিটেকচারে কম্পোজেবলগুলিকে হোস্ট করে। অ্যাপের স্ক্রিনগুলির জন্য একাধিক অ্যাক্টিভিটি থাকার পরিবর্তে, এই অ্যাক্টিভিটির কম্পোজেবলগুলি একাধিক নেভিগেশন গন্তব্য হোস্ট করে।
আপনার অ্যাপে অ্যাক্টিভিটি ব্যবহার করতে হলে, অ্যাপের ম্যানিফেস্টে সেগুলোর তথ্য নিবন্ধন করতে হবে এবং অ্যাক্টিভিটির জীবনচক্র সম্পর্কে অবগত থাকা একটি ভালো অভ্যাস। এই ডকুমেন্টের বাকি অংশে এই বিষয়গুলো আলোচনা করা হয়েছে।
ম্যানিফেস্ট কনফিগার করা
আপনার অ্যাপে অ্যাক্টিভিটি ব্যবহার করার জন্য, আপনাকে অবশ্যই ম্যানিফেস্টে অ্যাক্টিভিটিগুলো এবং সেগুলোর নির্দিষ্ট কিছু অ্যাট্রিবিউট ঘোষণা করতে হবে।
কার্যক্রম ঘোষণা করুন
আপনার অ্যাক্টিভিটি ডিক্লেয়ার করতে, আপনার ম্যানিফেস্ট ফাইলটি খুলুন এবং <application> এলিমেন্টের চাইল্ড হিসেবে একটি <activity> এলিমেন্ট যোগ করুন। উদাহরণস্বরূপ:
<manifest ... >
<application ... >
<activity android:name=".ExampleActivity" />
...
</application ... >
...
</manifest >
এই এলিমেন্টের জন্য একমাত্র আবশ্যক অ্যাট্রিবিউট হলো android:name , যা অ্যাক্টিভিটির ক্লাস নেম নির্দিষ্ট করে। এছাড়াও আপনি এমন অ্যাট্রিবিউট যোগ করতে পারেন যা অ্যাক্টিভিটির বৈশিষ্ট্য নির্ধারণ করে, যেমন লেবেল, আইকন বা UI থিম। এই এবং অন্যান্য অ্যাট্রিবিউট সম্পর্কে আরও তথ্যের জন্য, <activity> এলিমেন্টের রেফারেন্স ডকুমেন্টেশন দেখুন।
অভিপ্রায় ফিল্টার ঘোষণা করুন
ইনটেন্ট ফিল্টার অ্যান্ড্রয়েড প্ল্যাটফর্মের একটি অত্যন্ত শক্তিশালী বৈশিষ্ট্য। এটি শুধুমাত্র সুস্পষ্ট অনুরোধের ভিত্তিতেই নয়, বরং অপ্রত্যক্ষ অনুরোধের ভিত্তিতেও একটি অ্যাক্টিভিটি চালু করার ক্ষমতা প্রদান করে। উদাহরণস্বরূপ, একটি সুস্পষ্ট অনুরোধ সিস্টেমকে বলতে পারে, "জিমেইল অ্যাপে 'সেন্ড ইমেল' অ্যাক্টিভিটিটি চালু করো"। এর বিপরীতে, একটি অপ্রত্যক্ষ অনুরোধ সিস্টেমকে বলে, "যে কোনো অ্যাক্টিভিটিতে একটি 'সেন্ড ইমেল' স্ক্রিন চালু করো যা এই কাজটি করতে পারে।" যখন সিস্টেম UI কোনো কাজ সম্পাদনের জন্য ব্যবহারকারীকে জিজ্ঞাসা করে যে কোন অ্যাপটি ব্যবহার করতে হবে, তখন সেটি একটি ইনটেন্ট ফিল্টারের কাজ।
আপনি <activity> এলিমেন্টে একটি <intent-filter> অ্যাট্রিবিউট ডিক্লেয়ার করে এই ফিচারটির সুবিধা নিতে পারেন। এই এলিমেন্টের সংজ্ঞায় একটি <action> এলিমেন্ট এবং ঐচ্ছিকভাবে একটি <category> এলিমেন্ট এবং/অথবা একটি <data> এলিমেন্ট অন্তর্ভুক্ত থাকে। এই এলিমেন্টগুলো একত্রিত হয়ে নির্দিষ্ট করে দেয় যে আপনার অ্যাক্টিভিটি কোন ধরনের ইনটেন্টে সাড়া দিতে পারবে। উদাহরণস্বরূপ, নিচের কোড স্নিপেটটি দেখাচ্ছে কীভাবে এমন একটি অ্যাক্টিভিটি কনফিগার করতে হয় যা টেক্সট ডেটা ও ইমেল পাঠায় এবং অন্যান্য অ্যাক্টিভিটি থেকে তা করার জন্য অনুরোধ গ্রহণ করে:
<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="mailto" />
</intent-filter>
</activity>
এই উদাহরণে, <action> এলিমেন্টটি নির্দিষ্ট করে যে এই অ্যাক্টিভিটি ডেটা পাঠাবে। <category> এলিমেন্টটিকে DEFAULT হিসেবে ঘোষণা করলে অ্যাক্টিভিটিটি লঞ্চ রিকোয়েস্ট গ্রহণ করতে সক্ষম হয়। <data> এলিমেন্টটি নির্দিষ্ট করে যে এই অ্যাক্টিভিটিটি কী ধরনের ডেটা পাঠাতে পারবে। নিচের কোড স্নিপেটটি দেখায় কীভাবে উপরে বর্ণিত অ্যাক্টিভিটিটিকে একটি ইমেল কম্পোজ করার জন্য কল করতে হয়:
fun composeEmail(addresses: Array<String>, subject: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:") // Only email apps handle this.
putExtra(Intent.EXTRA_EMAIL, addresses)
putExtra(Intent.EXTRA_SUBJECT, subject)
}
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
}
যদি আপনি চান আপনার অ্যাপটি স্বয়ংসম্পূর্ণ থাকুক এবং অন্য কোনো অ্যাপ এর অ্যাক্টিভিটিগুলো সক্রিয় করতে না পারে, তাহলে আপনার অন্য কোনো ইন্টেন্ট ফিল্টারের প্রয়োজন নেই। যে অ্যাক্টিভিটিগুলো আপনি অন্য অ্যাপ্লিকেশনের জন্য উপলব্ধ করতে চান না, সেগুলোতে কোনো ইন্টেন্ট ফিল্টার থাকা উচিত নয় এবং আপনি সুস্পষ্ট ইন্টেন্ট ব্যবহার করে সেগুলো নিজেই শুরু করতে পারেন। আপনার অ্যাক্টিভিটিগুলো কীভাবে ইন্টেন্টের প্রতি সাড়া দিতে পারে সে সম্পর্কে আরও তথ্যের জন্য, ইন্টেন্ট এবং ইন্টেন্ট ফিল্টার দেখুন।
আগত ইন্টেন্টগুলি পরিচালনা করুন
নিম্নলিখিত উদাহরণটি একাধিক ইন্টেন্ট টাইপ—যেমন একক টেক্সট শেয়ার, একক ছবি এবং একাধিক ছবির অ্যারে—হ্যান্ডেল করার সময় অ্যাক্টিভিটি লাইফসাইকেল পরিচালনার একটি প্যাটার্ন দেখায়। এই বিভিন্ন ইনপুটগুলিকে একটি কেন্দ্রীভূত handleIntent ফাংশনের মাধ্যমে রাউট করার ফলে, এটি নিশ্চিত করে যে ACTION_SEND এবং ACTION_SEND_MULTIPLE উভয় অ্যাকশনই সঠিকভাবে পার্স করা হয়েছে এবং একটি রিঅ্যাক্টিভ UI আপডেটের জন্য ViewModel-এ ডেলিগেট করা হয়েছে।
class ExampleActivity : ComponentActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
setContent {
ComposeApp(viewModel)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleIntent(intent)
}
private fun handleIntent(intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SEND -> {
if ("text/plain" == intent.type) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
viewModel.handleText(it) // Update UI to reflect text being shared
}
} else if (intent.type?.startsWith("image/") == true) {
(intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))?.let {
viewModel.handleImage(it) // Update UI to reflect image being shared
}
}
}
Intent.ACTION_SEND_MULTIPLE -> {
if (intent.type?.startsWith("image/") == true) {
intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri::class.java)?.let {
viewModel.handleMultipleImages(it) // Update UI to reflect multiple images being shared
}
} else {
// Handle other types
}
}
else -> {
// Handle other intents
}
}
}
}
অনুমতি ঘোষণা করুন
কোন অ্যাপ একটি নির্দিষ্ট অ্যাক্টিভিটি শুরু করতে পারবে, তা নিয়ন্ত্রণ করতে আপনি ম্যানিফেস্টের <activity> ট্যাগ ব্যবহার করতে পারেন। একটি প্যারেন্ট অ্যাক্টিভিটি কোনো চাইল্ড অ্যাক্টিভিটি চালু করতে পারে না, যদি না উভয় অ্যাক্টিভিটির ম্যানিফেস্টে একই পারমিশন থাকে। যদি আপনি কোনো প্যারেন্ট অ্যাক্টিভিটির জন্য একটি <uses-permission> এলিমেন্ট ঘোষণা করেন, তবে প্রতিটি চাইল্ড অ্যাক্টিভিটিতেও একটি অনুরূপ <uses-permission> এলিমেন্ট থাকতে হবে।
উদাহরণস্বরূপ, যদি আপনার অ্যাপ সোশ্যাল মিডিয়ায় একটি পোস্ট শেয়ার করার জন্য SocialApp নামের একটি কাল্পনিক অ্যাপ ব্যবহার করতে চায়, তাহলে SocialApp-কেই সেই অনুমতিটি নির্ধারণ করতে হবে যা এটিকে কলকারী অ্যাপটির অবশ্যই থাকতে হবে:
<manifest>
<activity android:name="...."
android:permission="com.google.socialapp.permission.SHARE_POST"
/>
তারপর, SocialApp কল করার অনুমতি পেতে হলে, আপনার অ্যাপটিকে অবশ্যই SocialApp-এর ম্যানিফেস্টে সেট করা অনুমতির সাথে মিলতে হবে:
<manifest>
<uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>
অনুমতি এবং সাধারণ নিরাপত্তা সম্পর্কে আরও তথ্যের জন্য, নিরাপত্তা চেকলিস্ট দেখুন।
কার্যকলাপের জীবনচক্র পরিচালনা করা
একটি অ্যাক্টিভিটি তার জীবনচক্র জুড়ে বিভিন্ন অবস্থার মধ্য দিয়ে যায়। এই অবস্থাগুলোর মধ্যে পরিবর্তন পরিচালনা করার জন্য আপনি একাধিক কলব্যাক ব্যবহার করেন। পরবর্তী বিভাগগুলোতে এই কলব্যাকগুলো সম্পর্কে আলোচনা করা হয়েছে। একটি Compose অ্যাপে সরাসরি এই কলব্যাকগুলোতে হুক করা বাঞ্ছনীয় নয়। এর পরিবর্তে, অবস্থার পরিবর্তন পর্যবেক্ষণ করতে লাইফসাইকেল এপিআই (Lifecycle API) ব্যবহার করুন। আরও তথ্যের জন্য, “Integrate lifecycle with Compose” দেখুন।
onCreate
আপনাকে অবশ্যই এই কলব্যাকটি ইমপ্লিমেন্ট করতে হবে, যা সিস্টেম আপনার অ্যাক্টিভিটি তৈরি করার সময় ফায়ার হয়। আপনার ইমপ্লিমেন্টেশনে অ্যাক্টিভিটির অপরিহার্য উপাদানগুলো ইনিশিয়ালাইজ করা উচিত: উদাহরণস্বরূপ, আপনার অ্যাপে এখানে ভিউ তৈরি করা এবং লিস্টের সাথে ডেটা বাইন্ড করা উচিত।
একটি Compose অ্যাপে, নিচে দেখানো অনুযায়ী setContent ব্যবহার করে আপনার হোস্ট কম্পোজেবল সেট আপ করতে এই কলব্যাকটি ব্যবহার করুন:
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Text(text = stringResource(id = R.string.greeting))
}
}
}
যখন onCreate শেষ হয়, পরবর্তী কলব্যাকটি সর্বদা onStart হয়।
শুরুতে
onCreate থেকে বেরিয়ে আসার সাথে সাথে অ্যাক্টিভিটিটি Started অবস্থায় প্রবেশ করে এবং ব্যবহারকারীর কাছে দৃশ্যমান হয়ে ওঠে। এই কলব্যাকে অ্যাক্টিভিটির ফোরগ্রাউন্ডে এসে ইন্টারঅ্যাক্টিভ হওয়ার জন্য চূড়ান্ত প্রস্তুতিগুলো অন্তর্ভুক্ত থাকে।
রিজুমে
অ্যাক্টিভিটি ব্যবহারকারীর সাথে মিথস্ক্রিয়া শুরু করার ঠিক আগে সিস্টেম এই কলব্যাকটি আহ্বান করে। এই পর্যায়ে, অ্যাক্টিভিটিটি অ্যাক্টিভিটি স্ট্যাকের শীর্ষে থাকে এবং ব্যবহারকারীর সমস্ত ইনপুট গ্রহণ করে। একটি অ্যাপের বেশিরভাগ মূল কার্যকারিতা onResume মেথডে প্রয়োগ করা হয়।
onPause কলব্যাকটি সর্বদা onResume পরে আসে।
বিরতিতে
যখন অ্যাক্টিভিটি ফোকাস হারায় এবং পজড অবস্থায় প্রবেশ করে, তখন সিস্টেম onPause কল করে। এই অবস্থাটি ঘটে যখন, উদাহরণস্বরূপ, ব্যবহারকারী ব্যাক বা রিসেন্টস বোতামে ট্যাপ করেন। যখন সিস্টেম আপনার অ্যাক্টিভিটির জন্য onPause কল করে, তখন প্রযুক্তিগতভাবে এর অর্থ হলো আপনার অ্যাক্টিভিটিটি তখনও আংশিকভাবে দৃশ্যমান, কিন্তু বেশিরভাগ ক্ষেত্রেই এটি একটি ইঙ্গিত যে ব্যবহারকারী অ্যাক্টিভিটিটি ছেড়ে যাচ্ছেন এবং অ্যাক্টিভিটিটি শীঘ্রই স্টপড বা রিজুমড অবস্থায় প্রবেশ করবে।
পজ করা অবস্থায় থাকা কোনো অ্যাক্টিভিটি UI আপডেট করা চালিয়ে যেতে পারে, যদি ব্যবহারকারী UI আপডেট হওয়ার প্রত্যাশা করেন। এই ধরনের অ্যাক্টিভিটির উদাহরণ হলো নেভিগেশন ম্যাপ স্ক্রিন দেখানো বা মিডিয়া প্লেয়ার চালানো। এই ধরনের অ্যাক্টিভিটি ফোকাস হারালেও, ব্যবহারকারী আশা করেন যে তাদের UI আপডেট হতে থাকবে।
অ্যাপ্লিকেশন বা ব্যবহারকারীর ডেটা সংরক্ষণ করতে, নেটওয়ার্ক কল করতে, বা ডাটাবেস ট্রানজ্যাকশন সম্পাদন করতে আপনার onPause ব্যবহার করা উচিত নয় । ডেটা সংরক্ষণ সম্পর্কে তথ্যের জন্য, ক্ষণস্থায়ী UI অবস্থা সংরক্ষণ এবং পুনরুদ্ধার দেখুন।
onPause এক্সিকিউশন শেষ হয়ে গেলে, অ্যাক্টিভিটিটি Paused অবস্থায় প্রবেশ করার পর কী ঘটে তার উপর নির্ভর করে পরবর্তী কলব্যাকটি হয় onStop অথবা onResume ।
অনস্টপ
যখন অ্যাক্টিভিটিটি ব্যবহারকারীর কাছে আর দৃশ্যমান থাকে না, তখন সিস্টেম onStop কল করে। এটি ঘটতে পারে কারণ অ্যাক্টিভিটিটি ধ্বংস হয়ে যাচ্ছে, একটি নতুন অ্যাক্টিভিটি শুরু হচ্ছে, অথবা একটি বিদ্যমান অ্যাক্টিভিটি 'Resumed' অবস্থায় প্রবেশ করে বন্ধ থাকা অ্যাক্টিভিটিটিকে ঢেকে ফেলছে। এই সমস্ত ক্ষেত্রে, বন্ধ থাকা অ্যাক্টিভিটিটি আর মোটেই দৃশ্যমান থাকে না।
সিস্টেম পরবর্তী যে কলব্যাকটি কল করে, সেটি হয় onRestart , যদি অ্যাক্টিভিটিটি ব্যবহারকারীর সাথে পুনরায় যোগাযোগ করতে ফিরে আসে, অথবা onDestroy যদি এই অ্যাক্টিভিটিটি সম্পূর্ণরূপে বন্ধ হয়ে যায়।
পুনরায় চালু করুন
যখন Stopped অবস্থায় থাকা কোনো অ্যাক্টিভিটি পুনরায় চালু হতে যায়, তখন সিস্টেম এই কলব্যাকটি চালু করে। onRestart অ্যাক্টিভিটিটির অবস্থাকে সেই সময় থেকে পুনরুদ্ধার করে, যে সময়ে এটি বন্ধ করা হয়েছিল।
এই কলব্যাকের পরেই সর্বদা onStart আসে।
ধ্বংস করুন
কোনো অ্যাক্টিভিটি ধ্বংস হওয়ার আগে সিস্টেম এই কলব্যাকটি চালু করে।
এই কলব্যাকটিই অ্যাক্টিভিটির পাওয়া সর্বশেষ কলব্যাক। যখন কোনো অ্যাক্টিভিটি বা সেটিকে ধারণকারী প্রসেসটি ধ্বংস হয়ে যায়, তখন অ্যাক্টিভিটির সমস্ত রিসোর্স যেন মুক্ত হয়ে যায়, তা নিশ্চিত করার জন্য সাধারণত onDestroy প্রয়োগ করা হয়।
এই বিভাগে বিষয়টির কেবল একটি ভূমিকা দেওয়া হয়েছে। অ্যাক্টিভিটি লাইফসাইকেল এবং এর কলব্যাকগুলো সম্পর্কে আরও বিস্তারিত আলোচনার জন্য, “The activity lifecycle” দেখুন।