ধারণা এবং জেটপ্যাক কম্পোজ বাস্তবায়ন
একজন ব্যবহারকারী যখন আপনার অ্যাপের মধ্যে দিয়ে যান, অ্যাপ থেকে বেরিয়ে যান এবং আবার ফিরে আসেন, তখন আপনার অ্যাপের Activity ইনস্ট্যান্সগুলো তাদের জীবনচক্রে বিভিন্ন অবস্থার মধ্য দিয়ে পরিবর্তিত হয়। Activity ক্লাসটি বেশ কিছু কলব্যাক প্রদান করে, যা অ্যাক্টিভিটিকে জানিয়ে দেয় কখন এর অবস্থার পরিবর্তন হচ্ছে, অথবা সিস্টেম কোনো অ্যাক্টিভিটি তৈরি করছে, বন্ধ করছে বা পুনরায় চালু করছে, কিংবা যে প্রসেসে অ্যাক্টিভিটিটি রয়েছে তা ধ্বংস করছে।
লাইফসাইকেল কলব্যাক মেথডগুলোর মধ্যে আপনি নির্ধারণ করতে পারেন যে, ব্যবহারকারী যখন অ্যাক্টিভিটি থেকে বেরিয়ে গিয়ে আবার প্রবেশ করে, তখন সেটি কীভাবে আচরণ করবে। উদাহরণস্বরূপ, আপনি যদি একটি স্ট্রিমিং ভিডিও প্লেয়ার তৈরি করেন, তাহলে ব্যবহারকারী অন্য কোনো অ্যাপে চলে গেলে আপনি ভিডিওটি পজ করে দিতে এবং নেটওয়ার্ক সংযোগ বিচ্ছিন্ন করে দিতে পারেন। ব্যবহারকারী ফিরে এলে, আপনি নেটওয়ার্কের সাথে পুনরায় সংযোগ স্থাপন করতে পারেন এবং তাকে একই জায়গা থেকে ভিডিওটি আবার শুরু করার সুযোগ দিতে পারেন।
প্রতিটি কলব্যাক আপনাকে অবস্থার একটি নির্দিষ্ট পরিবর্তনের জন্য উপযুক্ত বিশেষ কাজ সম্পাদন করতে দেয়। সঠিক সময়ে সঠিক কাজ করা এবং ট্রানজিশনগুলো সঠিকভাবে পরিচালনা করা আপনার অ্যাপকে আরও শক্তিশালী এবং কর্মক্ষম করে তোলে। উদাহরণস্বরূপ, লাইফসাইকেল কলব্যাকের ভালো বাস্তবায়ন আপনার অ্যাপকে নিম্নলিখিত বিষয়গুলো এড়াতে সাহায্য করতে পারে:
- আপনার অ্যাপটি ব্যবহার করার সময় ব্যবহারকারী ফোন কল পেলে বা অন্য কোনো অ্যাপে গেলে অ্যাপটি ক্র্যাশ করে।
- ব্যবহারকারী সক্রিয়ভাবে ব্যবহার না করা সত্ত্বেও মূল্যবান সিস্টেম রিসোর্স খরচ করা।
- ব্যবহারকারী যদি আপনার অ্যাপ থেকে বেরিয়ে যান এবং পরে আবার ফিরে আসেন, তাহলে তার অগ্রগতি হারিয়ে যায়।
- স্ক্রিন ল্যান্ডস্কেপ ও পোর্ট্রেট ওরিয়েন্টেশনের মধ্যে ঘোরানোর সময় ক্র্যাশ করা বা ব্যবহারকারীর অগ্রগতি হারিয়ে যাওয়া।
এই ডকুমেন্টটি অ্যাক্টিভিটি লাইফসাইকেল বিস্তারিতভাবে ব্যাখ্যা করে। ডকুমেন্টটি লাইফসাইকেল প্যারাডাইম বর্ণনা করার মাধ্যমে শুরু হয়। এরপর, এটি প্রতিটি কলব্যাক ব্যাখ্যা করে: সেগুলো কার্যকর হওয়ার সময় অভ্যন্তরীণভাবে কী ঘটে এবং সেগুলোর সময় আপনাকে কী বাস্তবায়ন করতে হবে।
এরপর এটি অ্যাক্টিভিটি স্টেট এবং সিস্টেম দ্বারা কোনো প্রসেস বন্ধ হয়ে যাওয়ার ঝুঁকির মধ্যেকার সম্পর্কটি সংক্ষেপে তুলে ধরে। পরিশেষে, এটি অ্যাক্টিভিটি স্টেটগুলোর মধ্যে রূপান্তর সম্পর্কিত বিভিন্ন বিষয় নিয়ে আলোচনা করে।
লাইফসাইকেল পরিচালনা সম্পর্কে তথ্যের জন্য, যার মধ্যে সেরা অনুশীলন সম্পর্কিত নির্দেশিকাও রয়েছে, “Handling Lifecycles with Lifecycle-Aware Components” এবং “Save UI states” দেখুন। আর্কিটেকচার কম্পোনেন্টের সাথে অ্যাক্টিভিটি ব্যবহার করে কীভাবে একটি শক্তিশালী, প্রোডাকশন-মানের অ্যাপের আর্কিটেকচার তৈরি করতে হয় তা জানতে, “Guide to app architecture” দেখুন।
কার্যকলাপ-জীবনচক্র ধারণা
অ্যাক্টিভিটি লাইফসাইকেলের বিভিন্ন ধাপের মধ্যে পরিবর্তন আনার জন্য, Activity ক্লাসটি ছয়টি মূল কলব্যাক প্রদান করে: onCreate , onStart , onResume , onPause , onStop , এবং onDestroy । অ্যাক্টিভিটি যখনই একটি নতুন অবস্থায় প্রবেশ করে, সিস্টেম এই কলব্যাকগুলোর প্রত্যেকটিকে আহ্বান করে।
চিত্র ১-এ এই প্রতিমানটির একটি চাক্ষুষ উপস্থাপনা তুলে ধরা হয়েছে।

