Android के साथ सामान्य Kotlin पैटर्न का इस्तेमाल करना

इस विषय में, Kotlin लैंग्वेज के कुछ सबसे काम के पहलुओं पर फ़ोकस किया गया है जब उसे Android के लिए डेवलप किया जा रहा हो.

फ़्रैगमेंट के साथ काम करना

Kotlin के कुछ सेक्शन को हाइलाइट करने के लिए, नीचे दिए गए सेक्शन में Fragment के उदाहरण का इस्तेमाल किया गया है बेहतरीन सुविधाएँ शामिल हैं.

Inheritance

आपके पास class कीवर्ड का इस्तेमाल करके, Kotlin में क्लास का एलान करने का विकल्प है. निम्न में उदाहरण के लिए, 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 का इस्तेमाल करते समय, तो आपको अपनी प्रॉपर्टी जल्द से जल्द शुरू करनी चाहिए.

इस उदाहरण में, View ऑब्जेक्ट असाइन करने के लिए, lateinit का इस्तेमाल करने के बारे में बताया गया है 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)
    }

    ...
}

एसएएम कन्वर्ज़न

Android में क्लिक इवेंट सुनने के लिए, OnClickListener इंटरफ़ेस. Button ऑब्जेक्ट में setOnClickListener() है फ़ंक्शन है, जो OnClickListener को लागू करता है.

OnClickListener में onClick() का एक ऐब्स्ट्रैक्ट तरीका है, जो आपको लागू करें. क्योंकि setOnClickListener() हमेशा OnClickListener को एक तर्क दिया गया है और क्योंकि OnClickListener में हमेशा एक ही ऐब्स्ट्रैक्ट होता है विधि है, तो इस कार्यान्वयन को Kotlin. इस प्रक्रिया को एक ऐब्स्ट्रैक्ट तरीके का कन्वर्ज़न, या एसएएम कन्वर्ज़न.

एसएएम कन्वर्ज़न आपके कोड को काफ़ी साफ़-सुथरा बना सकता है. यह उदाहरण दिखाता है कि एसएएम कन्वर्ज़न का इस्तेमाल करके,OnClickListener Button:

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 में लिखा जाता है. इसलिए, आपके पास शून्य होने की संभावना वाले एनोटेशन के बिना एपीआई में कॉल करते समय, यह उदाहरण देखें.

प्लैटफ़ॉर्म के टाइप

अगर आप किसी ऐसे name सदस्य का रेफ़रंस देने के लिए Kotlin का इस्तेमाल करते हैं जिसकी व्याख्या नहीं की गई है, तो Java की Account क्लास का इस्तेमाल करते समय, कंपाइलर को यह नहीं पता होता कि String Kotlin में String या String?. इस अस्पष्टता को platform type, String!.

String! का Kotlin कंपाइलर के लिए कोई खास मतलब नहीं होता है. String! ने प्रतिनिधि के तौर पर कोई String या String? होता है और कंपाइलर से आपको कोई भी टाइप करें. ध्यान रखें कि आपको NullPointerException फेंकने का जोखिम होता है, अगर टाइप को String के तौर पर दिखाएं और शून्य वैल्यू असाइन करें.

इस समस्या को हल करने के लिए, लिखते समय शून्य होने वाली जानकारी का इस्तेमाल करना चाहिए में कोड हो सकते हैं. इन एनोटेशन से Java और Kotlin डेवलपर, दोनों को मदद मिलती है.

उदाहरण के लिए, यहां Account क्लास दी गई है, जैसा कि इसे Java में तय किया गया है:

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. कई Java लाइब्रेरी ने, शून्य वाले होने के एनोटेशन को बेहतर तरीके से जोड़ा है Kotlin और Java डेवलपर, दोनों के साथ काम करते हैं.

शून्य होने की क्षमता को मैनेज करना

अगर आप Java के प्रकार को लेकर पक्का नहीं हैं, तो आपको इसे शून्य के लायक मानना चाहिए. उदाहरण के लिए, Account क्लास के name सदस्य के बारे में जानकारी नहीं दी गई है. इसलिए, आपको यह मान लिया जाना चाहिए कि यह शून्य होने लायक String है.

