Android आर्किटेक्चर के लिए सुझाव

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

यहां दिए गए सबसे सही तरीकों को विषय के हिसाब से ग्रुप किया गया है. हर तरीके की एक प्राथमिकता होती है, जिससे पता चलता है कि वह सुझाव कितना ज़रूरी है. प्राथमिकताओं की सूची यहां दी गई है:

  • ज़रूर अपनाएं: इस तरीके को तब तक अपनाएं, जब तक यह आपके तरीके से पूरी तरह मेल न खाता हो.
  • अपनाएं: इस तरीके से, आपके ऐप्लिकेशन को बेहतर बनाने में मदद मिल सकती है.
  • ज़रूरी नहीं: इस तरीके से, कुछ मामलों में आपके ऐप्लिकेशन को बेहतर बनाने में मदद मिल सकती है.

लेयर्ड आर्किटेक्चर

हमारा सुझाया गया लेयर्ड आर्किटेक्चर, अलग-अलग काम करने के सिद्धांत पर आधारित है. यह यूज़र इंटरफ़ेस (यूआई) को डेटा मॉडल से चलाता है, सिंगल सोर्स ऑफ़ ट्रुथ के सिद्धांत का पालन करता है, और एक दिशा में डेटा फ़्लो के सिद्धांतों का पालन करता है. लेयर्ड आर्किटेक्चर के लिए, यहां कुछ सबसे सही तरीके दिए गए हैं:

सुझाव ब्यौरा
साफ़ तौर पर तय की गई डेटा लेयर का इस्तेमाल करें. डेटा लेयर, ऐप्लिकेशन के डेटा को बाकी ऐप्लिकेशन के लिए उपलब्ध कराती है. साथ ही, इसमें आपके ऐप्लिकेशन की ज़्यादातर बिज़नेस लॉजिक शामिल होती है.
साफ़ तौर पर तय की गई यूज़र इंटरफ़ेस (यूआई) लेयर का इस्तेमाल करें. यूज़र इंटरफ़ेस (यूआई) लेयर, स्क्रीन पर ऐप्लिकेशन का डेटा दिखाती है. साथ ही, यह उपयोगकर्ता के इंटरैक्शन के लिए मुख्य पॉइंट के तौर पर काम करती है. Jetpack Compose, आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) बनाने के लिए, सुझाया गया मॉर्डन टूलकिट है.
  • छोटे ऐप्लिकेशन में, डेटा लेयर के टाइप को ui पैकेज या मॉड्यूल में रखा जा सकता है.
यूज़र इंटरफ़ेस (यूआई) लेयर के सबसे सही तरीकों के बारे में ज़्यादा जानने के लिए, यूज़र इंटरफ़ेस (यूआई) लेयर देखें.
रिपॉज़िटरी का इस्तेमाल करके, डेटा लेयर से ऐप्लिकेशन का डेटा उपलब्ध कराएं.

पक्का करें कि यूज़र इंटरफ़ेस (यूआई) लेयर में मौजूद कॉम्पोनेंट, जैसे कि कंपोज़ेबल या ViewModels, सीधे डेटा सोर्स से इंटरैक्ट न करें. डेटा सोर्स के उदाहरण:

  • डेटाबेस, DataStore, SharedPreferences, Firebase API.
  • जीपीएस लोकेशन उपलब्ध कराने वाली कंपनियां.
  • ब्लूटूथ डेटा उपलब्ध कराने वाली कंपनियां.
  • नेटवर्क कनेक्टिविटी की स्थिति उपलब्ध कराने वाली कंपनियां.
कोरूटीन और फ़्लो का इस्तेमाल करें. लेयर के बीच कम्यूनिकेट करने के लिए, कोरूटीन और फ़्लो का इस्तेमाल करें.

कोरूटीन के सबसे सही तरीकों के बारे में ज़्यादा जानने के लिए, Android में कोरूटीन के लिए सबसे सही तरीके देखें.

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

