রিসেন্টস স্ক্রিন, যা ওভারভিউ স্ক্রিন, রিসেন্ট টাস্ক লিস্ট বা রিসেন্ট অ্যাপস স্ক্রিন নামেও পরিচিত, হলো একটি সিস্টেম-লেভেল ইউআই যা সম্প্রতি সম্পন্ন করা কার্যকলাপ এবং টাস্কগুলোর তালিকা দেখায়। ব্যবহারকারী এই তালিকার মধ্যে দিয়ে নেভিগেট করতে, পুনরায় শুরু করার জন্য কোনো টাস্ক নির্বাচন করতে, অথবা সোয়াইপ করে তালিকা থেকে কোনো টাস্ক মুছে ফেলতে পারেন।
রিসেন্টস স্ক্রিন একটি ডকুমেন্ট-কেন্দ্রিক মডেল ব্যবহার করে—যা অ্যান্ড্রয়েড ৫.০ (এপিআই লেভেল ২১)-এ চালু হয়েছিল—যেখানে বিভিন্ন ডকুমেন্ট ধারণকারী একই অ্যাক্টিভিটির একাধিক ইনস্ট্যান্স রিসেন্টস স্ক্রিনে টাস্ক হিসেবে প্রদর্শিত হতে পারে। উদাহরণস্বরূপ, গুগল ড্রাইভে বেশ কয়েকটি গুগল ডকুমেন্টের প্রতিটির জন্য একটি করে টাস্ক থাকতে পারে। প্রতিটি ডকুমেন্ট রিসেন্টস স্ক্রিনে একটি টাস্ক হিসেবে প্রদর্শিত হয়:
এর আরেকটি সাধারণ উদাহরণ হলো, যখন ব্যবহারকারী তার ব্রাউজার ব্যবহার করার সময় শেয়ার > জিমেইল-এ ট্যাপ করেন। তখন জিমেইল অ্যাপের কম্পোজ স্ক্রিনটি দেখা যায়। সেই মুহূর্তে রিসেন্টস বাটনে ট্যাপ করলে দেখা যায় যে ক্রোম এবং জিমেইল আলাদা টাস্ক হিসেবে চলছে:
সাধারণত, রিসেন্টস স্ক্রিনে আপনার টাস্ক ও অ্যাক্টিভিটিগুলো কীভাবে দেখানো হবে, তা আপনি সিস্টেমকেই নির্ধারণ করতে দেন। এই আচরণটি পরিবর্তন করার কোনো প্রয়োজন নেই। তবে, আপনার অ্যাপ নির্ধারণ করতে পারে যে অ্যাক্টিভিটিগুলো রিসেন্টস স্ক্রিনে কীভাবে এবং কখন প্রদর্শিত হবে।
ActivityManager.AppTask ক্লাসটি আপনাকে টাস্ক পরিচালনা করতে দেয়, এবং Intent ক্লাসের অ্যাক্টিভিটি ফ্ল্যাগগুলো আপনাকে নির্দিষ্ট করতে দেয় যে কখন Recents স্ক্রিন থেকে কোনো অ্যাক্টিভিটি যোগ বা অপসারণ করা হবে। এছাড়াও, <activity> অ্যাট্রিবিউটগুলো আপনাকে ম্যানিফেস্টে এর আচরণ নির্ধারণ করতে দেয়।
সাম্প্রতিক স্ক্রিনে টাস্ক যোগ করুন
Intent ক্লাসের ফ্ল্যাগ ব্যবহার করে একটি টাস্ক যোগ করলে, Recents স্ক্রিনে কখন এবং কীভাবে একটি ডকুমেন্ট খোলা বা পুনরায় খোলা হবে তার উপর আপনি আরও বেশি নিয়ন্ত্রণ পান। যখন আপনি <activity> অ্যাট্রিবিউট ব্যবহার করেন, তখন আপনি ডকুমেন্টটি সর্বদা একটি নতুন টাস্কে খোলা অথবা ডকুমেন্টটির জন্য একটি বিদ্যমান টাস্ক পুনরায় ব্যবহার করার মধ্যে যেকোনো একটি বেছে নিতে পারেন।
টাস্ক যোগ করতে ইনটেন্ট ফ্ল্যাগ ব্যবহার করুন।
যখন আপনি আপনার অ্যাক্টিভিটির জন্য একটি নতুন ডকুমেন্ট তৈরি করেন, তখন আপনি startActivity() মেথডটি কল করেন এবং এতে অ্যাক্টিভিটিটি চালু করার ইন্টেন্টটি পাস করেন। একটি লজিক্যাল ব্রেক যোগ করার জন্য, যাতে সিস্টেম আপনার অ্যাক্টিভিটিকে রিসেন্টস স্ক্রিনে একটি নতুন টাস্ক হিসেবে গণ্য করে, অ্যাক্টিভিটিটি চালুকারী Intent addFlags() মেথডে FLAG_ACTIVITY_NEW_DOCUMENT ফ্ল্যাগটি পাস করুন।
নতুন ডকুমেন্ট তৈরি করার সময় আপনি যদি FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগটি সেট করেন, তাহলে সিস্টেম সর্বদা টার্গেট অ্যাক্টিভিটিকে রুট হিসেবে ব্যবহার করে একটি নতুন টাস্ক তৈরি করে। এই সেটিংটি একই ডকুমেন্টকে একাধিক টাস্কে খোলার সুযোগ দেয়। নিচের কোডটি দেখায় কিভাবে মূল অ্যাক্টিভিটি এটি করে এবং আপনার কম্পোজেবল থেকে নতুন অ্যাক্টিভিটিটি শুরু করে:
private fun newDocumentIntent(context: Context): Intent = Intent(context, NewDocumentActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, documentCounter++) } @Composable fun CreateDocumentButton() { val context = LocalContext.current Button( onClick = { val intent = newDocumentIntent(context) // Add FLAG_ACTIVITY_MULTIPLE_TASK if needed based on state context.startActivity(intent) } ) { Text("Create New Document") } }
যখন মূল অ্যাক্টিভিটি একটি নতুন অ্যাক্টিভিটি চালু করে, তখন সিস্টেম বিদ্যমান টাস্কগুলোর মধ্যে এমন একটি টাস্ক খোঁজে যার ইনটেন্টটি অ্যাক্টিভিটির ইনটেন্ট কম্পোনেন্টের নাম এবং ইনটেন্ট ডেটার সাথে মেলে। যদি টাস্কটি খুঁজে না পাওয়া যায়, অথবা ইনটেন্টটিতে FLAG_ACTIVITY_MULTIPLE_TASK ফ্ল্যাগটি থাকে, তাহলে অ্যাক্টিভিটিটিকে রুট হিসেবে ব্যবহার করে একটি নতুন টাস্ক তৈরি করা হয়।
যদি সিস্টেম এমন কোনো টাস্ক খুঁজে পায় যার ইনটেন্ট, ইনটেন্ট কম্পোনেন্টের নাম এবং ইনটেন্ট ডেটার সাথে মিলে যায়, তবে এটি সেই টাস্কটিকে সামনে নিয়ে আসে এবং নতুন ইনটেন্টটি onNewIntent() ফাংশনে পাঠিয়ে দেয়। নতুন অ্যাক্টিভিটিটি ইনটেন্টটি গ্রহণ করে এবং Recents স্ক্রিনে একটি নতুন ডকুমেন্ট তৈরি করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
class DocumentCentricActivity : ComponentActivity() { private var documentState by mutableStateOf( DocumentState( count = 0, textResId = R.string.hello_new_document_counter ) ) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val initialCount = intent.getIntExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0) documentState = documentState.copy(count = initialCount) setContent { MaterialTheme { DocumentScreen( count = documentState.count, textResId = documentState.textResId ) } } } override fun onNewIntent(newIntent: Intent) { super.onNewIntent(newIntent) // If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this Activity is reused. documentState = documentState.copy( textResId = R.string.reusing_document_counter ) } data class DocumentState(val count: Int, @StringRes val textResId: Int) companion object { const val KEY_EXTRA_NEW_DOCUMENT_COUNTER = "KEY_EXTRA_NEW_DOCUMENT_COUNTER" } } @Composable fun DocumentScreen(count: Int, @StringRes textResId: Int) { Column( modifier = Modifier .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.Center ) { // UI reacts to whichever string resource ID was passed down Text(text = stringResource(id = textResId)) Spacer(modifier = Modifier.height(8.dp)) Text(text = "Counter: $count") } }
পূর্ববর্তী কোডে, অ্যাক্টিভিটিটি OS-স্তরের রাউটিং ( onCreate এবং onNewIntent ) পরিচালনা করে, অপরদিকে @Composable ফাংশনটি শুধুমাত্র প্রদত্ত স্টেটের উপর ভিত্তি করে UI রেন্ডার করার দায়িত্বে থাকে।
টাস্ক যোগ করতে অ্যাক্টিভিটি অ্যাট্রিবিউট ব্যবহার করুন।
একটি অ্যাক্টিভিটি তার ম্যানিফেস্টে <activity> অ্যাট্রিবিউট android:documentLaunchMode ব্যবহার করে এটাও নির্দিষ্ট করতে পারে যে এটি সর্বদা একটি নতুন টাস্কে চালু হবে। এই অ্যাট্রিবিউটের চারটি মান রয়েছে, যা ব্যবহারকারী অ্যাপ্লিকেশনটি দিয়ে একটি ডকুমেন্ট খুললে নিম্নলিখিত প্রভাবগুলি তৈরি করে:
-
intoExisting - এই অ্যাক্টিভিটিটি ডকুমেন্টটির জন্য একটি বিদ্যমান টাস্ক পুনরায় ব্যবহার করে। এটি "Using the Intent flag to add a task" বিভাগে বর্ণিত
FLAG_ACTIVITY_MULTIPLE_TASKফ্ল্যাগটি সেট না করেইFLAG_ACTIVITY_NEW_DOCUMENTফ্ল্যাগ সেট করার মতোই। -
always - এই অ্যাক্টিভিটিটি ডকুমেন্টটির জন্য একটি নতুন টাস্ক তৈরি করে, এমনকি যদি ডকুমেন্টটি আগে থেকেই খোলা থাকে। এই ভ্যালুটি ব্যবহার করা
FLAG_ACTIVITY_NEW_DOCUMENTএবংFLAG_ACTIVITY_MULTIPLE_TASKউভয় ফ্ল্যাগ সেট করার সমান। -
none - এই অ্যাক্টিভিটিটি ডকুমেন্টের জন্য কোনো নতুন টাস্ক তৈরি করে না। রিসেন্টস স্ক্রিনটি অ্যাক্টিভিটিটিকে ডিফল্টভাবেই বিবেচনা করে। এটি অ্যাপটির জন্য একটিমাত্র টাস্ক প্রদর্শন করে, যা ব্যবহারকারী সর্বশেষ যে অ্যাক্টিভিটিটি চালু করেছিলেন সেখান থেকেই পুনরায় শুরু হয়।
-
never - এই অ্যাক্টিভিটিটি ডকুমেন্টের জন্য কোনো নতুন টাস্ক তৈরি করে না। এই মানটি সেট করলে
FLAG_ACTIVITY_NEW_DOCUMENTএবংFLAG_ACTIVITY_MULTIPLE_TASKফ্ল্যাগগুলোর আচরণ ওভাররাইড হয়ে যায়। যদি ইন্টেন্টে এগুলোর কোনোটি সেট করা থাকে এবং রিসেন্টস স্ক্রিনে অ্যাপটির জন্য একটিমাত্র টাস্ক প্রদর্শিত হয়, তবে এটি ব্যবহারকারী সর্বশেষ যে অ্যাক্টিভিটিটি চালু করেছিলেন সেখান থেকেই পুনরায় শুরু হয়।
কাজগুলো অপসারণ করুন
ডিফল্টরূপে, একটি ডকুমেন্ট টাস্কের অ্যাক্টিভিটি শেষ হলে সেটি স্বয়ংক্রিয়ভাবে রিসেন্টস স্ক্রিন থেকে বেরিয়ে যায়। আপনি ActivityManager.AppTask ক্লাস, একটি Intent ফ্ল্যাগ, অথবা একটি <activity> অ্যাট্রিবিউটের মাধ্যমে এই আচরণটি পরিবর্তন করতে পারেন।
আপনি <activity> অ্যাট্রিবিউট android:excludeFromRecents কে true সেট করে রিসেন্টস স্ক্রিন থেকে যেকোনো টাস্ককে সর্বদা সম্পূর্ণরূপে বাদ দিতে পারেন।
আপনার অ্যাপের রিসেন্টস স্ক্রিনে সর্বাধিক কতগুলো টাস্ক অন্তর্ভুক্ত করা যাবে, তা আপনি <activity> অ্যাট্রিবিউটের android:maxRecents একটি পূর্ণসংখ্যা (integer) মান দিয়ে নির্ধারণ করতে পারেন। যখন টাস্কের সর্বোচ্চ সংখ্যায় পৌঁছানো হয়, তখন সবচেয়ে কম ব্যবহৃত টাস্কটি রিসেন্টস স্ক্রিন থেকে অদৃশ্য হয়ে যায়। এর ডিফল্ট মান হলো ১৬ এবং সর্বোচ্চ মান হলো ৫০ (কম মেমোরির ডিভাইসে ২৫)। ১-এর কম মান গ্রহণযোগ্য নয়।
টাস্ক অপসারণ করতে AppTask ক্লাস ব্যবহার করুন।
রিসেন্টস স্ক্রিনে নতুন টাস্ক তৈরি করার অ্যাক্টিভিটিতে, আপনি finishAndRemoveTask() মেথডটি কল করার মাধ্যমে নির্দিষ্ট করে দিতে পারেন কখন টাস্কটি রিমুভ করতে হবে এবং এর সাথে যুক্ত সমস্ত অ্যাক্টিভিটি শেষ করতে হবে:
@Composable fun RemoveTaskButton() { val context = LocalContext.current Button( onClick = { // It is good practice to remove a document from the overview stack if not needed anymore. (context as? Activity)?.finishAndRemoveTask() } ) { Text("Remove from Recents") } }
সম্পন্ন কাজগুলো সংরক্ষণ করুন
যদি আপনি কোনো টাস্কের অ্যাক্টিভিটি শেষ হয়ে যাওয়ার পরেও সেটিকে রিসেন্টস স্ক্রিনে ধরে রাখতে চান, তাহলে যে ইন্টেন্টটি অ্যাক্টিভিটিটি চালু করে তার addFlags() মেথডে FLAG_ACTIVITY_RETAIN_IN_RECENTS ফ্ল্যাগটি পাস করুন।
private fun newDocumentIntent() = Intent(this, NewDocumentActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT or android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS) putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, getAndIncrement()) }
একই ফল পেতে, <activity> অ্যাট্রিবিউটের android:autoRemoveFromRecents কে false এ সেট করুন। ডকুমেন্ট অ্যাক্টিভিটির জন্য এর ডিফল্ট মান true এবং সাধারণ অ্যাক্টিভিটির জন্য false । এই অ্যাট্রিবিউটটি ব্যবহার করলে FLAG_ACTIVITY_RETAIN_IN_RECENTS ফ্ল্যাগটি ওভাররাইড হয়ে যায়।
সাম্প্রতিক URL শেয়ারিং সক্ষম করুন (শুধুমাত্র পিক্সেল-এর জন্য)
অ্যান্ড্রয়েড ১২ বা তার উচ্চতর সংস্করণে চালিত পিক্সেল ডিভাইসগুলোতে, ব্যবহারকারীরা সম্প্রতি দেখা ওয়েব কন্টেন্টের লিঙ্ক সরাসরি রিসেন্টস স্ক্রিন থেকে শেয়ার করতে পারেন। কোনো অ্যাপে কন্টেন্টটি দেখার পর, ব্যবহারকারী রিসেন্টস স্ক্রিনে সোয়াইপ করে সেই অ্যাপটি খুঁজে নিতে পারেন যেখানে তিনি কন্টেন্টটি দেখেছিলেন, তারপর ইউআরএলটি কপি বা শেয়ার করার জন্য লিঙ্ক বোতামে ট্যাপ করতে পারেন।
যেকোনো অ্যাপ একটি ওয়েব UI প্রদান করে এবং onProvideAssistContent() ওভাররাইড করার মাধ্যমে ব্যবহারকারীদের জন্য Recents লিঙ্কিং সক্ষম করতে পারে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
class MainActivity : ComponentActivity() { // Track the current URL as state so the UI can update it during navigation private var currentWebUri by mutableStateOf("https://example.com/home") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { AppTheme { // Pass a lambda to your Compose UI so it can update the URL state // as the user navigates through your app. MainScreen( onPageChanged = { newUrl -> currentWebUri = newUrl } ) } } } override fun onProvideAssistContent(outContent: AssistContent) { super.onProvideAssistContent(outContent) // The system calls this when the user enters the Recents screen. // Provide the active URI tracked by the Compose state. outContent.webUri = Uri.parse(currentWebUri) } }