এই বিষয়ে Kotlin ভাষার কিছু সবচেয়ে উপযোগী দিক সম্পর্কে আলোচনা করা হয়েছে যা Android-এর জন্য ডেভেলপ করার সময় কাজে লাগে।
ফ্র্যাগমেন্ট নিয়ে কাজ করা
Kotlin-এর সেরা কিছু ফিচার হাইলাইট করতে নিম্নলিখিত বিভাগে Fragmentটি উদাহরণ ব্যবহার করা হয়েছে।
উত্তরাধিকার
আপনি Kotlin-এ class কীওয়ার্ড ব্যবহার করে ক্লাস ঘোষণা করতে পারবেন। নিচের
উদাহরণে, LoginFragment হল Fragment-এর সাবক্লাস। আপনি সাবক্লাস ও তার পেরেন্টের মধ্যে : অপারেটর ব্যবহার করে
ইনহেরিটেন্স দেখাতে পারেন:
class LoginFragment : Fragment()
এই ক্লাস ডিক্লারেশনে, LoginFragment-এর দায়িত্ব হল তার সুপারক্লাস Fragment-এর কনস্ট্রাক্টরকে কল করা।
LoginFragment-এর মধ্যে, আপনার Fragment-এ স্ট্যাটাস পরিবর্তনের উত্তর দিতে
আপনি একাধিক লাইফসাইকেল কলব্যাক ওভাররাইড করতে পারবেন। কোনও ফাংশন ওভাররাইড করতে, override কীওয়ার্ড ব্যবহার করুন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.login_fragment, container, false)
}
প্যারেন্ট ক্লাসে কোনও ফাংশন রেফারেন্স করতে, super কীওয়ার্ড ব্যবহার করুন, যেমনটি নিম্নলিখিত উদাহরণে
দেখানো হয়েছে:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
নালেবিলিটি ও ইনিশিয়ালাইজেশন
আগের উদাহরণে, ওভাররাইড করা পদ্ধতিতে কিছু প্যারামিটারের টাইপের শেষে প্রশ্নচিহ্ন ? আছে। এর থেকে বোঝা যায় যে এইসব প্যারামিটারের জন্য
পাস করা আর্গুমেন্ট ফাঁকা থাকতে পারে। নিরাপদে সেগুলির নালেবিলিটি ম্যানেজ করতে
ভুলবেন না।
Kotlin-এ, অবজেক্ট ঘোষণা করার সময় আপনাকে অবশ্যই অবজেক্টের প্রপার্টি ইনিশিয়ালাইজ করতে হবে।
এর অর্থ হল, আপনি কোনও ক্লাসের ইনস্ট্যান্স পেলে, অবিলম্বে সেটির অ্যাক্সেসযোগ্য যেকোনও প্রপার্টি
রেফারেন্স করতে পারবেন। তবে, Fragment-এ View অবজেক্টগুলি
Fragment#onCreateView কল না করা পর্যন্ত ইনফ্লেট করার জন্য প্রস্তুত নয়, তাই
আপনাকে View-এর জন্য প্রপার্টি ইনিশিয়ালাইজেশন স্থগিত করার একটি উপায় খুঁজে বের করতে হবে।
lateinit আপনাকে প্রপার্টি ইনিশিয়ালাইজেশন স্থগিত রাখতে দেয়। lateinit ব্যবহার করার সময়,
যত তাড়াতাড়ি সম্ভব আপনার প্রপার্টি ইনিশিয়ালাইজ করা উচিত।
নিম্নলিখিত উদাহরণে দেখানো হয়েছে যে কীভাবে lateinit ব্যবহার করে View অবজেক্টকে
onViewCreated-এ অ্যাসাইন করা যায়:
class LoginFragment : Fragment() {
private lateinit var usernameEditText: EditText
private lateinit var passwordEditText: EditText
private lateinit var loginButton: Button
private lateinit var statusTextView: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
usernameEditText = view.findViewById(R.id.username_edit_text)
passwordEditText = view.findViewById(R.id.password_edit_text)
loginButton = view.findViewById(R.id.login_button)
statusTextView = view.findViewById(R.id.status_text_view)
}
...
}
SAM কনভার্সন
আপনি Android-এ ক্লিক ইভেন্ট শোনার জন্য
OnClickListener ইন্টারফেস প্রয়োগ করতে পারেন। Button অবজেক্টে একটি setOnClickListener()
ফাংশন থাকে যা OnClickListener-এর ইমপ্লিমেন্টেশন গ্রহণ করে।
OnClickListener-এ একটিই অ্যাবস্ট্র্যাক্ট মেথড, onClick(), আছে যা আপনাকে
প্রয়োগ করতে হবে। কারণ setOnClickListener() সবসময় আর্গুমেন্ট হিসেবে OnClickListener
নেয় এবং OnClickListener-এর সবসময় একই অ্যাবস্ট্রাক্ট মেথড থাকে,
তাই এই ইমপ্লিমেন্টেশন Kotlin-এ অ্যানোনিমাস ফাংশন ব্যবহার করে
দেখানো যেতে পারে। এই প্রসেসটি
সিঙ্গেল অ্যাবস্ট্রাক্ট মেথড কনভার্সন,
বা SAM কনভার্সন নামে পরিচিত।
SAM কনভার্সন আপনার কোডকে আরও পরিচ্ছন্ন করে তুলতে পারে। নিম্নলিখিত উদাহরণে
দেখানো হয়েছে যে কীভাবে Button-এর জন্য OnClickListener প্রয়োগ করতে
SAM কনভার্সন ব্যবহার করতে হয়:
loginButton.setOnClickListener {
val authSuccessful: Boolean = viewModel.authenticate(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
if (authSuccessful) {
// Navigate to next screen
} else {
statusTextView.text = requireContext().getString(R.string.auth_failed)
}
}
setOnClickListener()-এ পাস করা বেনামী ফাংশনের মধ্যে থাকা কোড
ব্যবহারকারী loginButton-এ ক্লিক করলে এক্সিকিউট হয়।
কম্প্যানিয়ন অবজেক্ট
কম্প্যানিয়ন অবজেক্ট
এমন একটি মেকানিজম প্রদান করে যা ভেরিয়েবল বা ফাংশন সংজ্ঞায়িত করে। এগুলি
ধারণাগতভাবে কোনও টাইপের সাথে লিঙ্ক করা থাকে, তবে কোনও নির্দিষ্ট অবজেক্টের সাথে বাঁধা থাকে না। কম্প্যানিয়ন
অবজেক্ট হল ভেরিয়েবল ও মেথডের জন্য Java-এর static কীওয়ার্ড ব্যবহার করার মতো।
নিচের উদাহরণে, TAG হল একটি String কনস্ট্যান্ট। LoginFragment-এর প্রতিটি ইনস্ট্যান্সের জন্য String-এর অনন্য ইনস্ট্যান্সের প্রয়োজন নেই, তাই আপনাকে এটি একটি কম্প্যানিয়ন অবজেক্টে সংজ্ঞায়িত করতে হবে:
class LoginFragment : Fragment() {
...
companion object {
private const val TAG = "LoginFragment"
}
}
আপনি ফাইলের টপ লেভেলে TAG সংজ্ঞায়িত করতে পারেন, তবে
ফাইলের টপ লেভেলে অনেক ভেরিয়েবল, ফাংশন ও ক্লাসও
সংজ্ঞায়িত করা থাকতে পারে। কম্প্যানিয়ন অবজেক্ট, সেই ক্লাসের কোনও নির্দিষ্ট ইনস্ট্যান্স উল্লেখ না করেই
ভেরিয়েবল, ফাংশন ও ক্লাস ডেফিনেশন কানেক্ট করতে সাহায্য করে।
প্রপার্টি ডেলিগেশন
প্রপার্টি ইনিশিয়ালাইজ করার সময়, আপনি Android-এর আরও সাধারণ কিছু প্যাটার্ন
পুনরাবৃত্তি করতে পারেন, যেমন Fragment-এর মধ্যে ViewModel অ্যাক্সেস করা। অতিরিক্ত ডুপ্লিকেট কোড এড়াতে, আপনি Kotlin-এর প্রপার্টি ডেলিগেশন সিনট্যাক্স ব্যবহার করতে পারেন।
private val viewModel: LoginViewModel by viewModels()
প্রপার্টি ডেলিগেশন একটি সাধারণ ইমপ্লিমেন্টেশন প্রদান করে যা আপনি আপনার অ্যাপ জুড়ে আবার ব্যবহার করতে পারবেন।
Android KTX আপনার জন্য কিছু প্রপার্টি ডেলিগেট প্রদান করে।
viewModels, উদাহরণস্বরূপ, একটি ViewModel পুনরুদ্ধার করে যা বর্তমান Fragment-এর জন্য স্কোপ করা হয়েছে।
প্রপার্টি ডেলিগেশন রিফ্লেকশন ব্যবহার করে, যা পারফর্ম্যান্সের ওভারহেড কিছুটা বাড়িয়ে দেয়। এর ফলে সিনট্যাক্স সংক্ষিপ্ত হয় এবং ডেভেলপমেন্টের সময় বাঁচে।
নালেবিলিটি
Kotlin-এ নালিবিলিটি সংক্রান্ত কঠোর নিয়ম আছে যা আপনার অ্যাপ জুড়ে টাইপ-নিরাপত্তা বজায় রাখে। Kotlin-এ অবজেক্টের রেফারেন্সে ডিফল্ট হিসেবে নাল ভ্যালু থাকতে পারে না। কোনও ভেরিয়েবলে নাল ভ্যালু অ্যাসাইন করতে, আপনাকে বেস টাইপের শেষে ? যোগ করে
নালেবেল ভেরিয়েবল টাইপ ঘোষণা করতে হবে।
উদাহরণ হিসেবে, Kotlin-এ নিম্নলিখিত এক্সপ্রেশনটি অবৈধ। name হল
String ধরনের এবং এটি নালেবেল নয়:
val name: String = null
নাল ভ্যালুর অনুমতি দিতে, আপনাকে অবশ্যই নালেবেল String ধরন, String? ব্যবহার করতে হবে, যেমন
নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
val name: String? = null
ইন্টারঅপারেবিলিটি
Kotlin-এর কঠোর নিয়ম আপনার কোডকে আরও নিরাপদ ও সংক্ষিপ্ত করে তোলে। এইসব নিয়ম NullPointerException-এর সম্ভাবনা কম করে
যার ফলে আপনার অ্যাপ ক্র্যাশ
করতে পারে। এছাড়াও, আপনার কোডে নাল চেক করার সংখ্যাও কমে যায়।
প্রায়ই, Android অ্যাপ লেখার সময় আপনাকে Kotlin-এ লেখা হয়নি এমন কোডও কল করতে হয়, কারণ বেশিরভাগ Android API, Java প্রোগ্রামিং ল্যাঙ্গুয়েজে লেখা হয়।
নালেবিলিটি হল এমন একটি গুরুত্বপূর্ণ ক্ষেত্র যেখানে Java এবং Kotlin-এর আচরণে পার্থক্য দেখা যায়। Java-তে নালেবিলিটি সিনট্যাক্স নিয়ে কড়াকড়ি কম।
উদাহরণস্বরূপ, Account ক্লাসের কিছু প্রপার্টি আছে, যার মধ্যে String
প্রপার্টিকে name বলা হয়। Java-তে Kotlin-এর মতো নালেবিলিটি সংক্রান্ত নিয়ম নেই,
পরিবর্তে আপনি নাল ভ্যালু অ্যাসাইন করতে পারবেন কিনা তা স্পষ্টভাবে ঘোষণা করার জন্য
ঐচ্ছিক নালেবিলিটি অ্যানোটেশন-এর উপর নির্ভর করে।
Android ফ্রেমওয়ার্ক মূলত Java-তে লেখা হয় বলে, নালেবিলিটি অ্যানোটেশন ছাড়া API কল করার সময় আপনি এই পরিস্থিতির সম্মুখীন হতে পারেন।
প্ল্যাটফর্মের ধরন
আপনি যদি Kotlin ব্যবহার করে Java Account ক্লাসে সংজ্ঞায়িত একটি অ্যানোটেট না করা name মেম্বারকে রেফারেন্স করেন, তাহলে কম্পাইলার জানে না যে String Kotlin-এ String বা String?-এ ম্যাপ করে কিনা। এই অস্পষ্টতা প্ল্যাটফর্মের ধরন, String!-এর মাধ্যমে
দেখানো হয়।
Kotlin কম্পাইলারের কাছে String!-এর কোনও বিশেষ অর্থ নেই। String!, String বা String?-এর মধ্যে যেকোনও একটিকে
প্রতিনিধিত্ব করতে পারে এবং কম্পাইলার আপনাকে যেকোনও একটি টাইপের
ভ্যালু অ্যাসাইন করতে দেয়। মনে রাখবেন, আপনি যদি ধরনকে String হিসেবে দেখান এবং একটি নাল ভ্যালু অ্যাসাইন করেন, তাহলে NullPointerException থ্রো করার ঝুঁকি থাকে।
এই সমস্যা সমাধান করতে, Java-তে কোড লেখার সময় আপনাকে নালিবিলিটি অ্যানোটেশন ব্যবহার করতে হবে। এইসব অ্যানোটেশন Java ও Kotlin ডেভেলপারদের সাহায্য করে।
যেমন, Java-তে যেভাবে সংজ্ঞায়িত করা হয়েছে, এখানে Account ক্লাসটি দেওয়া হল:
public class Account implements Parcelable {
public final String name;
public final String type;
private final @Nullable String accessId;
...
}
মেম্বার ভেরিয়েবলগুলির মধ্যে একটি, accessId, @Nullable-এর সাথে অ্যানোটেট করা আছে,
যা ইঙ্গিত করে যে এটি একটি নাল ভ্যালু ধারণ করতে পারে। Kotlin তখন accessId-কে
String? হিসেবে বিবেচনা করবে।
কোনও ভেরিয়েবল কখনও নাল হতে পারে না তা বোঝাতে, @NonNull অ্যানোটেশন ব্যবহার করুন:
public class Account implements Parcelable {
public final @NonNull String name;
...
}
এই পরিস্থিতিতে, Kotlin-এ name-কে নন-নালেবেল String হিসেবে বিবেচনা করা হয়।
নালেবিলিটি অ্যানোটেশন সব নতুন Android API এবং আগে থেকে থাকা অনেক Android API-তে অন্তর্ভুক্ত করা হয়েছে। Kotlin এবং Java ডেভেলপারদের আরও ভালোভাবে সাহায্য করার জন্য অনেক Java লাইব্রেরি নালিবিলিটি অ্যানোটেশন যোগ করেছে।
নালেবিলিটি ম্যানেজ করা
আপনি কোনও Java টাইপ সম্পর্কে নিশ্চিত না হলে, এটি নালেবেল হিসেবে বিবেচনা করা উচিত।
উদাহরণস্বরূপ, Account ক্লাসের name মেম্বার অ্যানোটেট করা নেই, তাই আপনাকে
ধরে নিতে হবে যে এটি নালেবেল String?।
আপনি যদি name ট্রিম করতে চান যাতে এর ভ্যালুতে লিডিং বা ট্রেলিং হোয়াইটস্পেস অন্তর্ভুক্ত না থাকে, তাহলে আপনি Kotlin-এর trim ফাংশন ব্যবহার করতে পারেন। আপনি নিরাপদে কয়েকটি ভিন্ন উপায়ে
String? ট্রিম করতে পারবেন। এর মধ্যে একটি উপায় হল নাল-নয়
অ্যাসার্শন অপারেটর, !! ব্যবহার করা, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
val account = Account("name", "type")
val accountName = account.name!!.trim()
!! অপারেটর তার বাঁদিকে থাকা সবকিছুকে নন-নাল হিসেবে বিবেচনা করে, তাই
এই ক্ষেত্রে, আপনি name-কে নন-নাল String হিসেবে বিবেচনা করছেন। এর বাঁদিকে থাকা এক্সপ্রেশনের ফলাফল ফাঁকা থাকলে, আপনার অ্যাপ NullPointerException থ্রো করে।
এই অপারেটরটি দ্রুত এবং সহজ, তবে এটি খুব কম ব্যবহার করা উচিত, কারণ এটি আপনার কোডে NullPointerException-এর ইনস্ট্যান্স আবার চালু করতে পারে।
আরও নিরাপদ বিকল্প হল সেফ-কল অপারেটর, ?. ব্যবহার করা, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
val account = Account("name", "type")
val accountName = account.name?.trim()
সেফ-কল অপারেটর ব্যবহার করে, name যদি নন-নাল হয়, তাহলে
name?.trim()-এর ফলাফল হল এমন একটি নাম ভ্যালু যার আগে বা পরে কোনও হোয়াইটস্পেস নেই। name
যদি শূন্য হয়, তাহলে name?.trim()-এর ফলাফল null হবে। এর অর্থ হল,
এই স্টেটমেন্ট এক্সিকিউট করার সময় আপনার অ্যাপ কখনই NullPointerException থ্রো করতে পারবে না।
সেফ-কল অপারেটর আপনাকে সম্ভাব্য NullPointerException থেকে রক্ষা করলেও,
এটি পরবর্তী স্টেটমেন্টে একটি নাল ভ্যালু পাস করে। পরিবর্তে, আপনি এলভিস অপারেটর (?:) ব্যবহার করে অবিলম্বে নাল
কেসগুলি হ্যান্ডেল করতে পারেন, যেমনটি নিম্নলিখিত
উদাহরণে দেখানো হয়েছে:
val account = Account("name", "type")
val accountName = account.name?.trim() ?: "Default name"
এলভিস অপারেটরের বাঁদিকে থাকা এক্সপ্রেশনের ফলাফল
ফাঁকা হলে, ডানদিকে থাকা ভ্যালু accountName-এ অ্যাসাইন করা হয়। এই
টেকনিকটি একটি ডিফল্ট ভ্যালু প্রদান করার জন্য উপযোগী যা অন্যথায় শূন্য হবে।
এছাড়াও, আপনি কোনও ফাংশন থেকে তাড়াতাড়ি ফিরে আসতে এলভিস অপারেটর ব্যবহার করতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
fun validateAccount(account: Account?) {
val accountName = account?.name?.trim() ?: "Default name"
// account cannot be null beyond this point
account ?: return
...
}
Android API-তে পরিবর্তন
Android API-গুলি ক্রমবর্ধমানভাবে Kotlin-বান্ধব হয়ে উঠছে। Android-এর অনেক
সবচেয়ে সাধারণ API, যার মধ্যে AppCompatActivity এবং Fragment আছে, তাতে
নালেবিলিটি অ্যানোটেশন আছে এবং Fragment#getContext-এর মতো নির্দিষ্ট কলে
Kotlin-এর সাথে আরও মানানসই বিকল্প আছে।
যেমন, Fragment-এর Context অ্যাক্সেস করা প্রায় সবসময়ই নন-নাল হয়,
কারণ Fragment-এ আপনি যেসব কল করেন তার বেশিরভাগই Fragment-এর সাথে
Activity (Context-এর সাবক্লাস) অ্যাটাচ করা থাকাকালীন হয়। তবে,
Fragment#getContext সবসময় নন-নাল ভ্যালু রিটার্ন করে না, কারণ এমন
পরিস্থিতি হতে পারে যেখানে Fragment-এর সাথে Activity অ্যাটাচ করা নেই। তাই, Fragment#getContext-এর রিটার্ন
টাইপ নালেবেল।
যেহেতু Fragment#getContext থেকে রিটার্ন করা Context নালেবল (এবং @Nullable হিসেবে
অ্যানোটেট করা হয়েছে), তাই আপনার Kotlin কোডে এটিকে Context? হিসেবে বিবেচনা করতে হবে।
এর অর্থ হল, প্রপার্টি ও ফাংশন অ্যাক্সেস করার আগে নালেবিলিটি সমাধান করতে
আগে উল্লেখ করা অপারেটরগুলির মধ্যে একটি প্রয়োগ করা। এইসব পরিস্থিতির মধ্যে কিছু ক্ষেত্রে, Android-এ বিকল্প API আছে যা এই সুবিধা প্রদান করে।
যেমন, Fragment#requireContext একটি নন-নাল Context রিটার্ন করে এবং Context নাল হলে
কল করা হলে একটি IllegalStateException থ্রো করে। এইভাবে,
আপনি নিরাপদ-কল অপারেটর বা ওয়ার্কঅ্যারাউন্ডের প্রয়োজন ছাড়াই
ফলাফল হিসেবে পাওয়া Context-কে নন-নাল হিসেবে বিবেচনা করতে পারবেন।
প্রপার্টি ইনিশিয়ালাইজ করা
Kotlin-এ প্রপার্টি ডিফল্ট হিসেবে ইনিশিয়ালাইজ করা হয় না। তাদের এনক্লোজিং ক্লাস ইনিশিয়ালাইজ করা হলে তাদের অবশ্যই ইনিশিয়ালাইজ করতে হবে।
আপনি কয়েকটি ভিন্ন উপায়ে প্রপার্টি শুরু করতে পারেন। নিম্নলিখিত উদাহরণে
দেখানো হয়েছে যে কীভাবে ক্লাস ডিক্লারেশনে index ভেরিয়েবেলে ভ্যালু অ্যাসাইন করে
সেটি ইনিশিয়ালাইজ করতে হয়:
class LoginFragment : Fragment() {
val index: Int = 12
}
এই ইনিশিয়ালাইজেশন, ইনিশিয়ালাইজার ব্লকেও সংজ্ঞায়িত করা যেতে পারে:
class LoginFragment : Fragment() {
val index: Int
init {
index = 12
}
}
উপরের উদাহরণে, LoginFragment তৈরি করার সময় index
ইনিশিয়ালাইজ করা হয়।
তবে, আপনার কিছু প্রপার্টি থাকতে পারে যা অবজেক্ট কনস্ট্রাকশনের সময় ইনিশিয়ালাইজ করা যায় না। যেমন, আপনি হয়ত Fragment-এর মধ্যে থেকে View-এর রেফারেন্স দিতে চান, যার অর্থ হল লেআউটটি প্রথমে ইনফ্লেট করতে হবে। Fragment তৈরি করার সময়
ইনফ্লেশন হয় না। পরিবর্তে, Fragment#onCreateView-এ কল করার সময় এটি স্ফীত হয়।
এই পরিস্থিতি সামলানোর একটি উপায় হল, ভিউকে নালেবেল হিসেবে ঘোষণা করা এবং যত তাড়াতাড়ি সম্ভব এটি শুরু করা, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
class LoginFragment : Fragment() {
private var statusTextView: TextView? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)
statusTextView?.setText(R.string.auth_failed)
}
}
এটি প্রত্যাশা অনুযায়ী কাজ করলেও, আপনি যখনই View রেফারেন্স করবেন,
আপনাকে এখন অবশ্যই সেটির নালেবিলিটি ম্যানেজ করতে হবে। আরও ভালো সমাধান হল View ইনিশিয়ালাইজেশনের জন্য lateinit ব্যবহার করা, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
class LoginFragment : Fragment() {
private lateinit var statusTextView: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)
statusTextView.setText(R.string.auth_failed)
}
}
lateinit কীওয়ার্ড আপনাকে কোনও অবজেক্ট তৈরি করার সময় প্রপার্টি ইনিশিয়ালাইজ করা এড়াতে
সাহায্য করে। আপনার প্রপার্টি ইনিশিয়ালাইজ করার আগে রেফারেন্স করা হলে,
Kotlin একটি UninitializedPropertyAccessException থ্রো করে, তাই যত তাড়াতাড়ি সম্ভব
আপনার প্রপার্টি ইনিশিয়ালাইজ করতে ভুলবেন না।