यूज़र इंटरफ़ेस (यूआई) लेयर

यूज़र इंटरफ़ेस (यूआई) लेयर का काम, स्क्रीन पर ऐप्लिकेशन का डेटा दिखाना और उपयोगकर्ता के इंटरैक्शन के लिए मुख्य पॉइंट के तौर पर काम करना है. यूज़र इंटरफ़ेस (यूआई) लेयर के लिए, यहां कुछ सबसे सही तरीके दिए गए हैं:

सुझाव ब्यौरा
एक दिशा में डेटा फ़्लो (यूडीएफ़) के सिद्धांत का पालन करें. एक दिशा में डेटा फ़्लो (यूडीएफ़) के सिद्धांतों का पालन करें. इसके तहत, ViewModels, ऑब्ज़र्वर पैटर्न का इस्तेमाल करके यूज़र इंटरफ़ेस (यूआई) की स्थिति को दिखाते हैं. साथ ही, मेथड कॉल के ज़रिए यूज़र इंटरफ़ेस (यूआई) से कार्रवाइयां पाते हैं.
अगर AAC ViewModels के फ़ायदे आपके ऐप्लिकेशन पर लागू होते हैं, तो उनका इस्तेमाल करें. बिज़नेस लॉजिक को हैंडल करने और यूज़र इंटरफ़ेस (यूआई) की स्थिति को यूज़र इंटरफ़ेस (यूआई) के लिए उपलब्ध कराने के लिए, AAC ViewModels का इस्तेमाल करें. साथ ही, ऐप्लिकेशन का डेटा फ़ेच करें.

ViewModel के सबसे सही तरीकों के बारे में ज़्यादा जानने के लिए, आर्किटेक्चर के सुझाव देखें.

ViewModels के फ़ायदों के बारे में ज़्यादा जानने के लिए, ViewModel को बिज़नेस लॉजिक स्टेट होल्डर के तौर पर इस्तेमाल करना देखें.

लाइफ़साइकल के बारे में जानकारी रखने वाले यूज़र इंटरफ़ेस (यूआई) की स्थिति के कलेक्शन का इस्तेमाल करें. लाइफ़साइकल के बारे में जानकारी रखने वाले सही कोरूटीन बिल्डर, collectAsStateWithLifecycle का इस्तेमाल करके, यूज़र इंटरफ़ेस (यूआई) से यूज़र इंटरफ़ेस (यूआई) की स्थिति इकट्ठा करें.

collectAsStateWithLifecycle के बारे में ज़्यादा पढ़ें.

ViewModel से यूज़र इंटरफ़ेस (यूआई) पर इवेंट न भेजें. ViewModel में तुरंत इवेंट प्रोसेस करें और इवेंट को हैंडल करने के नतीजे के साथ, स्थिति को अपडेट करें. यूज़र इंटरफ़ेस (यूआई) के इवेंट के बारे में ज़्यादा जानने के लिए, ViewModel के इवेंट हैंडल करना देखें.
सिंगल-ऐक्टिविटी ऐप्लिकेशन का इस्तेमाल करें. अगर आपके ऐप्लिकेशन में एक से ज़्यादा स्क्रीन हैं, तो स्क्रीन के बीच नेविगेट करने के लिए Navigation 3 का इस्तेमाल करें. साथ ही, अपने ऐप्लिकेशन के लिए डीप लिंक बनाएं.
Jetpack Compose का इस्तेमाल करें. फ़ोन, टैबलेट, फ़ोल्ड किए जा सकने वाले डिवाइसों, और Wear OS के लिए नए ऐप्लिकेशन बनाने के लिए, Jetpack Compose का इस्तेमाल करें.

यहां दिए गए स्निपेट में, लाइफ़साइकल के बारे में जानकारी रखने वाले तरीके से यूज़र इंटरफ़ेस (यूआई) की स्थिति इकट्ठा करने का तरीका बताया गया है:

  @Composable
  fun MyScreen(
      viewModel: MyViewModel = viewModel()
  ) {
      val uiState by viewModel.uiState.collectAsStateWithLifecycle()
  }

