क्रैश

जब किसी Android ऐप्लिकेशन में, बिना हैंडल किए गए अपवाद या सिग्नल की वजह से अचानक बंद होने की समस्या आती है, तो वह क्रैश हो जाता है. अगर Java या Kotlin का इस्तेमाल करके बनाए गए किसी ऐप्लिकेशन में कोई ऐसी गड़बड़ी होती है जिसे ठीक नहीं किया जा सकता, तो वह क्रैश हो जाता है. इस गड़बड़ी को Throwable क्लास से दिखाया जाता है. मशीन कोड या C++ का इस्तेमाल करके लिखा गया कोई ऐप्लिकेशन, एक्ज़ीक्यूट होने के दौरान SIGSEGV जैसे अनहैंडल किए गए सिग्नल मिलने पर क्रैश हो जाता है.

जब कोई ऐप्लिकेशन क्रैश होता है, तो Android उस ऐप्लिकेशन की प्रोसेस को बंद कर देता है. साथ ही, उपयोगकर्ता को यह बताने के लिए एक डायलॉग दिखाता है कि ऐप्लिकेशन बंद हो गया है. जैसा कि पहली इमेज में दिखाया गया है.

Android पर चलने वाले डिवाइस पर ऐप्लिकेशन क्रैश होना
पहली इमेज. Android पर चलने वाले डिवाइस पर ऐप्लिकेशन क्रैश हो गया.

किसी ऐप्लिकेशन के क्रैश होने के लिए, उसका फ़ोरग्राउंड में चलना ज़रूरी नहीं है. ऐप्लिकेशन का कोई भी कॉम्पोनेंट, ऐप्लिकेशन के क्रैश होने की वजह बन सकता है. भले ही, वह कॉम्पोनेंट बैकग्राउंड में चल रहा हो. जैसे, ब्रॉडकास्ट रिसीवर या कॉन्टेंट प्रोवाइडर. ये क्रैश, उपयोगकर्ताओं के लिए अक्सर भ्रम की स्थिति पैदा करते हैं. ऐसा इसलिए होता है, क्योंकि वे आपके ऐप्लिकेशन का इस्तेमाल नहीं कर रहे थे.

अगर आपका ऐप्लिकेशन क्रैश हो रहा है, तो इस पेज पर दिए गए निर्देशों का इस्तेमाल करके समस्या का पता लगाया जा सकता है और उसे ठीक किया जा सकता है.

समस्या का पता लगाना

ऐसा हो सकता है कि आपको हमेशा यह पता न चले कि आपके ऐप्लिकेशन का इस्तेमाल करते समय, लोगों को क्रैश की समस्या आ रही है. अगर आपने पहले ही अपना ऐप्लिकेशन पब्लिश कर दिया है, तो Android की ज़रूरी जानकारी का इस्तेमाल करके, अपने ऐप्लिकेशन के क्रैश रेट देखे जा सकते हैं.

Android की ज़रूरी जानकारी

Android की ज़रूरी जानकारी की मदद से, ऐप्लिकेशन के क्रैश रेट को मॉनिटर किया जा सकता है और उसे बेहतर बनाया जा सकता है. 'Android की ज़रूरी जानकारी' में, क्रैश रेट को कई तरह से मेज़र किया जाता है:

  • क्रैश रेट: हर दिन के सक्रिय उपयोगकर्ताओं का प्रतिशत जिन्हें किसी भी तरह के क्रैश का पता चला.
  • यूज़र-पर्सीव्ड क्रैश रेट: हर दिन के ऐसे सक्रिय उपयोगकर्ताओं का प्रतिशत जिन्होंने ऐप्लिकेशन का इस्तेमाल करते समय कम से कम एक बार क्रैश होने की गड़बड़ी का सामना किया (यूज़र-पर्सीव्ड क्रैश). अगर कोई ऐप्लिकेशन कोई गतिविधि दिखा रहा है या कोई फ़ोरग्राउंड सेवा चालू कर रहा है, तो उसे ऐक्टिव माना जाता है.

  • मल्टिपल क्रैश रेट: हर दिन के सक्रिय उपयोगकर्ताओं का प्रतिशत जिन्होंने कम से कम दो बार क्रैश की गड़बड़ी का सामना किया.

