प्रसंग पाने के लिए विभिन्न तरीकों में क्या अंतर है?


390

एंड्रॉइड कोड के विभिन्न बिट्स में मैंने देखा है:

 public class MyActivity extends Activity {
    public void method() {
       mContext = this;    // since Activity extends Context
       mContext = getApplicationContext();
       mContext = getBaseContext();
    }
 }

हालाँकि मुझे कोई भी ऐसा अच्छा विवरण नहीं मिल रहा है, जो बेहतर हो और किन परिस्थितियों में इस्तेमाल किया जाए।

इस पर प्रलेखन के लिए संकेत, और अगर गलत को चुना जाता है तो क्या हो सकता है के बारे में मार्गदर्शन, बहुत सराहना की जाएगी।


2
यह लिंक आपकी मदद कर सकता है। के माध्यम से जाना इस ..
अजु

जवाबों:


305

मैं मानता हूं कि एंड्रॉइड में कॉन्टेक्स्ट की बात आने पर डॉक्यूमेंटेशन बहुत कम है, लेकिन आप विभिन्न स्रोतों से कुछ तथ्यों को एक साथ जोड़ सकते हैं।

आधिकारिक Google Android डेवलपर्स ब्लॉग पर यह ब्लॉग पोस्ट ज्यादातर मेमोरी लीक की सहायता के लिए लिखा गया था, लेकिन संदर्भ के बारे में कुछ अच्छी जानकारी प्रदान करता है:

एक नियमित Android एप्लिकेशन में, आपके पास आमतौर पर दो प्रकार के संदर्भ, गतिविधि और अनुप्रयोग होते हैं।

लेख को थोड़ा और पढ़ना दोनों के बीच अंतर के बारे में बताता है और जब आप Activity.getApplicationContext()गतिविधि संदर्भ का उपयोग करने के बजाय आवेदन संदर्भ ( ) का उपयोग करने पर विचार करना चाह सकते हैं this। मूल रूप से एप्लिकेशन संदर्भ एप्लिकेशन के साथ जुड़ा हुआ है और हमेशा आपके ऐप के जीवन चक्र के दौरान समान रहेगा, जहां गतिविधि संदर्भ गतिविधि के साथ जुड़ा हुआ है और संभवतः कई बार नष्ट हो सकता है क्योंकि स्क्रीन अभिविन्यास परिवर्तन के दौरान गतिविधि नष्ट हो जाती है और इस तरह के।

एंड्रॉइड एसडीके पर काम करने वाले Google इंजीनियरों में से एक, डायने हैकॉर्न की पोस्ट के अलावा getBaseContext () का उपयोग करने के बारे में मुझे वास्तव में कुछ भी नहीं मिला:

GetBaseContext () का उपयोग न करें, बस आपके पास जो संदर्भ है उसका उपयोग करें।

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

तो कुल मिलाकर जब संभव हो तो वैश्विक अनुप्रयोग संदर्भ का उपयोग करना बेहतर लगता है।


13
जब मेरे पास एक गतिविधि ए होती है, जो गतिविधि बी को शुरू कर सकती है, जो बदले में, CLEAR_TOP ध्वज के साथ A को पुनः आरंभ कर सकती है (और संभवतः इस चक्र को कई बार दोहराएं) - इस मामले में मुझे किस संदर्भ का उपयोग करना चाहिए ताकि एक विशाल निशान के निर्माण से बच सकें। संदर्भित संदर्भ? डायना getBaseContext के बजाय 'इस' का उपयोग करते हुए कहती हैं, लेकिन तब ... अधिकांश बार A का पुन: उपयोग किया जाएगा लेकिन ऐसी स्थितियां हैं जब A के लिए एक नई वस्तु बनाई जाएगी और फिर पुरानी A लीक होगी। तो ऐसा लगता है कि getBaseContext अधिकांश मामलों के लिए सबसे उचित विकल्प है। फिर यह स्पष्ट नहीं है कि क्यों Don't use getBaseContext()। क्या कोई इसे स्पष्ट कर सकता है?
JBM

2
एक वर्ग के अंदर संदर्भ ऑब्जेक्ट तक कैसे पहुंचेगा जो गतिविधि का विस्तार नहीं करता है?
कोल

