Android में संदर्भ से गतिविधि हो रही है


182

इसने मुझे स्टम्प किया है।

मुझे कस्टम लेआउट क्लास के भीतर से एक गतिविधि विधि को कॉल करने की आवश्यकता है। इसके साथ समस्या यह है कि मैं नहीं जानता कि लेआउट के भीतर से गतिविधि का उपयोग कैसे किया जाए।

प्रोफ़ाइल दृश्य

public class ProfileView extends LinearLayout
{
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }

    //Heres where things get complicated
    public void onClick(View v)
    {
        //Need to get the parent activity and call its method.
        ProfileActivity x = (ProfileActivity) context;
        x.activityMethod();
    }
}

ProfileActivity

public class ProfileActivityActivity extends Activity
{
    //In here I am creating multiple ProfileViews and adding them to the activity dynamically.

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.profile_activity_main);
    }

    public void addProfilesToThisView()
    {
        ProfileData tempPd = new tempPd(.....)
        Context actvitiyContext = this.getApplicationContext();
        //Profile view needs context, null, name and a profileData
        ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
        profileLayout.addView(pv);
    }
}

जैसा कि आप ऊपर देख सकते हैं, मैं प्रोफाइल व्यू को प्रोग्रामेटिक रूप से इंस्टेंट कर रहा हूं और इसके साथ एक्टिविटी कॉन्टेक्स्ट में पास कर रहा हूं। 2 प्रश्न:

  1. क्या मैं प्रोफाइलव्यू में सही संदर्भ दे रहा हूं?
  2. मैं संदर्भ से युक्त गतिविधि कैसे प्राप्त करूं?

जवाबों:


471

अपने से Activity, बस अपने लेआउट के thisरूप में पास Contextकरें:

ProfileView pv = new ProfileView(this, null, temp, tempPd);

बाद में आपके पास Contextलेआउट में एक होगा , लेकिन आपको पता होगा कि यह वास्तव में आपका है Activityऔर आप इसे डाल सकते हैं ताकि आपके पास वह हो जो आपको चाहिए:

Activity activity = (Activity) context;

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

6
बोरिस, सवाल पूछते हैं कि क्या एक संदर्भ से एक गतिविधि प्राप्त करने का एक तरीका है। यह नहीं हो सकता। बेशक आप कास्ट कर सकते हैं, लेकिन यह एक अंतिम उपाय है। यदि आप एक गतिविधि के रूप में संदर्भ का इलाज करना चाहते हैं, तो एक गतिविधि के लिए डाउनकास्ट न करें। यह सरल कोड के लिए बनाता है, और बाद में बग का खतरा कम होता है जब कोई अन्य व्यक्ति आपके कोड को बनाए रखता है।
आकाश केल्सी

6
ध्यान दें कि 'get' के बजाय 'getApplicationContext ()' काम नहीं करेगा।
dwbrito

1
@BorisStrandjev मुझे आपकी टिप्पणी समझ में नहीं आई है। वैसे भी, मैंने कहा कि आपके उदाहरण की कोशिश करने के बाद, लेकिन 'इस' के बजाय मैंने getApplicationContext () का उपयोग किया और एप्लिकेशन ने एप्लिकेशन को स्वयं कास्ट करने का प्रयास किया, इसलिए गतिविधि के बजाय एक कास्ट त्रुटि दी। 'यह' पर स्विच करने के बाद, जैसा कि आपने उत्तर दिया, इसने काम किया।
dwbrito

1
आपके लिंक पर उच्चतम उत्तोलित उत्तर दोनों प्रश्न को चुनौती देने का सुझाव देते हैं यदि यह बदबूदार है। यह सवाल निश्चित रूप से बदबूदार है। ओपी ने पहले कहा: "मुझे एक कस्टम लेआउट क्लास के भीतर से एक गतिविधि विधि को कॉल करने की आवश्यकता है।" जो इंटरफेस के उचित उपयोग के साथ पूरी तरह से प्राप्त करने योग्य है। फिर वह कहता है "इसके साथ समस्या यह है कि मुझे नहीं पता कि लेआउट के भीतर से गतिविधि का उपयोग कैसे किया जाए।" जो गलतफहमी की ओर एक महत्वपूर्ण संकेत है। लोग प्रोग्रामिंग में हर समय गलत काम करने की कोशिश करते हैं और हमें इससे आँख नहीं फेरनी चाहिए।
सैम

39

यह वह चीज है जिसका मैंने सफलतापूर्वक उपयोग किया Contextहै Activityजब यह UI के भीतर खंडों या कस्टम दृश्य में काम कर रहा है। यदि यह विफल रहता है तो यह ContextWrapper को पुन: खोल देगा या अशक्त कर देगा।