যখন ব্যবহারকারী অ্যাক্টিভিটিটি ছেড়ে যেতে শুরু করেন, তখন সিস্টেম অ্যাক্টিভিটিটি ভেঙে ফেলার জন্য বিভিন্ন মেথড কল করে। কিছু ক্ষেত্রে, অ্যাক্টিভিটিটি কেবল আংশিকভাবে ভেঙে ফেলা হয় এবং মেমরিতে থেকে যায়, যেমন যখন ব্যবহারকারী অন্য কোনো অ্যাপে চলে যান। এইসব ক্ষেত্রেও অ্যাক্টিভিটিটি আবার ফোরগ্রাউন্ডে ফিরে আসতে পারে।
যদি ব্যবহারকারী অ্যাক্টিভিটিতে ফিরে আসেন, তবে এটি সেখান থেকেই পুনরায় শুরু হয় যেখান থেকে তিনি শেষ করেছিলেন। কিছু ব্যতিক্রম ছাড়া, অ্যাপগুলো ব্যাকগ্রাউন্ডে চলার সময় অ্যাক্টিভিটি শুরু করতে পারে না ।
সিস্টেমের দ্বারা কোনো একটি নির্দিষ্ট প্রসেসকে, তার ভেতরের কার্যকলাপগুলোসহ, বন্ধ করে দেওয়ার সম্ভাবনা নির্ভর করে সেই সময়ে কার্যকলাপটির অবস্থার উপর। অবস্থা এবং বহিষ্কারের ঝুঁকির মধ্যে সম্পর্ক বিষয়ে আরও তথ্যের জন্য, কার্যকলাপের অবস্থা এবং মেমরি থেকে বহিষ্কার সম্পর্কিত বিভাগটি দেখুন।
আপনার কার্যকলাপের জটিলতার উপর নির্ভর করে, আপনার সম্ভবত সমস্ত লাইফসাইকেল মেথড প্রয়োগ করার প্রয়োজন নেই। তবে, প্রতিটি মেথড বোঝা এবং সেগুলোর বাস্তবায়ন করা গুরুত্বপূর্ণ, যা আপনার অ্যাপকে ব্যবহারকারীদের প্রত্যাশা অনুযায়ী কাজ করতে সাহায্য করে।
লাইফসাইকেল কলব্যাক
এই বিভাগে অ্যাক্টিভিটি লাইফসাইকেল চলাকালীন ব্যবহৃত কলব্যাক মেথডগুলো সম্পর্কে ধারণাগত এবং বাস্তবায়নগত তথ্য প্রদান করা হয়েছে।
কিছু অ্যাকশন অ্যাক্টিভিটি লাইফসাইকেল মেথডের অন্তর্ভুক্ত। তবে, কোনো ডিপেন্ডেন্ট কম্পোনেন্টের অ্যাকশনগুলো বাস্তবায়নকারী কোড অ্যাক্টিভিটি লাইফসাইকেল মেথডের পরিবর্তে কম্পোনেন্টটির মধ্যেই রাখুন। এটি করার জন্য, আপনাকে ডিপেন্ডেন্ট কম্পোনেন্টটিকে লাইফসাইকেল-অ্যাওয়ার করতে হবে। আপনার ডিপেন্ডেন্ট কম্পোনেন্টগুলোকে কীভাবে লাইফসাইকেল-অ্যাওয়ার করবেন তা জানতে, “Handling lifecycles with lifecycle-aware components” দেখুন।
onCreate
আপনাকে অবশ্যই এই কলব্যাকটি ইমপ্লিমেন্ট করতে হবে, যা সিস্টেম প্রথমবার অ্যাক্টিভিটি তৈরি করার সময় ফায়ার হয়। অ্যাক্টিভিটি তৈরি হওয়ার পর, এটি Created স্টেটে প্রবেশ করে। onCreate মেথডে, অ্যাপ্লিকেশনের প্রাথমিক স্টার্টআপ লজিক সম্পাদন করুন, যা অ্যাক্টিভিটির পুরো জীবনকালে শুধুমাত্র একবারই ঘটে।
উদাহরণস্বরূপ, আপনার onCreate এর ইমপ্লিমেন্টেশন লিস্টে ডেটা বাইন্ড করতে পারে, অ্যাক্টিভিটিকে একটি ViewModel সাথে যুক্ত করতে পারে এবং কিছু ক্লাস-স্কোপ ভেরিয়েবল ইনস্ট্যানশিয়েট করতে পারে। এই মেথডটি savedInstanceState প্যারামিটারটি গ্রহণ করে, যা একটি Bundle অবজেক্ট এবং এতে অ্যাক্টিভিটির পূর্বে সংরক্ষিত স্টেট থাকে। যদি অ্যাক্টিভিটিটি আগে কখনও বিদ্যমান না থাকে, তাহলে Bundle অবজেক্টটির মান null হয়।
আপনার যদি একটি লাইফসাইকেল-অ্যাওয়ার কম্পোনেন্ট থাকে যা আপনার অ্যাক্টিভিটির লাইফসাইকেলের সাথে সংযুক্ত, তবে এটি ON_CREATE ইভেন্টটি গ্রহণ করে। @OnLifecycleEvent দিয়ে অ্যানোটেট করা মেথডটি কল করা হয়, যাতে আপনার লাইফসাইকেল-অ্যাওয়ার কম্পোনেন্টটি তৈরি হওয়া অবস্থার জন্য প্রয়োজনীয় সেটআপ কোড সম্পাদন করতে পারে।
onCreate মেথডের নিম্নলিখিত উদাহরণটি অ্যাক্টিভিটির মৌলিক সেটআপ দেখায়, যেমন ইউজার ইন্টারফেস ঘোষণা করা (যা একটি XML লেআউট ফাইলে সংজ্ঞায়িত), মেম্বার ভেরিয়েবল নির্ধারণ করা এবং UI-এর কিছু অংশ কনফিগার করা। এই উদাহরণে, XML লেআউট ফাইলটি setContentView তে ফাইলের রিসোর্স আইডি R.layout.main_activity পাস করে।
কোটলিন
lateinit var textView: TextView
// Some transient state for the activity instance.
var gameState: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
// Call the superclass onCreate to complete the creation of
// the activity, like the view hierarchy.
super.onCreate(savedInstanceState)
// Recover the instance state.
gameState = savedInstanceState?.getString(GAME_STATE_KEY)
// Set the user interface layout for this activity.
// The layout is defined in the project res/layout/main_activity.xml file.
setContentView(R.layout.main_activity)
// Initialize member TextView so it is available later.
textView = findViewById(R.id.text_view)
}
// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}
// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
outState?.run {
putString(GAME_STATE_KEY, gameState)
putString(TEXT_VIEW_KEY, textView.text.toString())
}
// Call superclass to save any view hierarchy.
super.onSaveInstanceState(outState)
}
জাভা
TextView textView;
// Some transient state for the activity instance.
String gameState;
@Override
public void onCreate(Bundle savedInstanceState) {
// Call the superclass onCreate to complete the creation of
// the activity, like the view hierarchy.
super.onCreate(savedInstanceState);
// Recover the instance state.
if (savedInstanceState != null) {
gameState = savedInstanceState.getString(GAME_STATE_KEY);
}
// Set the user interface layout for this activity.
// The layout is defined in the project res/layout/main_activity.xml file.
setContentView(R.layout.main_activity);
// Initialize member TextView so it is available later.
textView = (TextView) findViewById(R.id.text_view);
}
// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}
// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(GAME_STATE_KEY, gameState);
outState.putString(TEXT_VIEW_KEY, textView.getText());
// Call superclass to save any view hierarchy.
super.onSaveInstanceState(outState);
}
XML ফাইল সংজ্ঞায়িত করে setContentView তে পাস করার বিকল্প হিসেবে, আপনি আপনার অ্যাক্টিভিটি কোডে নতুন View অবজেক্ট তৈরি করতে পারেন এবং একটি ViewGroup মধ্যে নতুন View অবজেক্টগুলো সন্নিবেশ করে একটি ভিউ হায়ারার্কি তৈরি করতে পারেন। এরপর আপনি রুট ViewGroup টিকে setContentView তে পাস করে সেই লেআউটটি ব্যবহার করতে পারেন। ইউজার ইন্টারফেস তৈরি করার বিষয়ে আরও তথ্যের জন্য, ইউজার ইন্টারফেস ডকুমেন্টেশন দেখুন।
আপনার অ্যাক্টিভিটি Created অবস্থায় থাকে না। onCreate মেথডটির এক্সিকিউশন শেষ হওয়ার পর, অ্যাক্টিভিটিটি Started অবস্থায় প্রবেশ করে এবং সিস্টেম দ্রুত পরপর onStart ও onResume মেথডগুলোকে কল করে।
শুরুতে
যখন অ্যাক্টিভিটি 'Started' অবস্থায় প্রবেশ করে, তখন সিস্টেম onStart কল করে। এই কলটি অ্যাক্টিভিটিকে ব্যবহারকারীর কাছে দৃশ্যমান করে তোলে, কারণ অ্যাপটি অ্যাক্টিভিটিকে ফোরগ্রাউন্ডে এনে ইন্টারেক্টিভ করার জন্য প্রস্তুত হয়। উদাহরণস্বরূপ, এই মেথডেই UI রক্ষণাবেক্ষণকারী কোড ইনিশিয়ালাইজ করা হয়।
যখন অ্যাক্টিভিটিটি Started অবস্থায় চলে যায়, তখন অ্যাক্টিভিটির লাইফসাইকেলের সাথে যুক্ত যেকোনো লাইফসাইকেল-সচেতন কম্পোনেন্ট ON_START ইভেন্টটি গ্রহণ করে।
onStart মেথডটি দ্রুত সম্পন্ন হয় এবং Created অবস্থার মতোই, অ্যাক্টিভিটিটি Started অবস্থায় থাকে না। এই কলব্যাকটি শেষ হয়ে গেলে, অ্যাক্টিভিটিটি Resumed অবস্থায় প্রবেশ করে এবং সিস্টেম onResume মেথডটিকে কল করে।
রিজুমে
যখন অ্যাক্টিভিটিটি 'Resumed' অবস্থায় প্রবেশ করে, তখন এটি ফোরগ্রাউন্ডে চলে আসে এবং সিস্টেম onResume কলব্যাকটি কল করে। এই অবস্থাতেই অ্যাপটি ব্যবহারকারীর সাথে যোগাযোগ করে। অ্যাপটি এই অবস্থায় ততক্ষণ থাকে যতক্ষণ না এমন কিছু ঘটে যা অ্যাপটি থেকে ফোকাস সরিয়ে নেয়, যেমন ডিভাইসে ফোন কল আসা, ব্যবহারকারী অন্য কোনো অ্যাক্টিভিটিতে চলে যাওয়া, বা ডিভাইসের স্ক্রিন বন্ধ হয়ে যাওয়া।
যখন অ্যাক্টিভিটিটি 'Resumed' অবস্থায় চলে যায়, তখন অ্যাক্টিভিটির লাইফসাইকেলের সাথে যুক্ত যেকোনো লাইফসাইকেল-সচেতন কম্পোনেন্ট ' ON_RESUME ইভেন্টটি গ্রহণ করে। এই পর্যায়ে লাইফসাইকেল কম্পোনেন্টগুলো এমন যেকোনো কার্যকারিতা চালু করতে পারে যা কম্পোনেন্টটি দৃশ্যমান এবং ফোরগ্রাউন্ডে থাকা অবস্থায় চালানো প্রয়োজন, যেমন ক্যামেরা প্রিভিউ শুরু করা।
যখন কোনো বিঘ্নকারী ঘটনা ঘটে, তখন অ্যাক্টিভিটিটি Paused অবস্থায় প্রবেশ করে এবং সিস্টেম onPause কলব্যাকটি চালু করে।
যদি অ্যাক্টিভিটিটি Paused অবস্থা থেকে Resumed অবস্থায় ফিরে আসে, তাহলে সিস্টেম পুনরায় onResume মেথডটি কল করে। এই কারণে, onPause চলাকালীন রিলিজ করা কম্পোনেন্টগুলো ইনিশিয়ালাইজ করতে এবং প্রতিবার অ্যাক্টিভিটি Resumed অবস্থায় প্রবেশ করার সময় আবশ্যক এমন অন্যান্য ইনিশিয়ালাইজেশনগুলো সম্পাদন করতে onResume ইমপ্লিমেন্ট করুন।
এখানে একটি লাইফসাইকেল-সচেতন কম্পোনেন্টের উদাহরণ দেওয়া হলো, যেটি ON_RESUME ইভেন্টটি পেলে ক্যামেরা অ্যাক্সেস করে:
কোটলিন
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
...
}
জাভা
public class CameraComponent implements LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void initializeCamera() {
if (camera == null) {
getCamera();
}
}
...
}
পূর্ববর্তী কোডটি ক্যামেরা চালু করে যখন LifecycleObserver ON_RESUME ইভেন্টটি গ্রহণ করে। তবে, মাল্টি-উইন্ডো মোডে আপনার অ্যাক্টিভিটি Paused অবস্থায় থাকলেও সম্পূর্ণরূপে দৃশ্যমান হতে পারে। উদাহরণস্বরূপ, যখন অ্যাপটি মাল্টি-উইন্ডো মোডে থাকে এবং ব্যবহারকারী এমন একটি উইন্ডোতে ট্যাপ করেন যেখানে আপনার অ্যাক্টিভিটি নেই, তখন আপনার অ্যাক্টিভিটি Paused অবস্থায় চলে যায়।
আপনি যদি চান যে অ্যাপটি শুধুমাত্র পুনরায় চালু (ফোরগ্রাউন্ডে দৃশ্যমান ও সক্রিয়) হওয়ার সময় ক্যামেরাটি সক্রিয় থাকুক, তাহলে পূর্বে প্রদর্শিত ON_RESUME ইভেন্টের পরে ক্যামেরাটি ইনিশিয়ালাইজ করুন। আর যদি আপনি চান যে অ্যাক্টিভিটিটি পজ করা অবস্থায় কিন্তু দৃশ্যমান থাকা সত্ত্বেও, যেমন মাল্টি-উইন্ডো মোডে, ক্যামেরাটি সক্রিয় থাকুক, তাহলে ON_START ইভেন্টের পরে ক্যামেরাটি ইনিশিয়ালাইজ করুন।
তবে, আপনার অ্যাক্টিভিটি পজ করা অবস্থায় ক্যামেরা চালু রাখলে, মাল্টি-উইন্ডো মোডে অন্য কোনো রিজুম করা অ্যাপ ক্যামেরা ব্যবহার করতে নাও পারতে পারে। কখনও কখনও আপনার অ্যাক্টিভিটি পজ করা অবস্থায় ক্যামেরা চালু রাখা প্রয়োজন হয়, কিন্তু তা করলে সার্বিক ইউজার এক্সপেরিয়েন্সের অবনতি ঘটতে পারে।
এই কারণে, মাল্টি-উইন্ডো মোডের প্রেক্ষাপটে লাইফসাইকেলের কোন পর্যায়ে শেয়ার করা সিস্টেম রিসোর্সগুলোর নিয়ন্ত্রণ নেওয়া সবচেয়ে উপযুক্ত হবে, সে বিষয়ে সাবধানে চিন্তা করুন। মাল্টি-উইন্ডো মোড সমর্থন করা সম্পর্কে আরও জানতে, “মাল্টি-উইন্ডো মোড সমর্থন করুন” দেখুন।
আপনি ইনিশিয়ালাইজেশন অপারেশন সম্পাদনের জন্য যে বিল্ড-আপ ইভেন্টই বেছে নিন না কেন, রিসোর্সটি রিলিজ করার জন্য সংশ্লিষ্ট লাইফসাইকেল ইভেন্টটি ব্যবহার করতে ভুলবেন না। যদি আপনি ON_START ইভেন্টের পরে কিছু ইনিশিয়ালাইজ করেন, তবে ON_STOP ইভেন্টের পরে তা রিলিজ বা টার্মিনেট করুন। যদি আপনি ON_RESUME ইভেন্টের পরে ইনিশিয়ালাইজ করেন, তবে ON_PAUSE ইভেন্টের পরে তা রিলিজ করুন।
The preceding code snippet places camera initialization code in a lifecycle-aware component. You can instead put this code directly into the activity lifecycle callbacks, such as onStart and onStop , but we don't recommend this. Adding this logic to an independent, lifecycle-aware component lets you reuse the component across multiple activities without having to duplicate code. To learn how to create a lifecycle-aware component, see Handling lifecycles with lifecycle-aware components (Views) .
বিরতিতে
ব্যবহারকারী আপনার অ্যাক্টিভিটি ছেড়ে যাচ্ছেন, এটি বোঝানোর প্রথম ইঙ্গিত হিসেবে সিস্টেম এই মেথডটিকে কল করে, যদিও এর মানে এই নয় যে অ্যাক্টিভিটিটি সবসময় ধ্বংস হয়ে যাচ্ছে। এটি নির্দেশ করে যে অ্যাক্টিভিটিটি আর ফোরগ্রাউন্ডে নেই, কিন্তু ব্যবহারকারী মাল্টি-উইন্ডো মোডে থাকলে এটি তখনও দৃশ্যমান থাকে। একটি অ্যাক্টিভিটি বিভিন্ন কারণে এই অবস্থায় প্রবেশ করতে পারে:
-
onResumeকলব্যাক সম্পর্কিত অংশে যেমন বর্ণনা করা হয়েছে, যে ইভেন্ট অ্যাপের কার্য সম্পাদনে বাধা দেয়, তা বর্তমান অ্যাক্টিভিটিকে থামিয়ে দেয়। এটিই সবচেয়ে সাধারণ পরিস্থিতি। - মাল্টি-উইন্ডো মোডে, যেকোনো সময়ে শুধুমাত্র একটি অ্যাপ ফোকাসে থাকে এবং সিস্টেম অন্য সব অ্যাপকে বিরতি দেয়।
- একটি নতুন, আধা-স্বচ্ছ কার্যকলাপ, যেমন একটি সংলাপ, চালু হলে তার দ্বারা আবৃত কার্যকলাপটি থেমে যায়। যতক্ষণ কার্যকলাপটি আংশিকভাবে দৃশ্যমান থাকে কিন্তু ফোকাসে না থাকে, ততক্ষণ এটি থেমে থাকা অবস্থায় থাকে।
যখন কোনো অ্যাক্টিভিটি Paused অবস্থায় চলে যায়, তখন অ্যাক্টিভিটিটির লাইফসাইকেলের সাথে যুক্ত যেকোনো লাইফসাইকেল-সচেতন কম্পোনেন্ট ON_PAUSE ইভেন্টটি গ্রহণ করে। এই পর্যায়ে লাইফসাইকেল কম্পোনেন্টগুলো এমন যেকোনো কার্যকারিতা বন্ধ করতে পারে যা কম্পোনেন্টটি ফোরগ্রাউন্ডে না থাকা অবস্থায় চলার প্রয়োজন নেই, যেমন ক্যামেরা প্রিভিউ বন্ধ করা।
Activity টি Paused অবস্থায় থাকাকালীন যে অপারেশনগুলো চালিয়ে যাওয়া সম্ভব নয়, বা সীমিত আকারে চলতে পারে এবং যা আপনি শীঘ্রই পুনরায় চালু করবেন বলে আশা করেন, সেগুলোকে থামাতে বা সামঞ্জস্য করতে onPause মেথডটি ব্যবহার করুন।
আপনার অ্যাক্টিভিটি পজ করা অবস্থায় এবং ব্যবহারকারীর প্রয়োজন না থাকলে, সিস্টেম রিসোর্স, সেন্সরের হ্যান্ডেল (যেমন GPS) বা ব্যাটারির আয়ু প্রভাবিত করে এমন যেকোনো রিসোর্স মুক্ত করতেও আপনি onPause মেথডটি ব্যবহার করতে পারেন।
তবে, onResume সম্পর্কিত অংশে যেমন উল্লেখ করা হয়েছে, অ্যাপটি মাল্টি-উইন্ডো মোডে থাকলে একটি Paused অ্যাক্টিভিটি তখনও সম্পূর্ণরূপে দৃশ্যমান থাকতে পারে। মাল্টি-উইন্ডো মোডকে আরও ভালোভাবে সাপোর্ট করার জন্য UI-সম্পর্কিত রিসোর্স এবং অপারেশনগুলোকে সম্পূর্ণরূপে রিলিজ বা অ্যাডজাস্ট করতে onPause এর পরিবর্তে onStop ব্যবহার করার কথা বিবেচনা করুন।
ON_PAUSE ইভেন্টের প্রতি সাড়া দেওয়া একটি LifecycleObserver এর নিম্নলিখিত উদাহরণটি পূর্ববর্তী ON_RESUME ইভেন্টের উদাহরণের প্রতিরূপ, যা ON_RESUME ইভেন্টটি পাওয়ার পর ইনিশিয়ালাইজ হওয়া ক্যামেরাটিকে মুক্ত করে দেয়:
কোটলিন
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun releaseCamera() {
camera?.release()
camera = null
}
...
}
জাভা
public class JavaCameraComponent implements LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void releaseCamera() {
if (camera != null) {
camera.release();
camera = null;
}
}
...
}
এই উদাহরণে, LifecycleObserver এর কাছে ON_PAUSE ইভেন্টটি পৌঁছানোর পরে ক্যামেরা রিলিজ কোডটি রাখা হয়।
onPause এক্সিকিউশন খুবই সংক্ষিপ্ত এবং এটি সেভ অপারেশন সম্পন্ন করার জন্য যথেষ্ট সময় নাও দিতে পারে। এই কারণে, অ্যাপ্লিকেশন বা ইউজার ডেটা সেভ করতে, নেটওয়ার্ক কল করতে, বা ডাটাবেস ট্রানজ্যাকশন সম্পাদন করতে onPause ব্যবহার করবেন না । এই ধরনের কাজ মেথডটি শেষ হওয়ার আগেই হয়তো সম্পূর্ণ নাও হতে পারে।
এর পরিবর্তে, onStop চলাকালীন ভারী-লোড শাটডাউন অপারেশনগুলি সম্পাদন করুন। onStop চলাকালীন সম্পাদন করার জন্য উপযুক্ত অপারেশনগুলি সম্পর্কে আরও তথ্যের জন্য, পরবর্তী বিভাগটি দেখুন। ডেটা সংরক্ষণ সম্পর্কে আরও তথ্যের জন্য, স্টেট সংরক্ষণ এবং পুনরুদ্ধার সম্পর্কিত বিভাগটি দেখুন।
onPause মেথডটি সম্পন্ন হওয়ার অর্থ এই নয় যে অ্যাক্টিভিটিটি Paused অবস্থা থেকে বেরিয়ে আসে। বরং, অ্যাক্টিভিটিটি এই অবস্থাতেই থাকে যতক্ষণ না এটি পুনরায় চালু হয় অথবা ব্যবহারকারীর কাছে সম্পূর্ণরূপে অদৃশ্য হয়ে যায়। যদি অ্যাক্টিভিটিটি পুনরায় চালু হয়, তবে সিস্টেমটি আবার onResume কলব্যাকটি আহ্বান করে।
যদি অ্যাক্টিভিটিটি Paused অবস্থা থেকে Resumed অবস্থায় ফিরে আসে, তাহলে সিস্টেম Activity ইনস্ট্যান্সটিকে মেমরিতে স্থায়ী রাখে এবং যখন সিস্টেম onResume কল করে তখন সেই ইনস্ট্যান্সটিকে পুনরায় কল করে। এই পরিস্থিতিতে, Resumed অবস্থায় যাওয়ার আগে পর্যন্ত কোনো কলব্যাক মেথডের সময় তৈরি হওয়া কম্পোনেন্টগুলোকে পুনরায় ইনিশিয়ালাইজ করার প্রয়োজন হয় না। যদি অ্যাক্টিভিটিটি সম্পূর্ণরূপে অদৃশ্য হয়ে যায়, তাহলে সিস্টেম onStop কল করে।
অনস্টপ
যখন আপনার অ্যাক্টিভিটি ব্যবহারকারীর কাছে আর দৃশ্যমান থাকে না, তখন এটি 'Stopped ' অবস্থায় প্রবেশ করে এবং সিস্টেম onStop কলব্যাকটি কল করে। এটি তখন ঘটতে পারে যখন সদ্য চালু হওয়া কোনো অ্যাক্টিভিটি পুরো স্ক্রিন জুড়ে থাকে। অ্যাক্টিভিটিটির চলমান কাজ শেষ হয়ে গেলে এবং এটি বন্ধ হওয়ার ঠিক আগেও সিস্টেম onStop কল করে।
যখন অ্যাক্টিভিটিটি Stopped অবস্থায় চলে যায়, তখন অ্যাক্টিভিটির লাইফসাইকেলের সাথে যুক্ত যেকোনো লাইফসাইকেল-সচেতন কম্পোনেন্ট ON_STOP ইভেন্টটি গ্রহণ করে। এই পর্যায়ে লাইফসাইকেল কম্পোনেন্টগুলো এমন যেকোনো কার্যকারিতা বন্ধ করতে পারে, যা কম্পোনেন্টটি স্ক্রিনে দৃশ্যমান না থাকা অবস্থায় চালানোর প্রয়োজন নেই।
onStop মেথডে, সেইসব রিসোর্স রিলিজ বা অ্যাডজাস্ট করা হয় যেগুলো ব্যবহারকারীর কাছে অ্যাপটি অদৃশ্য থাকার সময় প্রয়োজন হয় না। উদাহরণস্বরূপ, আপনার অ্যাপ অ্যানিমেশন পজ করতে পারে অথবা ফাইন-গ্রেইনড থেকে কোর্স-গ্রেইনড লোকেশন আপডেটে পরিবর্তন করতে পারে। onPause এর পরিবর্তে onStop ব্যবহার করার অর্থ হলো, ব্যবহারকারী যখন আপনার অ্যাক্টিভিটি মাল্টি-উইন্ডো মোডে দেখছেন, তখনও UI-সম্পর্কিত কাজ চলতে থাকে।
এছাড়াও, তুলনামূলকভাবে সিপিইউ-এর উপর বেশি চাপ সৃষ্টিকারী শাটডাউন অপারেশনগুলো সম্পাদন করতে onStop ব্যবহার করুন। উদাহরণস্বরূপ, যদি আপনি কোনো ডেটাবেসে তথ্য সংরক্ষণ করার জন্য এর চেয়ে ভালো সময় খুঁজে না পান, তাহলে আপনি onStop চলাকালীন তা করতে পারেন। নিম্নলিখিত উদাহরণটি onStop এর একটি বাস্তবায়ন দেখায় যা একটি ড্রাফট নোটের বিষয়বস্তু পারসিস্টেন্ট স্টোরেজে সংরক্ষণ করে:
কোটলিন
override fun onStop() {
// Call the superclass method first.
super.onStop()
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
val values = ContentValues().apply {
put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
}
// Do this update in background on an AsyncQueryHandler or equivalent.
asyncQueryHandler.startUpdate(
token, // int token to correlate calls
null, // cookie, not used here
uri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
)
}
জাভা
@Override
protected void onStop() {
// Call the superclass method first.
super.onStop();
// Save the note's current draft, because the activity is stopping
// and we want to be sure the current note progress isn't lost.
ContentValues values = new ContentValues();
values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());
// Do this update in background on an AsyncQueryHandler or equivalent.
asyncQueryHandler.startUpdate (
mToken, // int token to correlate calls
null, // cookie, not used here
uri, // The URI for the note to update.
values, // The map of column names and new values to apply to them.
null, // No SELECT criteria are used.
null // No WHERE columns are used.
);
}
পূর্ববর্তী কোড স্যাম্পলটিতে সরাসরি SQLite ব্যবহার করা হয়েছে। তবে, আমরা Room ব্যবহারের পরামর্শ দিই, যা SQLite-এর উপর একটি অ্যাবস্ট্রাকশন লেয়ার প্রদানকারী একটি পার্সিস্টেন্স লাইব্রেরি। Room ব্যবহারের সুবিধা এবং আপনার অ্যাপে কীভাবে Room প্রয়োগ করবেন সে সম্পর্কে আরও জানতে, Room পার্সিস্টেন্স লাইব্রেরি গাইডটি দেখুন।
যখন আপনার অ্যাক্টিভিটি 'Stopped' অবস্থায় প্রবেশ করে, তখন ' Activity ' অবজেক্টটি মেমরিতে স্থায়ী থাকে: এটি তার সমস্ত অবস্থা এবং সদস্যের তথ্য বজায় রাখে, কিন্তু উইন্ডো ম্যানেজারের সাথে সংযুক্ত থাকে না। যখন অ্যাক্টিভিটি পুনরায় চালু হয়, তখন এটি এই তথ্যগুলো পুনরুদ্ধার করে।
Resumed স্টেটে পৌঁছানোর আগে কোনো কলব্যাক মেথডের সময় তৈরি হওয়া কম্পোনেন্টগুলোকে পুনরায় ইনিশিয়ালাইজ করার প্রয়োজন নেই। সিস্টেমটি লেআউটের প্রতিটি View অবজেক্টের বর্তমান স্টেটও ট্র্যাক করে রাখে, তাই যদি ব্যবহারকারী একটি EditText উইজেটে টেক্সট প্রবেশ করান, সেই কন্টেন্টটি সংরক্ষিত থাকে, ফলে আপনাকে তা সেভ এবং রিস্টোর করার প্রয়োজন হয় না।
Stopped অবস্থা থেকে, অ্যাক্টিভিটিটি হয় ব্যবহারকারীর সাথে যোগাযোগ করার জন্য ফিরে আসে, অথবা এর কাজ শেষ হয়ে যায় এবং এটি চলে যায়। যদি অ্যাক্টিভিটিটি ফিরে আসে, সিস্টেম onRestart কল করে। যদি Activity শেষ হয়ে যায়, সিস্টেম onDestroy কল করে।
ধ্বংস করুন
অ্যাক্টিভিটি ধ্বংস হওয়ার আগে onDestroy কল করা হয়। সিস্টেম দুটি কারণের একটির জন্য এই কলব্যাকটি আহ্বান করে:
- ব্যবহারকারী অ্যাক্টিভিটিটি সম্পূর্ণরূপে বাতিল করে দেওয়ায় অথবা অ্যাক্টিভিটিটিতে '
finish(finish) কল করা হওয়ায় অ্যাক্টিভিটিটি সমাপ্ত হচ্ছে। - ডিভাইস ঘোরানো বা মাল্টি-উইন্ডো মোডে প্রবেশের মতো কনফিগারেশন পরিবর্তনের কারণে সিস্টেমটি সাময়িকভাবে কার্যক্রমটি বন্ধ করে দিচ্ছে।
যখন অ্যাক্টিভিটিটি ডেস্ট্রয়েড (destroyed) অবস্থায় চলে যায়, তখন অ্যাক্টিভিটির লাইফসাইকেলের সাথে যুক্ত যেকোনো লাইফসাইকেল-অ্যাওয়ার (lifecycle-aware) কম্পোনেন্ট ON_DESTROY ইভেন্টটি গ্রহণ করে। এখানেই লাইফসাইকেল কম্পোনেন্টগুলো Activity ডেস্ট্রয় হওয়ার আগে তাদের প্রয়োজনীয় সবকিছু গুছিয়ে নিতে পারে।
Instead of putting logic in your Activity to determine why it is being destroyed, use a ViewModel object to contain the relevant view data for your Activity . If the Activity is recreated due to a configuration change, the ViewModel does not have to do anything, since it is preserved and given to the next Activity instance.
যদি Activity পুনরায় তৈরি না করা হয়, তাহলে ViewModel এর onCleared মেথডটি কল করা হয়, যেখানে এটি ধ্বংস হওয়ার আগে প্রয়োজনীয় ডেটা পরিষ্কার করে নিতে পারে। আপনি isFinishing মেথডের মাধ্যমে এই দুটি পরিস্থিতির মধ্যে পার্থক্য করতে পারেন।
অ্যাক্টিভিটিটি শেষ হওয়ার সময়, onDestroy হলো অ্যাক্টিভিটিটির প্রাপ্ত সর্বশেষ লাইফসাইকেল কলব্যাক। যদি কোনো কনফিগারেশন পরিবর্তনের ফলে onDestroy কল করা হয়, তাহলে সিস্টেম অবিলম্বে একটি নতুন অ্যাক্টিভিটি ইনস্ট্যান্স তৈরি করে এবং তারপর নতুন কনফিগারেশনে সেই নতুন ইনস্ট্যান্সটিতে onCreate কল করে।
onDestroy কলব্যাকটি onStop মতো পূর্ববর্তী কলব্যাক দ্বারা মুক্ত না হওয়া সমস্ত রিসোর্স মুক্ত করে।
অস্থায়ী UI অবস্থা সংরক্ষণ এবং পুনরুদ্ধার করা
একজন ব্যবহারকারী আশা করেন যে, রোটেশন বা মাল্টি-উইন্ডো মোডে স্যুইচ করার মতো কোনো কনফিগারেশন পরিবর্তনের সময়ও একটি অ্যাক্টিভিটির UI স্টেট একই থাকবে। কিন্তু, এই ধরনের কনফিগারেশন পরিবর্তন ঘটলে সিস্টেম ডিফল্টভাবে অ্যাক্টিভিটিটি ডেস্ট্রয় করে দেয়, যার ফলে অ্যাক্টিভিটি ইনস্ট্যান্সে সংরক্ষিত সমস্ত UI স্টেট মুছে যায়।
একইভাবে, একজন ব্যবহারকারী আশা করেন যে তিনি যদি সাময়িকভাবে আপনার অ্যাপ থেকে অন্য কোনো অ্যাপে চলে যান এবং পরে আবার আপনার অ্যাপে ফিরে আসেন, তাহলে UI-এর অবস্থা একই থাকবে। তবে, ব্যবহারকারী যখন দূরে থাকেন এবং আপনার অ্যাক্টিভিটি বন্ধ থাকে, তখন সিস্টেম আপনার অ্যাপ্লিকেশনের প্রসেসটি বন্ধ করে দিতে পারে।
যখন সিস্টেমের সীমাবদ্ধতার কারণে অ্যাক্টিভিটিটি বন্ধ হয়ে যায়, তখন ViewModel , onSaveInstanceState এবং/অথবা লোকাল স্টোরেজের সমন্বয়ে ব্যবহারকারীর ক্ষণস্থায়ী UI স্টেট সংরক্ষণ করুন। সিস্টেমের আচরণের তুলনায় ব্যবহারকারীর প্রত্যাশা এবং সিস্টেম-চালিত অ্যাক্টিভিটি ও প্রসেস বন্ধ হয়ে যাওয়ার পরেও কীভাবে জটিল UI স্টেট ডেটা সবচেয়ে ভালোভাবে সংরক্ষণ করা যায়, সে সম্পর্কে আরও জানতে "Save UI states" দেখুন।
এই বিভাগে ইনস্ট্যান্স স্টেট কী এবং কীভাবে onSaveInstance মেথডটি প্রয়োগ করতে হয়, যা অ্যাক্টিভিটির নিজস্ব একটি কলব্যাক, তা বর্ণনা করা হয়েছে। যদি আপনার UI ডেটা হালকা হয়, তাহলে কনফিগারেশন পরিবর্তন এবং সিস্টেম-জনিত প্রসেস বন্ধ হয়ে যাওয়া—উভয় ক্ষেত্রেই UI স্টেট ধরে রাখার জন্য আপনি শুধু onSaveInstance ব্যবহার করতে পারেন। কিন্তু যেহেতু onSaveInstance জন্য সিরিয়ালাইজেশন/ডিসেরিয়ালাইজেশন খরচ হয়, তাই বেশিরভাগ ক্ষেত্রে ViewModel এবং onSaveInstance উভয়ই ব্যবহার করা হয়, যেমনটি "UI স্টেট সংরক্ষণ করুন" অংশে বর্ণনা করা হয়েছে।
ইনস্ট্যান্স অবস্থা
There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button or your activity signals its own destruction by calling the finish method.
যখন ব্যবহারকারী 'ব্যাক' চাপেন বা অ্যাক্টিভিটিটি নিজে থেকেই শেষ হয়ে যায়, তখন সিস্টেম এবং ব্যবহারকারী উভয়ের কাছেই সেই Activity ইনস্ট্যান্সটির ধারণা চিরতরে বিলুপ্ত হয়ে যায়। এই পরিস্থিতিতে, ব্যবহারকারীর প্রত্যাশা সিস্টেমের আচরণের সাথে মিলে যায় এবং আপনাকে কোনো অতিরিক্ত কাজ করতে হয় না।
তবে, সিস্টেমের সীমাবদ্ধতার কারণে (যেমন কনফিগারেশন পরিবর্তন বা মেমরির চাপ) যদি সিস্টেম অ্যাক্টিভিটিটি ধ্বংস করে দেয়, তাহলে Activity আসল ইনস্ট্যান্সটি মুছে গেলেও সিস্টেম মনে রাখে যে এটির অস্তিত্ব ছিল। যদি ব্যবহারকারী অ্যাক্টিভিটিটিতে ফিরে যাওয়ার চেষ্টা করেন, তবে সিস্টেম এক সেট সংরক্ষিত ডেটা ব্যবহার করে সেই অ্যাক্টিভিটির একটি নতুন ইনস্ট্যান্স তৈরি করে, যা অ্যাক্টিভিটিটি ধ্বংস হওয়ার সময়কার অবস্থা বর্ণনা করে।
সিস্টেম পূর্ববর্তী অবস্থা পুনরুদ্ধার করতে যে সংরক্ষিত ডেটা ব্যবহার করে, তাকে ইনস্ট্যান্স স্টেট বলা হয়। এটি একটি Bundle ) অবজেক্টে সংরক্ষিত কী-ভ্যালু পেয়ারের একটি সংগ্রহ। ডিফল্টরূপে, সিস্টেম আপনার অ্যাক্টিভিটি লেআউটের প্রতিটি View ) অবজেক্ট সম্পর্কিত তথ্য সংরক্ষণ করতে Bundle ইনস্ট্যান্স স্টেট ব্যবহার করে, যেমন একটি EditText উইজেটে প্রবেশ করানো টেক্সট ভ্যালু।
সুতরাং, যদি আপনার অ্যাক্টিভিটি ইনস্ট্যান্সটি ধ্বংস করে পুনরায় তৈরি করা হয়, তাহলে আপনার কোনো কোড ছাড়াই লেআউটের অবস্থা তার পূর্বের অবস্থায় ফিরে আসে। তবে, আপনার অ্যাক্টিভিটিতে আরও কিছু স্টেট তথ্য থাকতে পারে যা আপনি পুনরুদ্ধার করতে চাইতে পারেন, যেমন মেম্বার ভেরিয়েবল যা অ্যাক্টিভিটিতে ব্যবহারকারীর অগ্রগতি ট্র্যাক করে।
সামান্য পরিমাণ ডেটার চেয়ে বেশি ডেটা সংরক্ষণের জন্য একটি Bundle অবজেক্ট উপযুক্ত নয়, কারণ এর জন্য মেইন থ্রেডে সিরিয়ালাইজেশন প্রয়োজন হয় এবং এটি সিস্টেম-প্রসেস মেমরি ব্যবহার করে। খুব অল্প পরিমাণের চেয়ে বেশি ডেটা সংরক্ষণ করতে, ডেটা সংরক্ষণের জন্য একটি সমন্বিত পদ্ধতি গ্রহণ করুন, যেমন—পার্সিস্টেন্ট লোকাল স্টোরেজ, onSaveInstanceState মেথড এবং ViewModel ক্লাস ব্যবহার করা, যা "Save UI states" অংশে বর্ণিত হয়েছে।
onSaveInstanceState ব্যবহার করে সহজ, হালকা UI স্টেট সংরক্ষণ করুন
আপনার অ্যাক্টিভিটি যখন বন্ধ হতে শুরু করে, তখন সিস্টেম onSaveInstanceState মেথডটিকে কল করে, যাতে আপনার অ্যাক্টিভিটি একটি ইনস্ট্যান্স স্টেট বান্ডেলে স্টেটের তথ্য সংরক্ষণ করতে পারে। এই মেথডের ডিফল্ট ইমপ্লিমেন্টেশনটি অ্যাক্টিভিটির ভিউ হায়ারার্কির অবস্থা সম্পর্কিত ক্ষণস্থায়ী তথ্য সংরক্ষণ করে, যেমন একটি EditText উইজেটের টেক্সট অথবা একটি ListView উইজেটের স্ক্রল পজিশন।
আপনার অ্যাক্টিভিটির জন্য অতিরিক্ত ইনস্ট্যান্স স্টেট তথ্য সংরক্ষণ করতে, onSaveInstanceState ওভাররাইড করুন এবং Bundle অবজেক্টে কী-ভ্যালু পেয়ার যোগ করুন, যা আপনার অ্যাক্টিভিটি অপ্রত্যাশিতভাবে ধ্বংস হয়ে গেলে সংরক্ষিত হয়। যখন আপনি onSaveInstanceState ওভাররাইড করবেন, তখন যদি আপনি চান যে ডিফল্ট ইমপ্লিমেন্টেশন ভিউ হায়ারার্কির স্টেট সংরক্ষণ করুক, তাহলে আপনাকে সুপারক্লাস ইমপ্লিমেন্টেশন কল করতে হবে। এটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
override fun onSaveInstanceState(outState: Bundle?) {
// Save the user's current game state.
outState?.run {
putInt(STATE_SCORE, currentScore)
putInt(STATE_LEVEL, currentLevel)
}
// Always call the superclass so it can save the view hierarchy state.
super.onSaveInstanceState(outState)
}
companion object {
val STATE_SCORE = "playerScore"
val STATE_LEVEL = "playerLevel"
}
জাভা
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state.
savedInstanceState.putInt(STATE_SCORE, currentScore);
savedInstanceState.putInt(STATE_LEVEL, currentLevel);
// Always call the superclass so it can save the view hierarchy state.
super.onSaveInstanceState(savedInstanceState);
}
ব্যবহারকারীর পছন্দ বা ডাটাবেসের ডেটার মতো স্থায়ী ডেটা সংরক্ষণ করতে, আপনার অ্যাক্টিভিটি যখন ফোরগ্রাউন্ডে থাকে তখন উপযুক্ত সুযোগ নিন। যদি এমন কোনো সুযোগ না আসে, তাহলে onStop মেথডের সময় স্থায়ী ডেটা সংরক্ষণ করুন।
সংরক্ষিত ইনস্ট্যান্স স্টেট ব্যবহার করে অ্যাক্টিভিটি UI স্টেট পুনরুদ্ধার করুন
আপনার অ্যাক্টিভিটি পূর্বে ধ্বংস হয়ে যাওয়ার পর যখন পুনরায় তৈরি করা হয়, তখন সিস্টেম আপনার অ্যাক্টিভিটিতে যে Bundle পাঠায়, তা থেকে আপনি আপনার সংরক্ষিত ইনস্ট্যান্স স্টেট পুনরুদ্ধার করতে পারেন। onCreate এবং onRestoreInstanceState উভয় কলব্যাক মেথডই একই Bundle গ্রহণ করে, যেটিতে ইনস্ট্যান্স স্টেটের তথ্য থাকে।
যেহেতু সিস্টেম আপনার অ্যাক্টিভিটির একটি নতুন ইনস্ট্যান্স তৈরি করুক বা আগেরটি পুনরায় তৈরি করুক, উভয় ক্ষেত্রেই onCreate মেথডটি কল করা হয়, তাই state Bundle পড়ার চেষ্টা করার আগে আপনাকে যাচাই করতে হবে যে সেটি null কি না। যদি এটি null হয়, তাহলে সিস্টেমটি ধ্বংস হয়ে যাওয়া আগের ইনস্ট্যান্সটি পুনরুদ্ধার না করে, অ্যাক্টিভিটির একটি নতুন ইনস্ট্যান্স তৈরি করছে।
নিম্নলিখিত কোড স্নিপেটটি দেখায় কিভাবে আপনি onCreate এ কিছু স্টেট ডেটা পুনরুদ্ধার করতে পারেন:
কোটলিন
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) // Always call the superclass first
// Check whether we're recreating a previously destroyed instance.
if (savedInstanceState != null) {
with(savedInstanceState) {
// Restore value of members from saved state.
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
} else {
// Probably initialize members with default values for a new instance.
}
// ...
}
জাভা
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance.
if (savedInstanceState != null) {
// Restore value of members from saved state.
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance.
}
// ...
}
onCreate চলাকালীন স্টেট পুনরুদ্ধার করার পরিবর্তে, আপনি onRestoreInstanceState ইমপ্লিমেন্ট করতে পারেন, যা সিস্টেম onStart মেথডের পরে কল করে। সিস্টেম শুধুমাত্র তখনই onRestoreInstanceState কল করে যখন পুনরুদ্ধার করার মতো কোনো সংরক্ষিত স্টেট থাকে, তাই Bundle নাল (null) কিনা তা আপনার পরীক্ষা করার প্রয়োজন নেই।
কোটলিন
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
// Always call the superclass so it can restore the view hierarchy.
super.onRestoreInstanceState(savedInstanceState)
// Restore state members from saved instance.
savedInstanceState?.run {
currentScore = getInt(STATE_SCORE)
currentLevel = getInt(STATE_LEVEL)
}
}
জাভা
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy.
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance.
currentScore = savedInstanceState.getInt(STATE_SCORE);
currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
কার্যকলাপের মধ্যে চলাচল
একটি অ্যাপ তার জীবনকালে সম্ভবত অনেকবারই কোনো একটি অ্যাক্টিভিটিতে প্রবেশ ও প্রস্থান করে, যেমন যখন ব্যবহারকারী ডিভাইসের ব্যাক বাটনে ট্যাপ করেন অথবা অ্যাক্টিভিটিটি থেকে অন্য কোনো অ্যাক্টিভিটি চালু হয়।
এই বিভাগে সফল অ্যাক্টিভিটি ট্রানজিশন বাস্তবায়নের জন্য প্রয়োজনীয় বিষয়গুলো আলোচনা করা হয়েছে। এই বিষয়গুলোর মধ্যে রয়েছে একটি অ্যাক্টিভিটি থেকে অন্য অ্যাক্টিভিটি শুরু করা, অ্যাক্টিভিটির স্টেট সংরক্ষণ করা এবং অ্যাক্টিভিটির স্টেট পুনরুদ্ধার করা।
একটি কাজ থেকে অন্য কাজ শুরু করা
প্রায়শই কোনো এক পর্যায়ে একটি অ্যাক্টিভিটি থেকে আরেকটি অ্যাক্টিভিটি শুরু করার প্রয়োজন হয়। এই প্রয়োজনটি দেখা দেয়, উদাহরণস্বরূপ, যখন কোনো অ্যাপকে বর্তমান স্ক্রিন থেকে নতুন কোনো স্ক্রিনে যেতে হয়।
আপনার অ্যাক্টিভিটি যে নতুন অ্যাক্টিভিটিটি শুরু করতে চলেছে, তার থেকে কোনো ফলাফল ফেরত চায় কি না, তার উপর নির্ভর করে আপনি startActivity মেথড অথবা startActivityForResult মেথড ব্যবহার করে নতুন অ্যাক্টিভিটিটি শুরু করেন। উভয় ক্ষেত্রেই, আপনাকে একটি Intent অবজেক্ট পাস করতে হয়।
Intent অবজেক্টটি আপনি যে নির্দিষ্ট অ্যাক্টিভিটি শুরু করতে চান তা নির্দিষ্ট করে, অথবা আপনি যে ধরনের কাজ সম্পাদন করতে চান তা বর্ণনা করে। সিস্টেম আপনার জন্য উপযুক্ত অ্যাক্টিভিটিটি নির্বাচন করে, যা এমনকি অন্য কোনো অ্যাপ্লিকেশন থেকেও হতে পারে। একটি Intent অবজেক্ট অল্প পরিমাণ ডেটাও বহন করতে পারে, যা শুরু হওয়া অ্যাক্টিভিটি ব্যবহার করবে। Intent ক্লাস সম্পর্কে আরও তথ্যের জন্য, Intents এবং Intent Filters দেখুন।
কার্যকলাপ শুরু করুন
নতুন শুরু হওয়া অ্যাক্টিভিটির যদি কোনো ফলাফল ফেরত দেওয়ার প্রয়োজন না হয়, তবে বর্তমান অ্যাক্টিভিটি startActivity মেথডটি কল করে সেটি শুরু করতে পারে।
আপনার নিজের অ্যাপ্লিকেশনে কাজ করার সময়, প্রায়শই একটি পরিচিত অ্যাক্টিভিটি চালু করার প্রয়োজন হয়। উদাহরণস্বরূপ, নিম্নলিখিত কোড স্নিপেটটি দেখায় কিভাবে SignInActivity নামক একটি অ্যাক্টিভিটি চালু করতে হয়।
কোটলিন
val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)
জাভা
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
আপনার অ্যাপ্লিকেশনটি আপনার অ্যাক্টিভিটির ডেটা ব্যবহার করে ইমেল, টেক্সট মেসেজ পাঠানো বা স্ট্যাটাস আপডেটের মতো কোনো কাজ সম্পাদন করতে চাইতে পারে। এক্ষেত্রে, এই ধরনের কাজ করার জন্য আপনার অ্যাপ্লিকেশনের নিজস্ব অ্যাক্টিভিটি নাও থাকতে পারে, তাই আপনি এর পরিবর্তে ডিভাইসের অন্যান্য অ্যাপ্লিকেশনের দেওয়া অ্যাক্টিভিটিগুলো ব্যবহার করতে পারেন, যেগুলো আপনার হয়ে কাজগুলো করে দেবে।
এইখানেই ইনটেন্টগুলো সত্যিই মূল্যবান। আপনি যে কাজটি করতে চান, তা বর্ণনা করে একটি ইনটেন্ট তৈরি করতে পারেন এবং সিস্টেমটি অন্য একটি অ্যাপ্লিকেশন থেকে উপযুক্ত অ্যাক্টিভিটিটি চালু করে দেয়। যদি ইনটেন্টটি পরিচালনা করার মতো একাধিক অ্যাক্টিভিটি থাকে, তবে ব্যবহারকারী কোনটি ব্যবহার করবেন তা বেছে নিতে পারেন। উদাহরণস্বরূপ, আপনি যদি ব্যবহারকারীকে একটি ইমেল বার্তা পাঠাতে দিতে চান, তাহলে আপনি নিম্নলিখিত ইনটেন্টটি তৈরি করতে পারেন:
কোটলিন
val intent = Intent(Intent.ACTION_SEND).apply {
putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)
জাভা
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);
ইন্টেন্টে যোগ করা EXTRA_EMAIL এক্সট্রাটি হলো একটি স্ট্রিং অ্যারে, যেখানে সেইসব ইমেল অ্যাড্রেস থাকে যাদের কাছে ইমেলটি পাঠানো হবে। যখন কোনো ইমেল অ্যাপ্লিকেশন এই ইন্টেন্টে সাড়া দেয়, তখন এটি এক্সট্রাতে দেওয়া স্ট্রিং অ্যারেটি পড়ে এবং অ্যাড্রেসগুলো ইমেল কম্পোজিশন ফর্মের "টু" ফিল্ডে রাখে। এই অবস্থায়, ইমেল অ্যাপ্লিকেশনটির অ্যাক্টিভিটি শুরু হয়, এবং ব্যবহারকারীর কাজ শেষ হলে আপনার অ্যাক্টিভিটি পুনরায় শুরু হয়।
startActivityForResult
কখনও কখনও আপনি কোনো অ্যাক্টিভিটি শেষ হওয়ার পর তার ফলাফল ফেরত পেতে চান। উদাহরণস্বরূপ, আপনি এমন একটি অ্যাক্টিভিটি শুরু করতে পারেন যা ব্যবহারকারীকে কন্ট্যাক্ট তালিকা থেকে একজন ব্যক্তিকে বেছে নিতে দেয়। এটি শেষ হলে, নির্বাচিত ব্যক্তির তথ্য ফেরত দেয়। এটি করার জন্য, আপনাকে startActivityForResult(Intent, int) মেথডটি কল করতে হবে, যেখানে ইন্টিজার প্যারামিটারটি কলটিকে শনাক্ত করে।
এই আইডেন্টিফায়ারটি একই অ্যাক্টিভিটি থেকে startActivityForResult(Intent, int) এর একাধিক কলকে আলাদা করার জন্য ব্যবহৃত হয়। এটি কোনো গ্লোবাল আইডেন্টিফায়ার নয় এবং অন্য অ্যাপ বা অ্যাক্টিভিটির সাথে এর কোনো সংঘাতের ঝুঁকি নেই। ফলাফলটি আপনার onActivityResult(int, int, Intent) মেথডের মাধ্যমে ফিরে আসে।
যখন কোনো চাইল্ড অ্যাক্টিভিটি শেষ হয়, তখন এটি তার প্যারেন্টকে ডেটা ফেরত দেওয়ার জন্য setResult(int) কল করতে পারে। চাইল্ড অ্যাক্টিভিটিকে অবশ্যই একটি রেজাল্ট কোড সরবরাহ করতে হবে, যা হতে পারে স্ট্যান্ডার্ড রেজাল্ট RESULT_CANCELED, RESULT_OK , অথবা RESULT_FIRST_USER থেকে শুরু করে যেকোনো কাস্টম ভ্যালু।
এছাড়াও, চাইল্ড অ্যাক্টিভিটি ঐচ্ছিকভাবে একটি Intent অবজেক্ট রিটার্ন করতে পারে, যাতে তার ইচ্ছামত যেকোনো অতিরিক্ত ডেটা থাকে। প্যারেন্ট অ্যাক্টিভিটি সেই তথ্য গ্রহণ করার জন্য onActivityResult(int, int, Intent) মেথডটি ব্যবহার করে, সাথে প্যারেন্ট অ্যাক্টিভিটির শুরুতে সরবরাহ করা ইন্টিজার আইডেন্টিফায়ারটিও যুক্ত করে।
যদি কোনো চাইল্ড অ্যাক্টিভিটি কোনো কারণে ব্যর্থ হয়, যেমন ক্র্যাশ করার ফলে, তাহলে প্যারেন্ট অ্যাক্টিভিটি RESULT_CANCELED কোডসহ একটি ফলাফল পায়।
কোটলিন
class MyActivity : Activity() {
// ...
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// When the user center presses, let them pick a contact.
startActivityForResult(
Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
PICK_CONTACT_REQUEST)
return true
}
return false
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
when (requestCode) {
PICK_CONTACT_REQUEST ->
if (resultCode == RESULT_OK) {
// A contact was picked. Display it to the user.
startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
}
}
}
companion object {
internal val PICK_CONTACT_REQUEST = 0
}
}
জাভা
public class MyActivity extends Activity {
// ...
static final int PICK_CONTACT_REQUEST = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
// When the user center presses, let them pick a contact.
startActivityForResult(
new Intent(Intent.ACTION_PICK,
new Uri("content://contacts")),
PICK_CONTACT_REQUEST);
return true;
}
return false;
}
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == PICK_CONTACT_REQUEST) {
if (resultCode == RESULT_OK) {
// A contact was picked. Display it to the user.
startActivity(new Intent(Intent.ACTION_VIEW, data));
}
}
}
}
সমন্বয়মূলক কার্যক্রম
যখন একটি অ্যাক্টিভিটি অন্যটিকে চালু করে, তখন উভয়ই লাইফসাইকেল ট্রানজিশনের মধ্য দিয়ে যায়। প্রথম অ্যাক্টিভিটিটি কাজ করা বন্ধ করে পজড বা স্টপড অবস্থায় চলে যায়, এবং একই সময়ে অন্য অ্যাক্টিভিটিটি তৈরি হয়। যদি এই অ্যাক্টিভিটিগুলো ডিস্কে বা অন্য কোথাও সংরক্ষিত ডেটা শেয়ার করে, তবে এটা বোঝা গুরুত্বপূর্ণ যে দ্বিতীয়টি তৈরি হওয়ার আগে প্রথম অ্যাক্টিভিটিটি পুরোপুরি বন্ধ হয় না। বরং, দ্বিতীয়টি চালু করার প্রক্রিয়াটি প্রথমটি বন্ধ করার প্রক্রিয়ার সাথে ওভারল্যাপ করে।
লাইফসাইকেল কলব্যাকগুলোর ক্রম সুনির্দিষ্ট, বিশেষ করে যখন দুটি অ্যাক্টিভিটি একই প্রসেসে—অর্থাৎ একই অ্যাপে—থাকে এবং একটি অন্যটিকে চালু করে। অ্যাক্টিভিটি A যখন অ্যাক্টিভিটি B চালু করে, তখন যে অপারেশনগুলো ঘটে তার ক্রম নিচে দেওয়া হলো:
- অ্যাক্টিভিটি A-এর
onPauseমেথডটি কার্যকর হয়। - অ্যাক্টিভিটি B-এর
onCreate,onStart, এবংonResumeমেথডগুলো ক্রমানুসারে সম্পাদিত হয়। এখন অ্যাক্টিভিটি B-তে ব্যবহারকারীর ফোকাস রয়েছে। - যদি অ্যাক্টিভিটি A স্ক্রিনে আর দৃশ্যমান না থাকে, তাহলে এর
onStopমেথডটি কার্যকর হয়।
লাইফসাইকেল কলব্যাকগুলির এই ক্রম আপনাকে একটি অ্যাক্টিভিটি থেকে অন্য অ্যাক্টিভিটিতে তথ্যের স্থানান্তর পরিচালনা করতে সাহায্য করে।