ViewModel

ViewModels, यूज़र इंटरफ़ेस (यूआई) की स्थिति उपलब्ध कराने और डेटा लेयर को ऐक्सेस करने के लिए ज़िम्मेदार होते हैं. ViewModels के लिए, यहां कुछ सबसे सही तरीके दिए गए हैं:

सुझाव ब्यौरा
ViewModels को Android लाइफ़साइकल से अलग रखें. ViewModels में, लाइफ़साइकल से जुड़े किसी भी टाइप का रेफ़रंस न रखें. Activity, Context, या Resources को डिपेंडेंसी के तौर पर पास न करें. अगर ViewModel में किसी चीज़ के लिए Context की ज़रूरत है, तो ध्यान से देखें कि वह सही लेयर में है या नहीं.
कोरूटीन और फ़्लो का इस्तेमाल करें.

ViewModel, डेटा या डोमेन लेयर के साथ इंटरैक्ट करने के लिए इनका इस्तेमाल करता है:

  • ऐप्लिकेशन का डेटा पाने के लिए, Kotlin फ़्लो
  • कार्रवाइयां करने के लिए, suspend फ़ंक्शन, viewModelScope का इस्तेमाल करके
स्क्रीन लेवल पर ViewModels का इस्तेमाल करें.

यूज़र इंटरफ़ेस (यूआई) के फिर से इस्तेमाल किए जा सकने वाले हिस्सों में ViewModels का इस्तेमाल न करें. आपको इनमें ViewModels का इस्तेमाल करना चाहिए:

  • स्क्रीन-लेवल कंपोज़ेबल
  • Jetpack Navigation का इस्तेमाल करते समय, डेस्टिनेशन या ग्राफ़

ज़्यादा जटिल कंपोज़ेबल या स्थिति के आधार पर डाइनैमिक व्यवहार वाले कंपोज़ेबल के लिए, ViewModel को सीधे कंपोज़ेबल की कॉल साइट पर स्कोप करने के लिए, rememberViewModelStoreOwner() का इस्तेमाल करें.

फिर से इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट में, सामान्य स्टेट होल्डर क्लास का इस्तेमाल करें. फिर से इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट में जटिलता को हैंडल करने के लिए, सामान्य स्टेट होल्डर क्लास का इस्तेमाल करें. ऐसा करने पर, स्थिति को होस्ट किया जा सकता है और उसे बाहरी तौर पर कंट्रोल किया जा सकता है.
AndroidViewModel का इस्तेमाल न करें. ViewModel क्लास का इस्तेमाल करें, न कि AndroidViewModel का. ViewModel में Application क्लास का इस्तेमाल न करें. इसके बजाय, डिपेंडेंसी को यूज़र इंटरफ़ेस (यूआई) या डेटा लेयर पर ले जाएं.
यूज़र इंटरफ़ेस (यूआई) की स्थिति उपलब्ध कराएं. अपने ViewModels को uiState नाम की एक प्रॉपर्टी के ज़रिए, यूज़र इंटरफ़ेस (यूआई) के लिए डेटा उपलब्ध कराएं. अगर यूज़र इंटरफ़ेस (यूआई) में, डेटा के कई ऐसे हिस्से दिखते हैं जो एक-दूसरे से जुड़े नहीं हैं, तो वीएम, यूज़र इंटरफ़ेस (यूआई) की स्थिति की कई प्रॉपर्टी उपलब्ध करा सकता है.
  • uiState को StateFlow बनाएं.
  • अगर डेटा, हैरारकी की अन्य लेयर से डेटा स्ट्रीम के तौर पर आता है, तो WhileSubscribed(5000) नीति के साथ stateIn ऑपरेटर का इस्तेमाल करके, uiState बनाएं. (यह कोड का उदाहरण देखें.)
  • डेटा लेयर से डेटा की स्ट्रीम न आने वाले आसान मामलों के लिए, MutableStateFlow का इस्तेमाल किया जा सकता है. इसे, न बदलने वाले StateFlow के तौर पर उपलब्ध कराया जाता है.
  • ${Screen}UiState को डेटा क्लास के तौर पर इस्तेमाल किया जा सकता है. इसमें डेटा, गड़बड़ियां, और लोड होने के सिग्नल शामिल हो सकते हैं. अगर अलग-अलग स्थितियां एक-दूसरे से अलग हैं, तो यह क्लास सील की गई क्लास भी हो सकती है.