public Activity getActivity(Context context)
{
    if (context == null)
    {
        return null;
    }
    else if (context instanceof ContextWrapper)
    {
        if (context instanceof Activity)
        {
            return (Activity) context;
        }
        else
        {
            return getActivity(((ContextWrapper) context).getBaseContext());
        }
    }

    return null;
}

यह सही जवाब है। अन्य लोग ContentWrapper पदानुक्रम को ध्यान में नहीं रखते हैं।
स्निकोलस

यह सही उत्तर है :)
गीत

1
@lygstate: आप अपने ऐप में किस लक्ष्य एपीआई स्तर का उपयोग कर रहे हैं? त्रुटि क्या है? यह केवल UI (गतिविधियों, टुकड़े, आदि) के भीतर काम करता है, सेवाओं में नहीं।
थियो

31
  1. नहीं
  2. आप नहीं कर सकते

एंड्रॉइड में दो अलग-अलग संदर्भ हैं। आपके आवेदन के लिए एक (आइए इसे BIG एक कहें) और प्रत्येक दृश्य के लिए (चलो इसे गतिविधि संदर्भ कहते हैं)।

एक रेखीय लेआउट एक दृश्य है, इसलिए आपको गतिविधि संदर्भ को कॉल करना होगा। इसे एक गतिविधि से कॉल करने के लिए, बस "यह" कहें। इतना आसान नहीं है?

जब आप उपयोग करते हैं

this.getApplicationContext();

आप BIG संदर्भ कहते हैं, वह जो आपके आवेदन का वर्णन करता है और आपके विचार का प्रबंधन नहीं कर सकता है।

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

सादर।


बस मेरा जवाब अपडेट करने के लिए। अपने को प्राप्त करने का सबसे आसान तरीका यह है कि आप अपने उदाहरण Activity contextको परिभाषित staticकरेंActivity । उदाहरण के लिए

public class DummyActivity extends Activity
{
    public static DummyActivity instance = null;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // Do some operations here
    }

    @Override
    public void onResume()
    {
        super.onResume();
        instance = this;
    }

    @Override
    public void onPause()
    {
        super.onPause();
        instance = null;
    }
}

और फिर, आपके Task, Dialogमें View, आप अपने कोड को पाने के लिए उस तरह के कोड का उपयोग कर सकते हैं Activity context:

if (DummyActivity.instance != null)
{
    // Do your operations with DummyActivity.instance
}

4
+1 विभिन्न प्रकार के संदर्भों के बीच भ्रम के एक बहुत ही सामान्य क्षेत्र को समझाने के लिए (जैसे 2 अलग-अलग Rs हैं)। Google लोगों को अपनी शब्दावली समृद्ध करने की आवश्यकता है।
A00b

3
BTW, @BorisStrandjev सही है: 2. हाँ आप कर सकते हैं । (वर्किंग कोड के साथ बहस नहीं कर सकते)
a00b

2
2. वास्तव में नहीं। यदि संदर्भ अनुप्रयोग संदर्भ होता, तो आपका ऐप क्रैश हो जाता।
स्टैकऑवरफ्लो

स्थिर उदाहरण ?! @ नीपर के पास इस imo का सबसे अच्छा समाधान है
सैम

14
एक गतिविधि के लिए एक स्थिर संदर्भ बनाना मेमोरी लीक बनाने का सबसे अच्छा तरीका है।
ब्लेडकॉडर

8

यदि आप कस्टम लेआउट क्लास (नॉन-एक्टिविटी क्लास) के भीतर से एक गतिविधि पद्धति को कॉल करना पसंद करते हैं। आपको इंटरफ़ेस का उपयोग करके एक प्रतिनिधि बनाना चाहिए।

यह अप्रयुक्त है और मैंने इसे सही कोडित किया है। लेकिन मैं जो चाहता हूं उसे हासिल करने का एक तरीका बता रहा हूं।

सबसे पहले बनाने और इंटरफ़ेस

interface TaskCompleteListener<T> {
   public void onProfileClicked(T result);
}



public class ProfileView extends LinearLayout
{
    private TaskCompleteListener<String> callback;
    TextView profileTitleTextView;
    ImageView profileScreenImageButton;
    boolean isEmpty;
    ProfileData data;
    String name;