हर दिन का सक्रिय उपयोगकर्ता, ऐसा यूनीक उपयोगकर्ता होता है जो एक दिन में एक ही डिवाइस पर आपके ऐप्लिकेशन का इस्तेमाल करता है. ऐसा हो सकता है कि वह एक से ज़्यादा सेशन में ऐप्लिकेशन का इस्तेमाल करे. अगर कोई उपयोगकर्ता आपके ऐप्लिकेशन का इस्तेमाल एक दिन में एक से ज़्यादा डिवाइसों पर करता है, तो उस दिन सक्रिय उपयोगकर्ता की गिनती इस्तेमाल किए गए डिवाइस के अनुसार की जाएगी. अगर एक दिन में कई उपयोगकर्ता एक ही डिवाइस का इस्तेमाल करते हैं, तो उन सभी की गिनती एक सक्रिय उपयोगकर्ता के तौर पर की जाएगी.

यूज़र-पर्सीव्ड क्रैश रेट, ऐप्लिकेशन के लिए सबसे ज़रूरी जानकारी की तरह होता है. इसका मतलब है कि इसका असर इस बात पर भी पड़ता है कि Google Play पर आपके ऐप्लिकेशन को लोग आसानी से खोज पा रहे हैं या नहीं. यूज़र-पर्सीव्ड क्रैश रेट बहुत ही ज़रूरी जानकारी होती है. इसमें उन क्रैश की गिनती की जाती है जिनसे उपयोगकर्ता को आपका ऐप्लिकेशन इस्तेमाल करते समय अक्सर सामना करना पड़ता है. साथ ही, इनसे ऐप्लिकेशन में सबसे ज़्यादा क्रैश और फ़्रीज़ होने जैसी समस्याएं भी आती हैं.

Play ने इस मेट्रिक के लिए, ऐप्लिकेशन की खराब परफ़ॉर्मेंस के दो थ्रेशोल्ड तय किए हैं:

  • सभी डिवाइस मॉडल पर ऐप्लिकेशन की खराब परफ़ॉर्मेंस का थ्रेशोल्ड: हर दिन के सक्रिय उपयोगकर्ताओं में से कम से कम 1.09% लोगों को सभी डिवाइस मॉडल पर यूज़र-पर्सीव्ड क्रैश का सामना करना पड़ता है.
  • किसी खास डिवाइस मॉडल पर ऐप्लिकेशन की खराब परफ़ॉर्मेंस की थ्रेशोल्ड वैल्यू: हर दिन के सक्रिय उपयोगकर्ताओं में से कम से कम 8% लोगों को किसी खास डिवाइस मॉडल पर यूज़र-पर्सीव्ड क्रैश का सामना करना पड़ता है.

अगर आपके ऐप्लिकेशन की खराब परफ़ॉर्मेंस का थ्रेशोल्ड, तय किए गए थ्रेशोल्ड से ज़्यादा है, तो उसे सभी डिवाइसों पर खोजे जाने की संभावना कम हो सकती है. अगर आपके ऐप्लिकेशन की खराब परफ़ॉर्मेंस का थ्रेशोल्ड, कुछ डिवाइसों पर हर डिवाइस के लिए तय किए गए थ्रेशोल्ड से ज़्यादा है, तो उन डिवाइसों पर आपके ऐप्लिकेशन को खोजे जाने की संभावना कम हो सकती है. साथ ही, आपके स्टोर पेज पर चेतावनी दिख सकती है.

अगर आपका ऐप्लिकेशन बहुत ज़्यादा क्रैश हो रहा है, तो Android की ज़रूरी जानकारी देने वाली सुविधा, Play Console में आपको इसकी सूचना दे सकती है.