यहां दिए गए स्निपेट में, ViewModel से यूज़र इंटरफ़ेस (यूआई) की स्थिति उपलब्ध कराने का तरीका बताया गया है:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

लाइफ़साइकल

ऐक्टिविटी लाइफ़साइकल के साथ काम करने के लिए, सबसे सही तरीके अपनाएं:

सुझाव ब्यौरा
Activity लाइफ़साइकल कॉलबैक को ओवरराइड करने के बजाय, कंपोज़ेबल में लाइफ़साइकल के बारे में जानकारी रखने वाले इफ़ेक्ट का इस्तेमाल करें.

यूज़र इंटरफ़ेस (यूआई) से जुड़े टास्क चलाने के लिए, onResume जैसी Activity लाइफ़साइकल के तरीकों को ओवरराइड न करें. इसके बजाय, Compose के LifecycleEffects या लाइफ़साइकल के बारे में जानकारी रखने वाले कोरूटीन स्कोप का इस्तेमाल करें:

  • जब आपकी ऐक्टिविटी शुरू और बंद होती है, तब सिंक्रोनस काम करने के लिए, LifecycleStartEffect का इस्तेमाल करें.
  • जब आपकी ऐक्टिविटी फिर से शुरू होती है और रुकती है, तब सिंक्रोनस काम करने के लिए, LifecycleResumeEffect का इस्तेमाल करें.
  • लाइफ़साइकल इवेंट के जवाब में एसिंक्रोनस काम करने के लिए, repeatOnLifecycle का इस्तेमाल करें.
  • collectAsStateWithLifecycle का इस्तेमाल करके, फ़्लो से एसिंक्रोनस डेटा इकट्ठा करें.

यहां दिए गए स्निपेट में, लाइफ़साइकल की किसी खास स्थिति के हिसाब से कार्रवाइयां करने का तरीका बताया गया है:

  @Composable
  fun LocationChangedEffect(
    locationManager: LocationManager,
    onLocationChanged: (Location) -> Unit
  ) {
    val currentOnLocationChanged by rememberUpdatedState(onLocationChanged)

    LifecycleStartEffect(locationManager) {
        val listener = LocationListener { newLocation ->
            currentOnLocationChanged(newLocation)
        }

        try {
            locationManager.requestLocationUpdates(
                LocationManager.GPS_PROVIDER,
                1000L,
                1f,
                listener,
            )
        } catch (e: SecurityException) {
            // TODO: Handle missing permissions
        }

        onStopOrDispose {
            locationManager.removeUpdates(listener)
        }
    }
  }

डिपेंडेंसी हैंडल करता है

कॉम्पोनेंट के बीच डिपेंडेंसी मैनेज करते समय, सबसे सही तरीके अपनाएं:

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

जांच करना

जांच करने के लिए, यहां कुछ सबसे सही तरीके दिए गए हैं:

सुझाव ब्यौरा
जानें कि क्या टेस्ट करना है.

अगर प्रोजेक्ट, "hello world" ऐप्लिकेशन जितना आसान नहीं है, तो उसकी जांच करें. कम से कम, इनमें शामिल करें:

  • ViewModels के लिए यूनिट टेस्ट, जिनमें फ़्लो शामिल हैं
  • डेटा लेयर की एंटिटी के लिए यूनिट टेस्ट. जैसे, रिपॉज़िटरी और डेटा सोर्स
  • यूज़र इंटरफ़ेस (यूआई) नेविगेशन टेस्ट. ये सीआई में रिग्रेशन टेस्ट के तौर पर काम के होते हैं