1
@Cole, आप एक क्लास बना सकते हैं, जिसे हम यहां "ExampleClass" कहेंगे, जिसका कंस्ट्रक्टर एक कॉन्सेप्ट ऑब्जेक्ट लेता है और क्लास उदाहरण चर, "appContext" को इंस्टेंट करता है। उसके बाद, आपकी गतिविधि कक्षा (या उस मामले के लिए कोई अन्य वर्ग) एक उदाहरणक्लास विधि को कॉल कर सकती है जो उदाहरणक्लास के "appContext" उदाहरण चर का उपयोग करती है।
आर्ची १

54

यहाँ मैं क्या उपयोग के बारे में पाया गया है context:

1)। Activityखुद के भीतर , thisलेआउट और मेनू को बढ़ाने के लिए उपयोग करें , संदर्भ मेनू को पंजीकृत करें, विजेट्स को त्वरित करें, अन्य गतिविधियों को शुरू करें, Intentएक Activity, त्वरित वरीयताओं के भीतर , या एक में उपलब्ध अन्य तरीकों से नया बनाएं Activity

मुद्रास्फीति की रूपरेखा:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup);

सूजन मेनू:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    this.getMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
}

संदर्भ मेनू पंजीकृत करें:

this.registerForContextMenu(myView);

तत्काल विजेट:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView);

प्रारंभ करें Activity:

Intent mIntent = new Intent(this, MyActivity.class);
this.startActivity(mIntent);

त्वरित प्राथमिकताएँ:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences();

२)। एप्लिकेशन-वाइड क्लास के लिए, getApplicationContext()इस संदर्भ का उपयोग अनुप्रयोग के जीवन काल के लिए मौजूद है।

वर्तमान Android पैकेज का नाम पुनः प्राप्त करें:

public class MyApplication extends Application {    
    public static String getPackageName() {
        String packageName = null;
        try {
            PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0);
            packageName = mPackageInfo.packageName;
        } catch (NameNotFoundException e) {
            // Log error here.
        }
        return packageName;
    }
}

एक आवेदन-व्यापक वर्ग को बांधें:

Intent mIntent = new Intent(this, MyPersistent.class);
MyServiceConnection mServiceConnection = new MyServiceConnection();
if (mServiceConnection != null) {
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

३)। श्रोताओं और अन्य प्रकार की एंड्रॉइड कक्षाओं के लिए (जैसे कि ContentObserver), एक संदर्भ प्रतिस्थापन का उपयोग करें जैसे:

mContext = this;    // Example 1
mContext = context; // Example 2

जहां thisया contextएक वर्ग (गतिविधि, आदि) का संदर्भ है।

Activity संदर्भ प्रतिस्थापन:

public class MyActivity extends Activity {
    private Context mContext;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        mContext = this;
    }
}

श्रोता संदर्भ प्रतिस्थापन:

public class MyLocationListener implements LocationListener {
    private Context mContext;
    public MyLocationListener(Context context) {
        mContext = context;
    }
}

ContentObserver संदर्भ प्रतिस्थापन:

public class MyContentObserver extends ContentObserver {
    private Context mContext;
    public MyContentObserver(Handler handler, Context context) {
        super(handler);
        mContext = context;
    }
}

४)। के लिए BroadcastReceiver(इनलाइन / एम्बेडेड रिसीवर सहित), रिसीवर के स्वयं के संदर्भ का उपयोग करें।

बाहरी BroadcastReceiver:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            sendReceiverAction(context, true);
        }
        private static void sendReceiverAction(Context context, boolean state) {
            Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action));
            mIntent.putExtra("extra", state);
            context.sendBroadcast(mIntent, null);
        }
    }
}

इनलाइन / एंबेडेड BroadcastReceiver:

public class MyActivity extends Activity {
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false);
            if (connected) {
                // Do something.
            }
        }
    };
}

5)। सेवाओं के लिए, सेवा के स्वयं के संदर्भ का उपयोग करें।

public class MyService extends Service {
    private BroadcastReceiver mBroadcastReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    private void registerReceiver() {
        IntentFilter mIntentFilter = new IntentFilter();
        mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        this.mBroadcastReceiver = new MyBroadcastReceiver();
        this.registerReceiver(this.mBroadcastReceiver, mIntentFilter);
    } 
}

6)। टोस्ट के लिए, आम तौर पर उपयोग करते हैं getApplicationContext(), लेकिन जहां संभव हो, गतिविधि, सेवा आदि से पारित संदर्भ का उपयोग करें।

आवेदन के संदर्भ का उपयोग करें:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG);
mToast.show();

स्रोत से पारित संदर्भ का उपयोग करें:

public static void showLongToast(Context context, String message) {
    if (context != null && message != null) {
        Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG);
        mToast.show();
    }
}

और अंतिम, getBaseContext()Android के फ्रेमवर्क डेवलपर्स द्वारा सलाह के अनुसार उपयोग न करें ।

अद्यतन:Context उपयोग के उदाहरण जोड़ें ।


1
MContext के बजाय कोई भी उपयोग कर सकता है OuterClass.this; stackoverflow.com/questions/9605459/… पर
पॉल वेरेस्ट

3
इस तरह के एक उपयोगी उत्तर के लिए +1! मैं मानता हूँ कि स्वीकृत उत्तर स्वीकृत उत्तर के रूप में ठीक है, लेकिन पवित्र मौली यह उत्तर सुपर जानकारीपूर्ण था! उन सभी उदाहरणों के लिए धन्यवाद, उन्होंने समग्र रूप से संदर्भ उपयोग को बेहतर ढंग से समझने में मेरी मदद की। मैंने आपके जवाब को एक संदर्भ के रूप में अपनी मशीन पर एक टेक्स्ट फ़ाइल में कॉपी किया।
रयान

13

मैंने कुछ दिन पहले खुद से एक ही सवाल पूछते हुए इस धागे को पढ़ा। इसे पढ़ने के बाद मेरा निर्णय सरल था: हमेशा ApplicationContext का उपयोग करें।

हालाँकि, मुझे इससे एक समस्या का सामना करना पड़ा, मैंने इसे खोजने के लिए कुछ घंटे बिताए, और इसे हल करने में कुछ सेकंड ... (एक शब्द को बदलते हुए ...)

मैं एक SpinIn युक्त दृश्य को बढ़ाने के लिए एक LayoutInflater का उपयोग कर रहा हूं।

तो यहाँ दो संभावनाएँ हैं:

1)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext());

2)

    LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext());

फिर, मैं कुछ इस तरह कर रहा हूँ:

    // managing views part
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false);
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId);
    String[] myStringArray = new String[] {"sweet","love"};

    // managing adapter part
    // The context used here don't have any importance -- both work.
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapter);

    theParentView.addView(view);

मैंने क्या देखा: यदि आपने ApplicationContext के साथ अपने रैखिक सूची का तत्काल रूपांतरण किया है, तो जब आप अपनी गतिविधि में स्पिनर पर क्लिक करते हैं, तो आपके पास एक अनकहा अपवाद होगा, जो कि dalvik वर्चुअल मशीन से आता है (आपके कोड से नहीं, यही कारण है कि मैंने बहुत खर्च किया है समय का पता लगाने के लिए जहां मेरी गलती थी ...)।

यदि आप बेस कॉन्टेक्स्ट का उपयोग करते हैं, तो यह ठीक है, संदर्भ मेनू खुल जाएगा और आप अपनी पसंद के बीच चयन करने में सक्षम होंगे।

तो यहाँ मेरा निष्कर्ष है: मुझे लगता है (मैंने इसे आगे परीक्षण नहीं किया है) जब आपकी गतिविधि में संदर्भमेनु के साथ व्यवहार किया जाता है तो बेसकनेक्ट की तुलना में आवश्यक होता है ...

परीक्षण को एपीआई 8 के साथ कोडिंग किया गया है, और एचटीसी डिज़ायर, एंड्रॉइड 2.3.3 पर परीक्षण किया गया है।

मुझे आशा है कि मेरी टिप्पणी ने आपको अब तक ऊब नहीं किया है, और आपको शुभकामनाएं। खुश कोडिंग ;-)


किसी गतिविधि में विचार बनाते समय मैंने हमेशा "इस" का उपयोग किया है। इस आधार पर कि यदि गतिविधि फिर से शुरू हो जाती है, तो दृश्य रीमेक हो जाते हैं और हो सकता है कि एक नया संदर्भ हो जो फिर से विचार बनाने के लिए उपयोग किया जाए। डेवलपर ब्लॉग में पोस्ट की गई खामी एक इमेज व्यू के अनुसार है, इस संदर्भ में उपयोग किए जा सकने योग्य / बिटमैप को नष्ट कर दिया जाता है। फिर भी मैं फिलहाल यही कर रहा हूं। एप्लिकेशन (सामान्य कक्षाओं) में कहीं और कोड के बारे में मैं सिर्फ आवेदन संदर्भ का उपयोग करता हूं क्योंकि यह किसी भी गतिविधि या यूआई तत्वों के लिए विशिष्ट नहीं है।
जॉनवेलिस