Google Play, Android की ज़रूरी जानकारी का डेटा कैसे इकट्ठा करता है, इस बारे में जानने के लिए Play Console का दस्तावेज़ देखें.

क्रैश की वजह का पता लगाना

जब आपको पता चल जाए कि आपका ऐप्लिकेशन क्रैश हो रहा है, तो अगला चरण यह पता लगाना है कि ऐसा क्यों हो रहा है. क्रैश की समस्याओं को ठीक करना मुश्किल हो सकता है. हालांकि, अगर आपको क्रैश होने की मुख्य वजह का पता चल जाता है, तो हो सकता है कि आपको इसका समाधान मिल जाए.

ऐसी कई स्थितियां हो सकती हैं जिनकी वजह से आपका ऐप्लिकेशन क्रैश हो सकता है. कुछ वजहें साफ़ तौर पर दिखती हैं. जैसे, शून्य वैल्यू या खाली स्ट्रिंग की जांच करना. हालांकि, अन्य वजहें ज़्यादा जटिल होती हैं. जैसे, किसी एपीआई को अमान्य आर्ग्युमेंट पास करना या मल्टीथ्रेड वाले जटिल इंटरैक्शन.

Android डिवाइस पर, ऐप्लिकेशन बंद होने की समस्याओं की वजह से स्टैक ट्रेस बनती है. स्टैक ट्रेस, नेस्ट किए हुए उन फ़ंक्शन के क्रम का स्नैपशॉट है जो ऐप्लिकेशन बंद होने के समय तक आपके प्रोग्राम में इस्तेमाल किए जा रहे थे. Android की ज़रूरी जानकारी में जाकर, क्रैश के स्टैक ट्रेस देखे जा सकते हैं.

स्टैक ट्रेस को कैसे पढ़ें

क्रैश की समस्या को ठीक करने के लिए, सबसे पहले यह पता लगाएं कि यह समस्या कहां हो रही है. अगर Play Console या logcat टूल का इस्तेमाल किया जा रहा है, तो रिपोर्ट की ज़्यादा जानकारी में उपलब्ध स्टैक ट्रेस का इस्तेमाल किया जा सकता है. अगर आपके पास स्टैक ट्रेस उपलब्ध नहीं है, तो आपको क्रैश को स्थानीय तौर पर फिर से बनाना होगा. इसके लिए, ऐप्लिकेशन की मैन्युअल तरीके से जांच करें या उन उपयोगकर्ताओं से संपर्क करें जिन पर इसका असर पड़ा है. इसके बाद, logcat का इस्तेमाल करके इसे फिर से बनाएं.

यहां दिए गए ट्रेस में, Jetpack Compose का इस्तेमाल करके लिखे गए ऐप्लिकेशन में क्रैश होने का उदाहरण दिखाया गया है:

--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.developer.crashsample, PID: 3686
java.lang.NullPointerException
    at com.android.developer.crashsample.ComposableSingletons$MainActivityKt.lambda$0(MainActivity.kt:27)
    at androidx.compose.foundation.ClickableNode.handleUpEvent(Clickable.kt:958)
    at androidx.compose.foundation.ClickableNode.onPointerEvent-H0pRuoY(Clickable.kt:895)
    at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:446)
    at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:181)
    at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:118)
    at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:2650)
    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2969)
    at android.app.Activity.dispatchTouchEvent(Activity.java:4683)
    at android.os.Looper.loop(Looper.java:398)
    at android.app.ActivityThread.main(ActivityThread.java:9569)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:918)

स्टैक ट्रेस में दो तरह की जानकारी दिखती है. क्रैश को डीबग करने के लिए, यह जानकारी बहुत ज़रूरी होती है:

  • अपवाद किस तरह का है.
  • कोड का वह सेक्शन जहां अपवाद थ्रो किया गया है.