मॉक के बजाय फ़ेक का इस्तेमाल करें. फ़ेक का इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, Android में टेस्ट डबल का इस्तेमाल करना देखें.
StateFlows की जांच करें. StateFlow की जांच करते समय, यह काम करें:

ज़्यादा जानकारी के लिए, Android में क्या टेस्ट करना है और अपने Compose लेआउट की जांच करना देखें.

मॉडल

अपने ऐप्लिकेशन में मॉडल डेवलप करते समय, इन सबसे सही तरीकों का पालन करें:

सुझाव ब्यौरा
जटिल ऐप्लिकेशन में, हर लेयर के लिए एक मॉडल बनाएं.

जटिल ऐप्लिकेशन में, अलग-अलग लेयर या कॉम्पोनेंट में नए मॉडल बनाएं, जब ऐसा करना सही हो. यहां दिए गए उदाहरण देखें:

  • रिमोट डेटा सोर्स, नेटवर्क के ज़रिए मिलने वाले मॉडल को, सिर्फ़ ऐप्लिकेशन के लिए ज़रूरी डेटा वाली आसान क्लास पर मैप कर सकता है.
  • रिपॉज़िटरी, डीएओ मॉडल को सिर्फ़ यूज़र इंटरफ़ेस (यूआई) लेयर के लिए ज़रूरी जानकारी वाली आसान डेटा क्लास पर मैप कर सकती हैं.
  • ViewModel, UiState क्लास में डेटा लेयर मॉडल शामिल कर सकता है.

नेमिंग कनवेंशन

अपने कोडबेस का नाम रखते समय, आपको इन सबसे सही तरीकों के बारे में पता होना चाहिए:

सुझाव ब्यौरा
मेथड के नाम रखना.
ज़रूरी नहीं
मेथड के नाम रखने के लिए, वर्ब फ़्रेज़ का इस्तेमाल करें. जैसे, makePayment().
प्रॉपर्टी के नाम रखना.
ज़रूरी नहीं
प्रॉपर्टी के नाम रखने के लिए, नाउन फ़्रेज़ का इस्तेमाल करें. जैसे, inProgressTopicSelection.
डेटा की स्ट्रीम के नाम रखना.
ज़रूरी नहीं
जब कोई क्लास, फ़्लो स्ट्रीम या कोई अन्य स्ट्रीम उपलब्ध कराती है, तो नेमिंग कनवेंशन get{model}Stream होता है. जैसे, getAuthorStream(): Flow<Author>. अगर फ़ंक्शन, मॉडल की सूची दिखाता है, तो प्लरल मॉडल का नाम इस्तेमाल करें: getAuthorsStream(): Flow<List<Author>>.
इंटरफ़ेस के लागू करने के नाम रखना.
ज़रूरी नहीं
इंटरफ़ेस के लागू करने के लिए, काम के नाम इस्तेमाल करें. अगर कोई बेहतर नाम नहीं मिल पाता है, तो प्रीफ़िक्स के तौर पर Default का इस्तेमाल करें. उदाहरण के लिए, NewsRepository इंटरफ़ेस के लिए, आपके पास OfflineFirstNewsRepository या InMemoryNewsRepository हो सकता है. अगर आपको कोई अच्छा नाम नहीं मिलता है, तो DefaultNewsRepository का इस्तेमाल करें. फ़ेक लागू करने के लिए, Fake प्रीफ़िक्स का इस्तेमाल करें. जैसे, FakeAuthorsRepository.

अन्य संसाधन

Android आर्किटेक्चर के बारे में ज़्यादा जानने के लिए, यहां दिए गए अन्य संसाधन देखें:

दस्तावेज़

Views कॉन्टेंट