    public ProfileView(Context context, AttributeSet attrs, String name, final ProfileData profileData)
    {
        super(context, attrs);
        ......
        ......
    }
    public setCallBack( TaskCompleteListener<String> cb) 
    {
      this.callback = cb;
    }
    //Heres where things get complicated
    public void onClick(View v)
    {
        callback.onProfileClicked("Pass your result or any type");
    }
}

और इसे किसी भी गतिविधि पर लागू करें।

और इसे कॉल करें

ProfileView pv = new ProfileView(actvitiyContext, null, temp, tempPd);
pv.setCallBack(new TaskCompleteListener
               {
                   public void onProfileClicked(String resultStringFromProfileView){}
               });

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

6

प्रसंग एक अनुप्रयोग, एक सेवा, एक गतिविधि और बहुत कुछ हो सकता है।

आम तौर पर किसी गतिविधि में दृश्य का संदर्भ स्वयं गतिविधि है, इसलिए आप सोच सकते हैं कि आप इस संदर्भ को गतिविधि में डाल सकते हैं, लेकिन वास्तव में आप हमेशा ऐसा नहीं कर सकते, क्योंकि इस मामले में संदर्भ भी एक संदर्भविषय हो सकता है।

ContextThemeWrapper AppCompat और Android के हाल के संस्करणों में बहुत अधिक उपयोग किया जाता है (एंड्रॉइड के लिए धन्यवाद: लेआउट में थीम विशेषता) इसलिए मैं व्यक्तिगत रूप से इस कलाकारों का प्रदर्शन कभी नहीं करूंगा।

इतना छोटा जवाब है: आप मज़बूती से एक दृश्य में एक संदर्भ से एक गतिविधि को पुनः प्राप्त नहीं कर सकते। गतिविधि को उस पर एक विधि कहकर पास करें जो गतिविधि को पैरामीटर के रूप में लेता है।


3

कभी भी getApplicationContext () का उपयोग न करें विचार के साथ ।

यह हमेशा गतिविधि का संदर्भ होना चाहिए, क्योंकि दृश्य गतिविधि से जुड़ा हुआ है। इसके अलावा, आपके पास एक कस्टम थीम सेट हो सकता है, और एप्लिकेशन के संदर्भ का उपयोग करते समय, सभी थीम खो जाएंगे। संदर्भों के विभिन्न संस्करणों के बारे में यहाँ पढ़ें ।


3

और कोटलिन में:

tailrec fun Context.activity(): Activity? = when {
  this is Activity -> this
  else -> (this as? ContextWrapper)?.baseContext?.activity()
}

0

एक गतिविधि प्रसंग का एक विशेषज्ञता है, इसलिए यदि आपके पास एक प्रसंग है जिसे आप पहले से जानते हैं कि आप किस गतिविधि का उपयोग करने का इरादा रखते हैं और बस एक में डाल सकते हैं ; जहां एक गतिविधि है और सी एक संदर्भ है।

Activity a = (Activity) c;

7
यह खतरनाक है, क्योंकि एक अलग टिप्पणी में उल्लेख किया गया है, संदर्भ हमेशा एक गतिविधि नहीं हो सकता है।

4
टाइपकास्ट केवल तभी (संदर्भ इंस्टॉफ़ गतिविधि) {// टाइपकास्ट}
अमित यादव

0

मैंने कन्वर्ट एक्टिविटी का इस्तेमाल किया

Activity activity = (Activity) context;

2
अलग-अलग तरह के संदर्भ हैं। गतिविधियों और अनुप्रयोगों के संदर्भ हो सकते हैं। यह केवल तभी काम करेगा जब संदर्भ एक गतिविधि का हो।
साइलोव

0

यह विधि सहायक होनी चाहिए ..!

public Activity getActivityByContext(Context context){

if(context == null){
    return null;
    }

else if((context instanceof ContextWrapper) && (context instanceof Activity)){
        return (Activity) context;
    }

else if(context instanceof ContextWrapper){
        return getActivity(((ContextWrapper) context).getBaseContext());
    }

return null;

    }

मुझे आशा है कि यह मदद करता है .. मेरी कोडिंग!


जाँचें कि आप जिस संदर्भ में पास हुए हैं, वह शून्य नहीं है .. यही समस्या है।
तस्लीम ओसेनी

0

कैसे कुछ लाइव डेटा कॉलबैक के बारे में,

class ProfileView{
    private val _profileViewClicked = MutableLiveData<ProfileView>()
    val profileViewClicked: LiveData<ProfileView> = _profileViewClicked
}

class ProfileActivity{

  override fun onCreateView(...){

    profileViewClicked.observe(viewLifecycleOwner, Observer { 
       activityMethod()
    })
  }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.