आम तौर पर, थ्रो किए गए अपवाद का टाइप, इस बात का बहुत अहम सुराग होता है कि क्या गड़बड़ी हुई है. देखें कि यह IOException है, OutOfMemoryError है या कुछ और. इसके बाद, अपवाद क्लास के बारे में दस्तावेज़ ढूंढें.

स्टैक ट्रेस की दूसरी लाइन में, सोर्स फ़ाइल का क्लास, तरीका, फ़ाइल, और लाइन नंबर दिखाया जाता है. इस फ़ाइल में अपवाद थ्रो किया जाता है. कॉल किए गए हर फ़ंक्शन के लिए, दूसरी लाइन में पिछली कॉल साइट (जिसे स्टैक फ़्रेम कहा जाता है) दिखती है.

स्टैक में ऊपर की ओर जाकर और कोड की जांच करके, आपको ऐसी जगह मिल सकती है जहां गलत वैल्यू पास की जा रही है. अगर आपका कोड स्टैक ट्रेस में नहीं दिखता है, तो हो सकता है कि आपने किसी जगह पर, एसिंक्रोनस ऑपरेशन में अमान्य पैरामीटर पास किया हो. स्टैक ट्रेस की हर लाइन की जांच करके, यह पता लगाया जा सकता है कि क्या हुआ. साथ ही, यह भी पता लगाया जा सकता है कि आपने किन एपीआई क्लास का इस्तेमाल किया है. इसके अलावा, यह पुष्टि की जा सकती है कि आपने जो पैरामीटर पास किए हैं वे सही हैं और आपने इसे ऐसी जगह से कॉल किया है जहां इसकी अनुमति है.

C और C++ कोड वाले ऐप्लिकेशन के लिए स्टैक ट्रेस, इसी तरह काम करते हैं.

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/foo/bar:10/123.456/78910:user/release-keys'
ABI: 'arm64'
Timestamp: 2020-02-16 11:16:31+0100
pid: 8288, tid: 8288, name: com.example.testapp  >>> com.example.testapp <<<
uid: 1010332
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Cause: null pointer dereference
    x0  0000007da81396c0  x1  0000007fc91522d4  x2  0000000000000001  x3  000000000000206e
    x4  0000007da8087000  x5  0000007fc9152310  x6  0000007d209c6c68  x7  0000007da8087000
    x8  0000000000000000  x9  0000007cba01b660  x10 0000000000430000  x11 0000007d80000000
    x12 0000000000000060  x13 0000000023fafc10  x14 0000000000000006  x15 ffffffffffffffff
    x16 0000007cba01b618  x17 0000007da44c88c0  x18 0000007da943c000  x19 0000007da8087000
    x20 0000000000000000  x21 0000007da8087000  x22 0000007fc9152540  x23 0000007d17982d6b
    x24 0000000000000004  x25 0000007da823c020  x26 0000007da80870b0  x27 0000000000000001
    x28 0000007fc91522d0  x29 0000007fc91522a0
    sp  0000007fc9152290  lr  0000007d22d4e354  pc  0000007cba01b640

backtrace:
  #00  pc 0000000000042f89  /data/app/com.example.testapp/lib/arm64/libexample.so (com::example::Crasher::crash() const)
  #01  pc 0000000000000640  /data/app/com.example.testapp/lib/arm64/libexample.so (com::example::runCrashThread())
  #02  pc 0000000000065a3b  /system/lib/libc.so (__pthread_start(void*))
  #03  pc 000000000001e4fd  /system/lib/libc.so (__start_thread)

अगर आपको नेटिव स्टैक ट्रेस में क्लास और फ़ंक्शन-लेवल की जानकारी नहीं दिखती है, तो आपको नेटिव डीबग सिंबल वाली फ़ाइल जनरेट करनी पड़ सकती है. इसके बाद, इसे Google Play Console पर अपलोड करें. ज़्यादा जानकारी के लिए, क्रैश स्टैक ट्रेस को डिकोड करना लेख पढ़ें. नेटिव क्रैश के बारे में सामान्य जानकारी के लिए, नेटिव क्रैश की जांच करना लेख पढ़ें.