अगर आपको name को ट्रिम करना है, ताकि उसकी वैल्यू में सबसे पहले या खाली सफ़ेद जगह के बाद, Kotlin के trim फ़ंक्शन का इस्तेमाल किया जा सकता है. आपके पास String? को अलग-अलग तरीकों से आज़माएं. इनमें से एक तरीका यह है कि not-null का इस्तेमाल करें दावा ऑपरेटर, !!, जैसा कि इस उदाहरण में दिखाया गया है:

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 से बचाता है, लेकिन यह अगले स्टेटमेंट के लिए शून्य वैल्यू पास करता है. इसके बजाय आप शून्य को हैंडल कर सकते हैं Elvis ऑपरेटर (?:) का इस्तेमाल करके ऐसे मामले तुरंत लागू कर दिए जाते हैं, जैसा कि नीचे दिखाया गया है उदाहरण:

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 के एपीआई, Kotlin के लिए काफ़ी मददगार होते जा रहे हैं. Android के कई AppCompatActivity और Fragment सहित ज़्यादातर सामान्य एपीआई में, अमान्य एनोटेशन और Fragment#getContext जैसे कुछ कॉल में Kotlin-फ़्रेंडली विकल्प.

उदाहरण के लिए, Fragment के Context का इस्तेमाल करना हमेशा शून्य नहीं होता है, क्योंकि Fragment में ज़्यादातर कॉल किए जाते हैं, जबकि Fragment एक Activity (Context की सब-क्लास) से अटैच है. हालांकि, Fragment#getContext हमेशा ऐसी वैल्यू नहीं दिखाता जो शून्य नहीं होती, क्योंकि ऐसी वैल्यू होती हैं ऐसे मामले जहां Fragment, Activity के साथ अटैच नहीं होता. इस तरह, रिटर्न Fragment#getContext का टाइप अमान्य है.

Fragment#getContext से रिस्पॉन्स के तौर पर मिला Context अमान्य है (और यह है @Nullable के तौर पर एनोटेट किया गया है), तो आपको अपने Kotlin कोड में इसे Context? के तौर पर मानना होगा. इसका मतलब है कि आईपी पते के लिए, ऊपर बताए गए किसी ऑपरेटर को लागू करना अमान्य वैल्यू मिल जाएगी. इनमें से कुछ के लिए की तरह, Android में यह सुविधा देने वाले वैकल्पिक एपीआई शामिल हैं. उदाहरण के लिए, Fragment#requireContext, शून्य के अलावा Context दिखाता है और थ्रो एक IllegalStateException, अगर Context के शून्य होने पर कॉल किया जाता है. इस तरह, तो आप नतीजे के तौर पर मिलने वाले Context को बिना शून्य के मान सकते हैं सुरक्षित कॉल ऑपरेटर या समाधान.

प्रॉपर्टी शुरू करना

Kotlin में प्रॉपर्टी डिफ़ॉल्ट रूप से शुरू नहीं होती हैं. इन्हें शुरू किया जाना चाहिए जब उनकी एनक्लोज़िंग क्लास शुरू होती है.

प्रॉपर्टी को अलग-अलग तरीकों से शुरू किया जा सकता है. यह उदाहरण यह दिखाता है कि किसी index वैरिएबल को कैसे शुरू किया जाए. इसके लिए, क्लास का एलान:

class LoginFragment : Fragment() {
    val index: Int = 12
}

इस प्रोसेस को इनिशलाइज़र ब्लॉक में भी तय किया जा सकता है:

class LoginFragment : Fragment() {
    val index: Int

    init {
        index = 12
    }
}

ऊपर दिए गए उदाहरण में, index तब शुरू होता है, जब LoginFragment बनाया गया.

हालांकि, आपके पास कुछ ऐसी प्रॉपर्टी हो सकती हैं जिन्हें ऑब्जेक्ट के दौरान शुरू नहीं किया जा सकता निर्माण. उदाहरण के लिए, हो सकता है कि आपView Fragment का मतलब है कि लेआउट को पहले इनफ़्लेट किया जाना चाहिए. मुद्रास्फीति यह करती है 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 थ्रो करता है, इसलिए पक्का करें कि अपनी प्रॉपर्टी को जल्द से जल्द शुरू करें.