ধারণা এবং জেটপ্যাক কম্পোজ বাস্তবায়ন
অ্যাপটি চলার সময় ডিভাইসের কিছু কনফিগারেশন পরিবর্তিত হতে পারে। এগুলোর মধ্যে রয়েছে, তবে তা শুধু এগুলোর মধ্যেই সীমাবদ্ধ নয়:
- অ্যাপ প্রদর্শনের আকার
- স্ক্রিন ওরিয়েন্টেশন
- ফন্টের আকার এবং ওজন
- অবস্থান
- ডার্ক মোড বনাম লাইট মোড
- কিবোর্ডের প্রাপ্যতা
এই কনফিগারেশন পরিবর্তনগুলোর বেশিরভাগই ব্যবহারকারীর কোনো কার্যকলাপের কারণে ঘটে থাকে। উদাহরণস্বরূপ, ডিভাইসটি ঘোরানো বা ভাঁজ করলে আপনার অ্যাপের জন্য উপলব্ধ স্ক্রিন স্পেসের পরিমাণ পরিবর্তিত হয়। একইভাবে, ফন্ট সাইজ, ভাষা বা পছন্দের থিমের মতো ডিভাইসের সেটিংস পরিবর্তন করলে Configuration অবজেক্টে তাদের নিজ নিজ মান পরিবর্তিত হয়।
এই প্যারামিটারগুলোর জন্য সাধারণত আপনার অ্যাপ্লিকেশনের UI-তে যথেষ্ট বড় পরিবর্তনের প্রয়োজন হয়, এবং সেই পরিবর্তনের জন্য অ্যান্ড্রয়েড প্ল্যাটফর্মে একটি বিশেষ ব্যবস্থা রয়েছে। এই ব্যবস্থাটি হলো Activity রিক্রিয়েশন ।
কার্যকলাপ বিনোদন
কনফিগারেশনে কোনো পরিবর্তন ঘটলে সিস্টেম একটি Activity পুনরায় তৈরি করে। এটি করার জন্য, সিস্টেম onDestroy কল করে এবং বিদ্যমান Activity ইনস্ট্যান্সটিকে ধ্বংস করে দেয়। এরপর এটি onCreate ব্যবহার করে একটি নতুন ইনস্ট্যান্স তৈরি করে, এবং এই নতুন Activity ইনস্ট্যান্সটি নতুন ও হালনাগাদ করা কনফিগারেশন দিয়ে ইনিশিয়ালাইজ করা হয়। এর মানে হলো, সিস্টেম নতুন কনফিগারেশন দিয়ে UI-টিও পুনরায় তৈরি করে।
পুনর্গঠন আচরণটি আপনার অ্যাপ্লিকেশনকে নতুন ডিভাইস কনফিগারেশনের সাথে মেলে এমন বিকল্প রিসোর্স দিয়ে স্বয়ংক্রিয়ভাবে পুনরায় লোড করার মাধ্যমে নতুন কনফিগারেশনের সাথে খাপ খাইয়ে নিতে সাহায্য করে।
বিনোদনের উদাহরণ
একটি TextView কথা ভাবুন যা একটি লেআউট XML ফাইলে সংজ্ঞায়িত android:text="@string/title" ব্যবহার করে একটি স্থির শিরোনাম প্রদর্শন করে। যখন ভিউটি তৈরি করা হয়, তখন এটি বর্তমান ভাষার উপর ভিত্তি করে টেক্সটটি ঠিক একবার সেট করে। যদি ভাষা পরিবর্তিত হয়, সিস্টেম অ্যাক্টিভিটিটি পুনরায় তৈরি করে। ফলস্বরূপ, সিস্টেম ভিউটিও পুনরায় তৈরি করে এবং নতুন ভাষার উপর ভিত্তি করে এটিকে সঠিক মান দিয়ে ইনিশিয়ালাইজ করে।
অ্যাক্টিভিটি পুনরায় তৈরি করার ফলে Activity বা এর অন্তর্ভুক্ত কোনো Fragment , View বা অন্যান্য অবজেক্টে ফিল্ড হিসেবে সংরক্ষিত যেকোনো স্টেটও মুছে যায়। এর কারণ হলো, Activity পুনরায় তৈরি করার ফলে Activity এবং UI-এর একটি সম্পূর্ণ নতুন ইনস্ট্যান্স তৈরি হয়। তাছাড়া, পুরোনো Activity আর দৃশ্যমান বা বৈধ থাকে না, তাই এটি বা এর অন্তর্ভুক্ত অবজেক্টগুলোর যেকোনো অবশিষ্ট রেফারেন্স অকার্যকর হয়ে যায়। এগুলো বাগ, মেমোরি লিক এবং ক্র্যাশের কারণ হতে পারে।
ব্যবহারকারীর প্রত্যাশা
একটি অ্যাপের ব্যবহারকারী তার অ্যাপের অবস্থা সংরক্ষিত থাকার প্রত্যাশা করেন। যদি কোনো ব্যবহারকারী একটি ফর্ম পূরণ করার সময় তথ্য দেখার জন্য মাল্টি-উইন্ডো মোডে অন্য কোনো অ্যাপ খোলেন, তবে তিনি যদি পূরণ করা ফর্মে বা অ্যাপের সম্পূর্ণ অন্য কোনো অংশে ফিরে আসেন, তবে তা একটি খারাপ ব্যবহারকারী অভিজ্ঞতা। একজন ডেভেলপার হিসেবে, কনফিগারেশন পরিবর্তন এবং অ্যাক্টিভিটি পুনরায় তৈরি করার মাধ্যমে আপনাকে অবশ্যই একটি সামঞ্জস্যপূর্ণ ব্যবহারকারী অভিজ্ঞতা প্রদান করতে হবে।
আপনার অ্যাপ্লিকেশনে স্টেট সংরক্ষিত আছে কিনা তা যাচাই করার জন্য, অ্যাপটি ফোরগ্রাউন্ডে এবং ব্যাকগ্রাউন্ডে উভয় অবস্থাতেই আপনি এমন কিছু কাজ করতে পারেন যা কনফিগারেশনে পরিবর্তন আনে। এই কাজগুলোর মধ্যে রয়েছে:
- ডিভাইসটি ঘোরানো
- মাল্টি-উইন্ডো মোডে প্রবেশ করা
- মাল্টি-উইন্ডো মোডে বা একটি ফ্রি-ফর্ম উইন্ডোতে থাকাকালীন অ্যাপ্লিকেশনটির আকার পরিবর্তন করা
- একাধিক ডিসপ্লে সহ একটি ফোল্ডেবল ডিভাইস ভাঁজ করা
- সিস্টেম থিম পরিবর্তন করা, যেমন ডার্ক মোড বনাম লাইট মোড
- ফন্টের আকার পরিবর্তন করা
- সিস্টেম বা অ্যাপের ভাষা পরিবর্তন করা
- হার্ডওয়্যার কিবোর্ড সংযোগ বা বিচ্ছিন্ন করা
- ডক সংযোগ বা বিচ্ছিন্ন করা
Activity রিক্রিয়েশনের মাধ্যমে প্রাসঙ্গিক স্টেট সংরক্ষণ করার জন্য তিনটি প্রধান পদ্ধতি রয়েছে। কোনটি ব্যবহার করবেন তা নির্ভর করে আপনি কোন ধরনের স্টেট সংরক্ষণ করতে চান তার উপর:
- জটিল বা বৃহৎ ডেটার ক্ষেত্রে প্রসেস বন্ধ হয়ে যাওয়া সামাল দেওয়ার জন্য লোকাল পারসিস্টেন্স ব্যবহার করা হয়। পারসিস্টেন্ট লোকাল স্টোরেজের মধ্যে ডেটাবেস বা
DataStoreঅন্তর্ভুক্ত। - ব্যবহারকারী যখন সক্রিয়ভাবে অ্যাপটি ব্যবহার করেন, তখন মেমরিতে UI-সম্পর্কিত অবস্থা পরিচালনা করার জন্য
ViewModelইনস্ট্যান্সের মতো অবজেক্টগুলো ধরে রাখা হয় । - সিস্টেম-প্রণোদিত প্রসেস বন্ধ হয়ে যাওয়া সামাল দিতে এবং ব্যবহারকারীর ইনপুট বা নেভিগেশনের ওপর নির্ভরশীল ক্ষণস্থায়ী অবস্থা বজায় রাখতে ইনস্ট্যান্সের অবস্থা সংরক্ষণ করা হয় ।
এগুলোর প্রত্যেকটির এপিআই (API) সম্পর্কে বিস্তারিতভাবে জানতে এবং কখন কোনটি ব্যবহার করা উপযুক্ত, তা জানতে সেভ ইউআই স্টেটস (Save UI states) দেখুন।
ভিউ সিস্টেমে কনফিগারেশন পরিবর্তনে প্রতিক্রিয়া জানান
View সিস্টেমে, যখন এমন কোনো কনফিগারেশন পরিবর্তন ঘটে যার জন্য আপনি Activity পুনঃসৃষ্টি নিষ্ক্রিয় করে রেখেছেন, তখন অ্যাক্টিভিটিটি Activity.onConfigurationChanged কল পায়। এর সাথে সংযুক্ত যেকোনো ভিউও View.onConfigurationChanged কল পায়। যেসব কনফিগারেশন পরিবর্তন আপনি android:configChanges এ যোগ করেননি, সেগুলোর ক্ষেত্রে সিস্টেম যথারীতি অ্যাক্টিভিটিটি পুনঃসৃষ্টি করে।
onConfigurationChanged কলব্যাক মেথডটি একটি Configuration অবজেক্ট গ্রহণ করে, যা নতুন ডিভাইস কনফিগারেশন নির্দিষ্ট করে। আপনার নতুন কনফিগারেশন কী তা নির্ধারণ করতে Configuration অবজেক্টের ফিল্ডগুলো পড়ুন। পরবর্তী পরিবর্তনগুলো করার জন্য, আপনার ইন্টারফেসে ব্যবহৃত রিসোর্সগুলো আপডেট করুন। যখন সিস্টেম এই মেথডটি কল করে, তখন আপনার অ্যাক্টিভিটির Resources অবজেক্টটি নতুন কনফিগারেশনের উপর ভিত্তি করে রিসোর্স রিটার্ন করার জন্য আপডেট হয়। এর ফলে সিস্টেম আপনার অ্যাক্টিভিটি রিস্টার্ট না করেই আপনি আপনার UI-এর উপাদানগুলো রিসেট করতে পারেন।
উদাহরণস্বরূপ, নিম্নলিখিত onConfigurationChanged ইমপ্লিমেন্টেশনটি পরীক্ষা করে দেখে যে একটি কীবোর্ড উপলব্ধ আছে কিনা:
কোটলিন
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Checks whether a keyboard is available
if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
} else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
}
}
জাভা
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks whether a keyboard is available
if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
} else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
}
}
যদি এই কনফিগারেশন পরিবর্তনের উপর ভিত্তি করে আপনার অ্যাপ্লিকেশন আপডেট করার প্রয়োজন না হয়, তাহলে আপনি এর পরিবর্তে onConfigurationChanged ইমপ্লিমেন্ট না করতে পারেন। সেক্ষেত্রে, কনফিগারেশন পরিবর্তনের আগে ব্যবহৃত সমস্ত রিসোর্স আগের মতোই ব্যবহৃত হতে থাকবে এবং আপনি কেবল আপনার অ্যাক্টিভিটির রিস্টার্ট এড়াতে পারবেন। উদাহরণস্বরূপ, একটি টিভি অ্যাপ হয়তো ব্লুটুথ কিবোর্ড সংযুক্ত বা বিচ্ছিন্ন হলে কোনো প্রতিক্রিয়া দেখাতে চাইবে না।
রাষ্ট্র ধরে রাখুন
এই কৌশলটি ব্যবহার করার সময়ও, স্বাভাবিক অ্যাক্টিভিটি লাইফসাইকেল চলাকালীন আপনাকে অবশ্যই স্টেট ধরে রাখতে হবে। এর কারণগুলো নিম্নরূপ:
- অনিবার্য পরিবর্তন: এমন কনফিগারেশন পরিবর্তন যা আপনি আটকাতে পারবেন না, তার ফলে আপনার অ্যাপ্লিকেশনটি পুনরায় চালু হতে পারে।
- প্রসেস বন্ধ হয়ে যাওয়া: আপনার অ্যাপ্লিকেশনকে অবশ্যই সিস্টেম-প্রবর্তিত প্রসেস বন্ধ হওয়া সামলাতে সক্ষম হতে হবে। যদি ব্যবহারকারী আপনার অ্যাপ্লিকেশন থেকে বেরিয়ে যান এবং অ্যাপটি ব্যাকগ্রাউন্ডে চলে যায়, তাহলে সিস্টেম অ্যাপটিকে বন্ধ করে দিতে পারে।
কনফিগারেশন পরিবর্তন: মূল ধারণা এবং সর্বোত্তম অনুশীলন
কনফিগারেশন পরিবর্তন নিয়ে কাজ করার সময় এই মূল ধারণাগুলো আপনার জানা প্রয়োজন:
- কনফিগারেশন: ডিভাইস কনফিগারেশন নির্ধারণ করে যে ব্যবহারকারীর কাছে UI কীভাবে প্রদর্শিত হবে, যেমন অ্যাপ প্রদর্শনের আকার, লোকেল বা সিস্টেম থিম।
- কনফিগারেশন পরিবর্তন: ব্যবহারকারীর কার্যকলাপের মাধ্যমে কনফিগারেশন পরিবর্তিত হয়। উদাহরণস্বরূপ, ব্যবহারকারী ডিভাইসের সেটিংস বা ডিভাইসটি ব্যবহারের পদ্ধতি পরিবর্তন করতে পারেন। কনফিগারেশন পরিবর্তন রোধ করার কোনো উপায় নেই।
-
Activityপুনঃসৃষ্টি: কনফিগারেশন পরিবর্তনের ফলে ডিফল্টরূপেActivityপুনঃসৃষ্ট হয়। নতুন কনফিগারেশনের জন্য অ্যাপের অবস্থা পুনরায় চালু করার এটি একটি অন্তর্নির্মিত ব্যবস্থা। -
Activityধ্বংসকরণ:Activityপুনঃসৃষ্টির ফলে সিস্টেম পুরানোActivityইনস্ট্যান্সটিকে ধ্বংস করে দেয় এবং তার জায়গায় একটি নতুন ইনস্ট্যান্স তৈরি করে। পুরানো ইনস্ট্যান্সটি এখন অপ্রচলিত হয়ে যায়। এটির সাথে সম্পর্কিত যেকোনো অবশিষ্ট রেফারেন্সের ফলে মেমোরি লিক, বাগ বা ক্র্যাশ হতে পারে। - স্টেট: পুরোনো
Activityইনস্ট্যান্সের স্টেট নতুনActivityইনস্ট্যান্সে উপস্থিত থাকে না, কারণ এগুলি দুটি ভিন্ন অবজেক্ট ইনস্ট্যান্স। "Save UI states" অংশে বর্ণিত পদ্ধতি অনুযায়ী অ্যাপ এবং ব্যবহারকারীর স্টেট সংরক্ষণ করুন। - অপ্ট-আউট: কোনো ধরনের কনফিগারেশন পরিবর্তনের জন্য অ্যাক্টিভিটি পুনরায় চালু হওয়া থেকে বিরত থাকা একটি সম্ভাব্য অপটিমাইজেশন। এর জন্য প্রয়োজন যে আপনার অ্যাপটি নতুন কনফিগারেশনের প্রতিক্রিয়ায় সঠিকভাবে আপডেট হয়।
ব্যবহারকারীদের ভালো অভিজ্ঞতা প্রদানের জন্য নিম্নলিখিত সর্বোত্তম অনুশীলনগুলো অনুসরণ করুন:
- ঘন ঘন কনফিগারেশন পরিবর্তনের জন্য প্রস্তুত থাকুন: এপিআই লেভেল, ফর্ম ফ্যাক্টর বা ইউআই টুলকিট নির্বিশেষে, কনফিগারেশন পরিবর্তন বিরল বা কখনোই হয় না—এমনটা ধরে নেবেন না। যখন কোনো ব্যবহারকারী কনফিগারেশন পরিবর্তন করেন, তখন তিনি আশা করেন যে অ্যাপগুলো আপডেট হবে এবং নতুন কনফিগারেশনের সাথে সঠিকভাবে কাজ করতে থাকবে।
- অবস্থা সংরক্ষণ করুন:
Activityপুনরায় তৈরি করার সময় ব্যবহারকারীর অবস্থা যেন হারিয়ে না যায়। UI অবস্থা সংরক্ষণ -এ বর্ণিত পদ্ধতি অনুযায়ী অবস্থা সংরক্ষণ করুন। - দ্রুত সমাধান হিসেবে অপ্ট-আউট করা থেকে বিরত থাকুন: স্টেট হারানোর ঝুঁকি এড়ানোর শর্টকাট হিসেবে
Activityরিক্রিয়েশন থেকে অপ্ট-আউট করবেন না। অ্যাক্টিভিটি রিক্রিয়েশন থেকে অপ্ট-আউট করলে আপনাকে পরিবর্তনটি হ্যান্ডেল করার প্রতিশ্রুতি পূরণ করতে হবে, এবং তারপরেও অন্যান্য কনফিগারেশন পরিবর্তন, প্রসেস ডেথ বা অ্যাপ বন্ধ করার কারণেActivityরিক্রিয়েশনের ফলে আপনি স্টেট হারাতে পারেন।Activityরিক্রিয়েশন সম্পূর্ণরূপে নিষ্ক্রিয় করা অসম্ভব। 'সেভ UI স্টেটস' অংশে বর্ণিত পদ্ধতি অনুযায়ী স্টেট সংরক্ষণ করুন। - কনফিগারেশন পরিবর্তন এড়িয়ে চলবেন না: কনফিগারেশন পরিবর্তন এবং
Activityপুনরায় তৈরি হওয়া এড়ানোর জন্য ওরিয়েন্টেশন, অ্যাসপেক্ট রেশিও বা রিসাইজেবিলিটির উপর বিধিনিষেধ আরোপ করবেন না। এটি সেইসব ব্যবহারকারীদের উপর নেতিবাচক প্রভাব ফেলে, যারা আপনার অ্যাপটি তাদের পছন্দের উপায়ে ব্যবহার করতে চান।
আকার-ভিত্তিক কনফিগারেশন পরিবর্তনগুলি পরিচালনা করুন
আকার-ভিত্তিক কনফিগারেশন পরিবর্তন যেকোনো সময় ঘটতে পারে এবং এর সম্ভাবনা বেশি থাকে যখন আপনার অ্যাপটি বড় স্ক্রিনের ডিভাইসে চলে, যেখানে ব্যবহারকারীরা মাল্টি-উইন্ডো মোডে প্রবেশ করতে পারেন। তারা আশা করেন যে আপনার অ্যাপটি সেই পরিবেশে ভালোভাবে কাজ করবে।
আকারের পরিবর্তন সাধারণত দুই প্রকারের হয়: তাৎপর্যপূর্ণ এবং তাৎপর্যহীন। তাৎপর্যপূর্ণ আকারের পরিবর্তন হলো এমন একটি পরিবর্তন, যেখানে স্ক্রিনের আকারের (যেমন প্রস্থ, উচ্চতা বা সর্বনিম্ন প্রস্থ) ভিন্নতার কারণে নতুন কনফিগারেশনে এক ভিন্ন সেট বিকল্প রিসোর্স প্রযোজ্য হয়। এই রিসোর্সগুলোর মধ্যে অ্যাপটির নিজের সংজ্ঞায়িত রিসোর্স এবং এর যেকোনো লাইব্রেরি থেকে প্রাপ্ত রিসোর্স অন্তর্ভুক্ত থাকে।
আকার-ভিত্তিক কনফিগারেশন পরিবর্তনের জন্য কার্যকলাপের পুনঃসৃষ্টি সীমাবদ্ধ করুন
যখন আপনি আকার-ভিত্তিক কনফিগারেশন পরিবর্তনের জন্য Activity পুনঃসৃষ্টি নিষ্ক্রিয় করেন, তখন সিস্টেম Activity পুনরায় তৈরি করে না। পরিবর্তে, এটি Activity.onConfigurationChanged এ একটি কল গ্রহণ করে। এর সাথে সংযুক্ত যেকোনো ভিউ View.onConfigurationChanged এ একটি কল পায়।
আপনার ম্যানিফেস্ট ফাইলে android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" থাকলে, সাইজ-ভিত্তিক কনফিগারেশন পরিবর্তনের জন্য Activity পুনরায় তৈরি করা নিষ্ক্রিয় থাকে।
আকার-ভিত্তিক কনফিগারেশন পরিবর্তনের জন্য অ্যাক্টিভিটি পুনরায় তৈরির অনুমতি দিন।
অ্যান্ড্রয়েড ৭.০ (এপিআই লেভেল ২৪) এবং এর পরবর্তী সংস্করণগুলিতে, Activity পুনরায় তৈরি করা হয় শুধুমাত্র আকার-ভিত্তিক কনফিগারেশন পরিবর্তনের ক্ষেত্রে, যদি আকারের পরিবর্তনটি উল্লেখযোগ্য হয়। যখন অপর্যাপ্ত আকারের কারণে সিস্টেম কোনো Activity পুনরায় তৈরি করে না, তখন এর পরিবর্তে সিস্টেম Activity.onConfigurationChanged এবং View.onConfigurationChanged কল করতে পারে।
যখন Activity পুনরায় তৈরি করা হয় না, তখন Activity এবং View কলব্যাকগুলির বিষয়ে কিছু সতর্কতা অবলম্বন করতে হবে:
- অ্যান্ড্রয়েড ১১ (এপিআই লেভেল ৩০) থেকে অ্যান্ড্রয়েড ১৩ (এপিআই লেভেল ৩৩) পর্যন্ত,
Activity.onConfigurationChangedকল করা হয় না। - একটি পরিচিত সমস্যা রয়েছে যেখানে Android 12L (API লেভেল 32) এবং Android 13-এর প্রাথমিক সংস্করণগুলিতে (API লেভেল 33) কিছু ক্ষেত্রে
View.onConfigurationChangedকল নাও হতে পারে। আরও তথ্যের জন্য, এই পাবলিক ইস্যুটি দেখুন। পরবর্তী Android 13 রিলিজ এবং Android 14-এ এই সমস্যার সমাধান করা হয়েছে।
যেসব কোড সাইজ-ভিত্তিক কনফিগারেশন পরিবর্তনের জন্য লিসেনিং-এর উপর নির্ভরশীল, সেগুলোর ক্ষেত্রে আমরা Activity রিক্রিয়েশন বা Activity.onConfigurationChanged এর উপর নির্ভর না করে, ওভাররাইড করা View.onConfigurationChanged সহ একটি ইউটিলিটি View ব্যবহার করার পরামর্শ দিই।