क्रैश को फिर से जनरेट करने के लिए सलाह

ऐसा हो सकता है कि सिर्फ़ एम्युलेटर शुरू करने या अपने डिवाइस को कंप्यूटर से कनेक्ट करने पर, समस्या को ठीक से न दोहराया जा सके. डेवलपमेंट एनवायरमेंट में, बैंडविड्थ, मेमोरी, और स्टोरेज जैसे ज़्यादा संसाधन होते हैं. अपवाद के टाइप का इस्तेमाल करके, यह पता लगाएं कि कौनसे संसाधन की कमी हो सकती है. इसके अलावा, Android के वर्शन, डिवाइस टाइप या आपके ऐप्लिकेशन के वर्शन के बीच संबंध का पता लगाएं.

मेमोरी की गड़बड़ियां

अगर आपके पास OutOfMemoryError है, तो जांच करने के लिए कम मेमोरी क्षमता वाला एम्युलेटर बनाया जा सकता है. दूसरी इमेज में, AVD मैनेजर की सेटिंग दिखाई गई हैं. यहां डिवाइस की मेमोरी को कंट्रोल किया जा सकता है.

AVD मैनेजर पर मेमोरी की सेटिंग
दूसरी इमेज. AVD मैनेजर पर मेमोरी सेटिंग.

नेटवर्किंग से जुड़े अपवाद

उपयोगकर्ता अक्सर मोबाइल या वाई-फ़ाई नेटवर्क कवरेज में आते-जाते रहते हैं. इसलिए, ऐप्लिकेशन नेटवर्क से जुड़ी समस्याओं को आम तौर पर गड़बड़ियों के तौर पर नहीं माना जाना चाहिए. इसके बजाय, इन्हें सामान्य ऑपरेटिंग स्थितियां माना जाना चाहिए जो अचानक होती हैं.

अगर आपको नेटवर्क से जुड़ी किसी समस्या को फिर से देखना है, जैसे कि UnknownHostException, तो अपने ऐप्लिकेशन के नेटवर्क का इस्तेमाल करने के दौरान, फ़्लाइट मोड चालू करके देखें.

इसके अलावा, नेटवर्क की स्पीड कम करने के लिए, नेटवर्क स्पीड इम्यूलेशन, नेटवर्क में देरी या दोनों को चुना जा सकता है. AVD मैनेजर पर, स्पीड और लेटेंसी सेटिंग का इस्तेमाल किया जा सकता है. इसके अलावा, यहां दिए गए कमांड-लाइन के उदाहरण में दिखाए गए तरीके से, -netdelay और -netspeed फ़्लैग के साथ एम्युलेटर शुरू किया जा सकता है:

emulator -avd [your-avd-image] -netdelay 20000 -netspeed gsm

इस उदाहरण में, सभी नेटवर्क अनुरोधों के लिए 20 सेकंड की देरी और अपलोड और डाउनलोड की स्पीड 14.4 केबीपीएस पर सेट की गई है. एम्युलेटर के लिए कमांड-लाइन विकल्पों के बारे में ज़्यादा जानने के लिए, कमांड लाइन से एम्युलेटर शुरू करना लेख पढ़ें.

logcat की मदद से लॉग पढ़ना

क्रैश की समस्या को दोहराने के बाद, ज़्यादा जानकारी पाने के लिए logcat जैसे टूल का इस्तेमाल किया जा सकता है.

logcat आउटपुट में, आपको प्रिंट किए गए अन्य लॉग मैसेज दिखेंगे. साथ ही, सिस्टम से जुड़े अन्य मैसेज भी दिखेंगे. आपने जो भी अतिरिक्त Log स्टेटमेंट जोड़े हैं उन्हें बंद करना न भूलें. ऐसा इसलिए, क्योंकि ऐप्लिकेशन के चालू रहने के दौरान, उन्हें प्रिंट करने से सीपीयू और बैटरी की खपत होती है.

