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

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

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

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

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

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

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

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

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

कोरूटीन इस्तेमाल करने के कुछ और सबसे सही तरीके यहां दिए गए हैं.

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

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

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

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

ViewModel के इस्तेमाल के सबसे सही तरीके यहां देखें.

ViewModels के फ़ायदे यहां देखें.

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

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

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

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

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

व्यू

class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

Compose

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

ViewModel

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

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

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

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

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

  • स्क्रीन-लेवल पर कंपोज़ेबल,
  • व्यू में गतिविधियां/फ़्रैगमेंट,
  • Jetpack नेविगेशन का इस्तेमाल करते समय, डेस्टिनेशन या ग्राफ़.
दोबारा इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट में, सामान्य स्टेटस होल्डर क्लास का इस्तेमाल करें. फिर से इस्तेमाल किए जा सकने वाले यूज़र इंटरफ़ेस (यूआई) कॉम्पोनेंट में जटिलता को मैनेज करने के लिए, सामान्य स्टेटस होल्डर क्लास का इस्तेमाल करें. ऐसा करने से, इस राज्य को बाहरी तौर पर इकट्ठा और कंट्रोल किया जा सकता है.
AndroidViewModel का इस्तेमाल न करें. AndroidViewModel के बजाय, ViewModel क्लास का इस्तेमाल करें. 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
            )

    // ...
}

लाइफ़साइकल

Android लाइफ़साइकल के साथ काम करने के कुछ सबसे सही तरीके यहां दिए गए हैं:

सुझाव ब्यौरा
ऐक्टिविटी या फ़्रैगमेंट में लाइफ़साइकल के तरीकों को बदलें नहीं. ऐक्टिविटी या फ़्रैगमेंट में, लाइफ़साइकल के onResume जैसे मेथड को बदलें. इसके बजाय, LifecycleObserver का इस्तेमाल करें. अगर ऐप्लिकेशन को लाइफ़साइकल के किसी खास Lifecycle.State पर कोई काम करना है, तो repeatOnLifecycle एपीआई का इस्तेमाल करें.

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

व्यू

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

Compose

@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

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

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

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

टेस्ट करना

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

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

अगर प्रोजेक्ट, 'हैलो वर्ल्ड' ऐप्लिकेशन जितना आसान नहीं है, तो आपको कम से कम इनके साथ इसकी जांच करनी चाहिए:

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

ज़्यादा जानकारी के लिए, Android DAC गाइड में क्या जांचना है लेख पढ़ें.

मॉडल

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

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

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

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

नाम रखने के तरीके

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

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