6

सबसे पहले, मैं इस बात से सहमत हूं कि हमें जब भी संभव हो, एप्कोनेक्ट का उपयोग करना चाहिए। तब गतिविधि में "यह"। मुझे बेसकनेक्ट के लिए कभी जरूरत नहीं पड़ी।

मेरे परीक्षणों में, ज्यादातर मामलों में उन्हें आपस में जोड़ा जा सकता है। ज्यादातर मामलों में, जिस कारण से आप किसी संदर्भ को पकड़ना चाहते हैं, वह है फ़ाइलों, वरीयताओं, डेटाबेस आदि का उपयोग करना। ये डेटा अंततः आपके ऐप के निजी डेटा फ़ोल्डर (/ डेटा / डेटा /) में फ़ाइलों के रूप में परिलक्षित होते हैं। कोई फर्क नहीं पड़ता कि आप किस संदर्भ का उपयोग करते हैं, वे उसी फ़ोल्डर / फ़ाइलों में मैप किए जाएंगे ताकि आप ठीक हों।

यही मैंने देखा। शायद ऐसे मामले हैं जिन्हें आपको उन्हें अलग करना चाहिए।


मुझे विश्वव्यापी रूप से स्टार्टअप पर ऐप की भाषा सेट करने के लिए बेसकनेक्ट की आवश्यकता है (जब यह फोन डिफ़ॉल्ट लैंग से मेल नहीं खाता)।
टीना

3

कुछ मामलों में आप थ्रेड में कुछ चलाते समय एप्लिकेशन संदर्भ पर गतिविधि संदर्भ का उपयोग कर सकते हैं। जब थ्रेड निष्पादन पूर्ण हो जाता है और आपको कॉलर गतिविधि पर परिणाम वापस करने की आवश्यकता होती है, तो आपको एक हैंडलर के साथ उस संदर्भ की आवश्यकता होती है।

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...);

2

सरल शब्दों में

getApplicationContext()जैसा कि विधि नाम का सुझाव आपके ऐप को एप्लिकेशन के विस्तृत विवरण से अवगत कराएगा, जिसे आप ऐप में कहीं से भी एक्सेस कर सकते हैं। तो आप इसका उपयोग सेवा बंधन में कर सकते हैं, प्रसारण पंजीकरण आदि Application contextऐप से बाहर निकलने तक जीवित रहेंगे।

getActivity()या thisआपके ऐप को वर्तमान स्क्रीन के बारे में अवगत कराएगा जो कि दृश्यमान है जो ऐप द्वारा प्रदान किया गया है application context। तो जो कुछ भी आप वर्तमान स्क्रीन के बारे में जानना चाहते हैं जैसे Window ActionBar Fragementmangerऔर इस संदर्भ में उपलब्ध हैं। मूल रूप से और Activityविस्तार Context। यह संदर्भ तब तक जीवित रहेगा जब तक कि वर्तमान घटक (गतिविधि) जीवित है


1

भ्रम इस तथ्य से उपजा है कि कॉन्टेक्स्ट को एक्सेस करने के कई तरीके हैं, (सतह पर) कोई भी अंतर नहीं है। नीचे चार सबसे आम तरीके हैं जो आप एक गतिविधि में संदर्भ तक पहुंचने में सक्षम हो सकते हैं।

getContext()
getBaseContext()
getApplicationContext()
getActionBar().getThemedContext() //new

एक संदर्भ क्या है? मैं व्यक्तिगत रूप से किसी भी समय आपके आवेदन की स्थिति के संदर्भ में सोचना पसंद करता हूं। आवेदन प्रसंग आपके आवेदन के एक वैश्विक या आधार विन्यास का प्रतिनिधित्व करता है और एक गतिविधि या सेवा इस पर निर्माण कर सकती है और आपके आवेदन की एक विन्यास आवृत्ति या इसके लिए एक सकर्मक स्थिति का प्रतिनिधित्व करती है।

यदि आप android.content.Context के स्रोत को देखते हैं, तो आप देखते हैं कि संदर्भ एक अमूर्त वर्ग है और कक्षा पर टिप्पणियाँ इस प्रकार हैं:

एक अनुप्रयोग वातावरण के बारे में वैश्विक जानकारी के लिए इंटरफ़ेस। यह एक अमूर्त वर्ग है जिसका कार्यान्वयन एंड्रॉइड सिस्टम द्वारा प्रदान किया गया है। यह application-specificसंसाधनों और कक्षाओं तक पहुंच के साथ-साथ application-levelसंचालन के लिए अप-कॉल्स जैसे कि लॉन्चिंग गतिविधियों, प्रसारण और परिचय प्राप्त करना आदि की अनुमति देता है, जो मैं इससे दूर ले जाता हूं वह यह है कि कॉन्सेप्ट एप्लिकेशन स्तर के साथ-साथ सिस्टम स्तर तक पहुंचने के लिए एक सामान्य कार्यान्वयन प्रदान करता है। संसाधनों। अनुप्रयोग स्तर संसाधन स्ट्रिंग संसाधनों [getResources()]या परिसंपत्तियों जैसी चीजों तक पहुँच सकते हैं [getAssets()]और सिस्टम-स्तरीय संसाधन कुछ भी है जिसे आप एक्सेस करते हैंContext.getSystemService().

तथ्य की बात के रूप में, तरीकों पर टिप्पणियों पर एक नज़र डालें और वे इस धारणा को सुदृढ़ करने के लिए लग रहे हैं:

getSystemService(): system-levelनाम से एक सेवा के लिए संभाल लौटें । लौटी हुई वस्तु का वर्ग अनुरोधित नाम से भिन्न होता है। getResources(): अपने एप्लिकेशन के पैकेज के लिए संसाधन उदाहरण लौटाएं। getAssets(): अपने एप्लिकेशन के पैकेज के लिए संसाधन उदाहरण लौटाएं। यह इंगित करने योग्य हो सकता है कि प्रसंग सार वर्ग में, उपरोक्त सभी विधियाँ अमूर्त हैं! GetSystemService (क्लास) के केवल एक उदाहरण में एक कार्यान्वयन है और जो एक अमूर्त पद्धति को लागू करता है। इसका मतलब है, इनको लागू करने के लिए लागू करने वाले वर्गों द्वारा प्रदान किया जाना चाहिए, जिसमें शामिल हैं:

ContextWrapper
Application
Activity
Service
IntentService

एपीआई प्रलेखन को देखते हुए, कक्षाओं का पदानुक्रम इस तरह दिखता है:

प्रसंग

| - प्रसंगवार्ता

| - - आवेदन

| - - ContextThemeWrapper

| - - - - गतिविधि

| - - सर्विस

| - - - IntentService

चूँकि हम जानते हैं कि Contextस्वयं कोई अंतर्दृष्टि प्रदान नहीं कर रहा है, हम पेड़ को नीचे ले जाते हैं और देखते हैं ContextWrapperऔर महसूस करते हैं कि वहाँ बहुत कुछ नहीं है। चूंकि अनुप्रयोग का विस्तार होता है ContextWrapper, इसलिए वहां पर देखने के लिए बहुत कुछ नहीं है क्योंकि यह कार्यान्वयन द्वारा प्रदान किए गए कार्य को ओवरराइड नहीं करता है ContextWrapper। इसका अर्थ है कि प्रसंग के लिए कार्यान्वयन ओएस द्वारा प्रदान किया गया है और से छिपा हुआ है API। आप ContextImpl वर्ग के लिए स्रोत को देखकर संदर्भ के लिए ठोस कार्यान्वयन पर एक नज़र डाल सकते हैं।


0

मैंने केवल इसका उपयोग किया है और getBaseContextजब onClick(जावा और एंड्रॉइड दोनों के लिए बहुत हरा नॉब) से टोस्टिंग किया गया है । मैं इसका उपयोग तब करता हूं जब मेरा क्लिकर सीधे गतिविधि में होता है और getBaseContextएक अनाम आंतरिक क्लिकर में उपयोग करना होता है। मुझे लगता है कि बहुत ज्यादा चाल है getBaseContext, यह शायद उस गतिविधि के संदर्भ को वापस कर रहा है जिसमें आंतरिक वर्ग छिपा रहा है।


1
यह गलत है, यह गतिविधि के आधार संदर्भ को स्वयं वापस कर रहा है। एक अनाम आंतरिक वर्ग की गतिविधि का उपयोग करने के लिए (जिसे आप संदर्भ के रूप में उपयोग करना चाहते हैं) कुछ इस तरह का उपयोग करें MyActivity.this। आधार संदर्भ का उपयोग करने के रूप में आप वर्णन करते हैं कि शायद समस्याएं नहीं होंगी, लेकिन यह गलत है।
nicmartens1980
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.