शून्य पॉइंटर अपवादों की वजह से होने वाली क्रैश की समस्याओं को रोकना

शून्य पॉइंटर अपवाद (जिन्हें रनटाइम गड़बड़ी के टाइप NullPointerException से पहचाना जाता है) तब होते हैं, जब किसी ऐसे ऑब्जेक्ट को ऐक्सेस करने की कोशिश की जाती है जो शून्य है. आम तौर पर, ऐसा उसके तरीकों को लागू करके या उसके सदस्यों को ऐक्सेस करके किया जाता है. Google Play पर ऐप्लिकेशन क्रैश होने की सबसे बड़ी वजह, नल पॉइंटर एक्सेप्शन हैं. null का मतलब है कि ऑब्जेक्ट मौजूद नहीं है. उदाहरण के लिए, इसे अभी तक बनाया या असाइन नहीं किया गया है.

नल पॉइंटर अपवादों से बचने के लिए, आपको यह पक्का करना होगा कि जिन ऑब्जेक्ट रेफ़रंस के साथ काम किया जा रहा है वे गैर-शून्य हों. ऐसा तब करना होगा, जब आपको उन पर तरीकों को कॉल करना हो या उनके सदस्यों को ऐक्सेस करना हो. अगर ऑब्जेक्ट रेफ़रंस शून्य है, तो इस स्थिति को अच्छी तरह से हैंडल करें. उदाहरण के लिए, ऑब्जेक्ट रेफ़रंस पर कोई भी कार्रवाई करने से पहले, किसी तरीके से बाहर निकलें और डीबग लॉग में जानकारी लिखें.

आपको कॉल की गई हर विधि के हर पैरामीटर के लिए, शून्य की जांच नहीं करनी है. इसलिए, शून्य होने की स्थिति को दिखाने के लिए, आईडीई या ऑब्जेक्ट के टाइप पर भरोसा किया जा सकता है.

Kotlin

Kotlin में, शून्य वैल्यू, टाइप सिस्टम का हिस्सा होती है. उदाहरण के लिए, किसी वैरिएबल को शुरू से ही शून्य हो सकने वाला या शून्य नहीं हो सकने वाला घोषित करना ज़रूरी है. नल वैल्यू स्वीकार करने वाले टाइप को ? से मार्क किया जाता है:

// non-null
var s: String = "Hello"

// null
var s: String? = "Hello"

शून्य नहीं हो सकने वाले वैरिएबल को शून्य वैल्यू असाइन नहीं की जा सकती. साथ ही, शून्य हो सकने वाले वैरिएबल को गैर-शून्य के तौर पर इस्तेमाल करने से पहले, यह देखना ज़रूरी है कि वे शून्य हो सकते हैं या नहीं.

अगर आपको साफ़ तौर पर शून्य की जांच नहीं करनी है, तो ?. सुरक्षित कॉल ऑपरेटर का इस्तेमाल करें:

val length: Int? = string?.length  // length is a nullable int
                                   // if string is null, then length is null

सबसे सही तरीका यह है कि आप किसी ऐसे ऑब्जेक्ट के लिए नल केस को हैंडल करें जिसमें नल वैल्यू हो सकती है. ऐसा न करने पर, आपका ऐप्लिकेशन अनचाही स्थितियों में फंस सकता है. NullPointerException का इस्तेमाल करने पर, अगर आपका ऐप्लिकेशन अब क्रैश नहीं होता है, तो आपको इन गड़बड़ियों के बारे में पता नहीं चलेगा.

शून्य की जांच करने के कुछ तरीके यहां दिए गए हैं:

  • if चेक

    val length = if(string != null) string.length else 0
    

    स्मार्ट-कास्ट और शून्य की जांच की वजह से, Kotlin कंपाइलर को पता है कि स्ट्रिंग वैल्यू शून्य नहीं है. इसलिए, यह आपको सुरक्षित कॉल ऑपरेटर के बिना सीधे तौर पर रेफ़रंस का इस्तेमाल करने की अनुमति देता है.

  • ?: एल्विस ऑपरेटर

    इस ऑपरेटर की मदद से, यह तय किया जा सकता है कि "अगर ऑब्जेक्ट शून्य नहीं है, तो ऑब्जेक्ट दिखाएं. ऐसा न होने पर, कोई और ऑब्जेक्ट दिखाएं".

    val length = string?.length ?: 0
    

Kotlin में अब भी NullPointerException का इस्तेमाल किया जा सकता है. आम तौर पर, ये स्थितियां देखने को मिलती हैं:

  • जब आपने साफ़ तौर पर NullPointerException थ्रो किया हो.
  • null assertion !! operator का इस्तेमाल करते समय. यह ऑपरेटर, हर वैल्यू को गैर-शून्य टाइप में बदल देता है. अगर वैल्यू शून्य है, तो NullPointerException दिखाता है.
  • जब किसी प्लैटफ़ॉर्म टाइप के शून्य रेफ़रंस को ऐक्सेस किया जा रहा हो.

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

प्लैटफ़ॉर्म टाइप, Java से मिलने वाले ऑब्जेक्ट डिक्लेरेशन होते हैं. इन टाइप को खास तौर पर ट्रीट किया जाता है; इनमें null की जांच नहीं की जाती. इसलिए, non-null होने की गारंटी Java के जैसी ही होती है. किसी प्लैटफ़ॉर्म टाइप के रेफ़रंस को ऐक्सेस करने पर, Kotlin कंपाइल टाइम की गड़बड़ियां नहीं बनाता. हालांकि, इन रेफ़रंस की वजह से रनटाइम की गड़बड़ियां हो सकती हैं. Kotlin के दस्तावेज़ में दिया गया यह उदाहरण देखें:

val list = ArrayList<String>() // non-null (constructor result) list.add("Item")
val size = list.size // non-null (primitive int) val item = list[0] // platform
type inferred (ordinary Java object) item.substring(1) // allowed, may throw an
                                                       // exception if item == null

जब किसी प्लैटफ़ॉर्म वैल्यू को Kotlin वैरिएबल असाइन किया जाता है, तब Kotlin टाइप इन्फ़रेंस पर निर्भर करता है. इसके अलावा, यह भी तय किया जा सकता है कि किस टाइप की वैल्यू की उम्मीद है. Java से आने वाले किसी रेफ़रंस की शून्यता की स्थिति सही है या नहीं, यह पक्का करने का सबसे अच्छा तरीका है कि Java कोड में शून्यता एनोटेशन (उदाहरण के लिए, @Nullable) का इस्तेमाल किया जाए. Kotlin कंपाइलर, इन रेफ़रंस को प्लैटफ़ॉर्म टाइप के तौर पर नहीं, बल्कि शून्य वैल्यू वाले या शून्य वैल्यू वाले टाइप के तौर पर दिखाएगा.

Java Jetpack API को ज़रूरत के मुताबिक @Nullable या @NonNull के साथ एनोटेट किया गया है. साथ ही, Android 11 SDK में भी इसी तरीके का इस्तेमाल किया गया है. इस SDK टूल से मिलने वाले टाइप, Kotlin में इस्तेमाल किए जाते हैं. इन्हें सही तरीके से, वैल्यू न होने की स्थिति वाले या वैल्यू होने की स्थिति वाले टाइप के तौर पर दिखाया जाएगा.

Kotlin का टाइप सिस्टम, NullPointerException क्रैश को काफ़ी हद तक कम कर देता है. उदाहरण के लिए, Google Home ऐप्लिकेशन में नई सुविधाओं को Kotlin पर माइग्रेट करने के दौरान, नल पॉइंटर एक्सेप्शन की वजह से होने वाली क्रैश की संख्या में 30% की कमी आई.