getActivity () फ्रैगमेंट फ़ंक्शन में अशक्त देता है


191

मेरे पास इस तरह एक सार्वजनिक विधि के साथ एक टुकड़ा (एफ 1) है

public void asd() {
    if (getActivity() == null) {
        Log.d("yes","it is null");
    }
}

और हां जब मैं इसे (गतिविधि से) कहता हूं, तो यह अशक्त है ...

FragmentTransaction transaction1 = getSupportFragmentManager().beginTransaction();
F1 f1 = new F1();
transaction1.replace(R.id.upperPart, f1);
transaction1.commit();
f1.asd();

यह कुछ ऐसा होना चाहिए जो मैं बहुत गलत कर रहा हूं, लेकिन मुझे नहीं पता कि वह क्या है


मुझे यकीन नहीं है कि जब आपको इस पोस्ट में पेस्ट किया गया था तो सिर्फ एक त्रुटि थी, लेकिन आपको बाद में कोष्ठक की आवश्यकता है getActivity()। इसके अलावा, आप कैसे खंडन कर रहे हैं? क्या आपके पास यह आपके लेआउट में है। xml?
केसीबी

दूसरा कोड टुकड़ा कहाँ से संबंधित है? Oncreate () - गतिविधि की विधि? और क्या आपने पहले ही setContentView () कहा है?
फ्रैंकिस्कस कार्सुन्के

R.id.upperPar लेआउट में एक तत्व है, इसलिए इसे टुकड़े के साथ प्रतिस्थापित किया जाना चाहिए, लेकिन यह मेरी समस्या नहीं है। मुझे समझ नहीं आ रहा है कि जब मैं कस्टम एट्रैमेंट मेथड्स में गेटअक्टिविटी () कहता हूं, तो मैं क्यों अशक्त हो जाता हूं, ऑनएक्टिविटी क्रिएटेड मेथड में बताएं कि एक्टिविटी असल में अशक्त नहीं है
लुकाप

समस्या यह है कि लेआउट में नहीं है, ऐप अच्छा काम करता है, लेकिन मुझे गेटऐक्टिविटी के लिए क्यों अशक्त हो जाता है ?, सभी तत्वों को उसमें शामिल किया गया है, जैसे कि यह यहां जारी नहीं होना चाहिए
Lukap

1
आपको इस विधि को कॉल करना चाहिए: f1.asd (); onActivityCreated विधि जो आपके खंड वर्ग में ओवरराइड की जानी है।
नम्रता बागवाल

जवाबों:


164

commit लेन-देन का समय निर्धारित करता है, अर्थात यह सीधा नहीं होता है, लेकिन अगली बार मुख्य धागा तैयार होने पर मुख्य धागे पर काम के रूप में निर्धारित किया जाता है।

मैं जोड़ने का सुझाव देता हूं

onAttach(Activity activity)

आपकी विधि Fragmentऔर उस पर एक विराम बिंदु डालने और देखने के लिए जब यह आपके कॉल के सापेक्ष कहा जाता है asd()। आप देखेंगे कि यह उस पद्धति के बाद कहा जाता है जहाँ आप कॉल करने के लिए asd()बाहर निकलते हैं। onAttachजहां कॉल है Fragmentअपनी गतिविधि के लिए और इस बिंदु से जुड़ा हुआ है getActivity()में गैर-शून्य वापस आ जाएगी (nb वहाँ भी एक है onDetach()कॉल)।


5
मुझे समझ नहीं आया कि आप अपनी समस्या को कैसे हल कर सकते हैं। यदि मेरी getActivity () स्टिल तैयार नहीं है, तो मैं FragmentActivity ऑब्जेक्ट का संदर्भ कैसे प्राप्त कर सकता हूं?
CeccoCQ

2
@ विवेक मुझे नहीं पता कि आप क्या हासिल करना चाहते हैं। यदि आपको सीधे संवाद प्रदर्शित करने के लिए फ़्रैगमेंट की आवश्यकता है, तो इसके निर्माण में क्या करना है, जैसे इसके onCreateViewया onActivityCreatedतरीकों में। मैं सवाल करता हूं कि asd () को क्यों बुलाया जाना चाहिए जब यह प्रश्न पोस्टिंग में होता है।
PJL

3
onAttach ने पदावनत किया
abbasalim

6
onAachach (एक्टिविटी mActivity) का ह्रास होता दिख रहा है .. इसके लिए कोई भी समाधान
ashish.n

4
एपीआई 24 ने पेश कियाcommitNow()
निकोलस

92

इससे छुटकारा पाने के लिए सबसे अच्छा यह है कि जब भी एटक को कॉल किया जाए, तो एक्टिविटी रेफरेंस रखें और इसके लिए एक्टिविटी रेफरेंस का इस्तेमाल करें

@Override
public void onAttach(Context context) {
    super.onAttach(activity);
    mContext = context;
}

@Override
public void onDetach() {
    super.onDetach();
    mContext = null;
}

34
क्या हमें mActivity = null onDetach () सेट करना चाहिए?
ओलिवर पीयरमैन

5
@OliverPearmain अगर आप इसे onDetach () में करेंगे तो कोई लाभ नहीं होगा। आपको इसे onDestory () में nullify करना होगा। इसके अलावा आपको इसे WeakRefernce में रखना होगा।
किरिल पोपोव

मैं इसे दोनों में अशक्त कर रहा हूं onDestroy()और onDetach()क्योंकि onDestroy()बुलाया जाने की गारंटी नहीं है।
मोहम्मद अली

8
Activityअगर हम इसे शून्य नहीं करते हैं तो क्या हम लीक कर रहे हैं onDestroy()?
मोहम्मद अली

3
Developer.android.com/intl/zh-tw/guide/compenders/… के अनुसार onCreateView () को कॉल करने से पहले onAttach () को कॉल किया जाता है। लेकिन मुझे अभी भी एक NullPointerException मिलती है, जबकि मैं onCreateView () में getActivity () कह रहा हूं। ऐसा कैसे हो सकता है?
किमी चिउ

81

यह तब हुआ जब आप getActivity()किसी अन्य थ्रेड में कॉल करते हैं जो टुकड़े को हटाने के बाद समाप्त हो गया है। जब HTTP अनुरोध समाप्त हो जाता है (तब) के getActivity()लिए विशिष्ट मामला कॉल होता है (पूर्व के लिए Toast)onResponse उदाहरण के लिए) तो उदाहरण के लिए)।

इससे बचने के लिए, आप एक फ़ील्ड नाम को परिभाषित कर सकते हैं mActivityऔर इसके बजाय इसका उपयोग कर सकते हैं getActivity()। इस क्षेत्र को प्रारंभ में () निम्नलिखित के रूप में टुकड़े की विधि पर आरंभ किया जा सकता है:

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (context instanceof Activity){
        mActivity =(Activity) context;
    }
}

अपनी परियोजनाओं में, मैं आमतौर पर इस सुविधा के साथ अपने सभी अंशों के लिए एक आधार वर्ग को परिभाषित करता हूं:

public abstract class BaseFragment extends Fragment {

    protected FragmentActivity mActivity;

    @Override
public void onAttach(Context context) {
    super.onAttach(context);

    if (context instanceof Activity){
        mActivity =(Activity) context;
    }
}
}

हैप्पी कोडिंग,


19
क्या हम mActivity = null सेट करेंगे; onDetach () में?
Bharat Dodeja

Thucnguyen, एकल गतिविधि ऐप के लिए mActivity को स्थिर कैसे घोषित करें?
IAMthevoid

मुझे Activityकिसी अन्य थ्रेड से पहुंचने का कोई कारण नहीं दिखता है । आप इसके साथ कुछ भी नहीं कर सकते, टोस्ट भी नहीं दिखा सकते। इसलिए आपको या तो पहले मुख्य धागे में काम स्थानांतरित करना चाहिए, या गतिविधि का उपयोग बिल्कुल नहीं करना चाहिए।
Dzmitry Lazerka

4
@BharatDodeja को हमें mActivity = null onDetach सेट करना चाहिए? क्या तुम्हें पता चला?
सलेंसर

5
यह गतिविधि को शून्य किए बिना लीक हो रहा है।
डेरेक डेनिज़ियाक

30

अन्य जवाब जो onAttach में गतिविधि का एक संदर्भ रखने का सुझाव देते हैं, वे वास्तविक समस्या के लिए केवल एक बैंडएड का सुझाव दे रहे हैं। जब गेटएक्टिविटी वापस आती है तो इसका मतलब है कि फ्रैगमेंट एक्टिविटी से जुड़ा नहीं है। ज्यादातर यह तब होता है जब गतिविधि रोटेशन के कारण दूर हो गई है या गतिविधि समाप्त हो रही है, लेकिन फ्रैगमेंट में अभी भी कुछ प्रकार के कॉलबैक विवरण पंजीकृत हैं। जब श्रोता को कॉल किया जाता है यदि आपको गतिविधि के साथ कुछ करने की आवश्यकता होती है लेकिन गतिविधि चली गई है तो बहुत कुछ ऐसा नहीं है जो आप कर सकते हैं। अपने कोड में आपको बस जाँच करनी चाहिएgetActivity() != nullऔर अगर यह नहीं है तो कुछ भी मत करो। यदि आप उस गतिविधि का संदर्भ रखते हैं जो आप गए हैं तो आप गतिविधि को कचरा एकत्र होने से रोक रहे हैं। कोई भी यूआई चीजें जो आप करने की कोशिश कर सकते हैं, उन्हें उपयोगकर्ता द्वारा नहीं देखा जाएगा। मैं कुछ स्थितियों की कल्पना कर सकता हूं जहां कॉलबैक श्रोता में आप गैर-यूआई से संबंधित कुछ के लिए एक संदर्भ रखना चाहते हैं, उन मामलों में यह संभवत: एप्लिकेशन संदर्भ प्राप्त करने के लिए अधिक समझ में आता है। ध्यान दें कि एकमात्र कारण यह है कि onAttachट्रिक एक बड़ी मेमोरी लीक नहीं है क्योंकि आम तौर पर कॉलबैक श्रोता के निष्पादित होने के बाद इसकी आवश्यकता नहीं होगी और यह फ्रैगमेंट के साथ कचरा एकत्र किया जा सकता है, इसके सभी दृश्य और गतिविधि का संदर्भ। अगर तुमsetRetainInstance(true) स्मृति रिसाव का एक बड़ा मौका है क्योंकि गतिविधि क्षेत्र को भी बनाए रखा जाएगा, लेकिन रोटेशन के बाद जो पिछली गतिविधि हो सकती है वह वर्तमान नहीं है।


1
यह वास्तव में मेरी समस्या है। मेरे पास एक टुकड़ा है जो एक प्रक्रिया करता है -> फिर एक विज्ञापन दिखाया जाता है -> और फिर गद्य जारी रहता है। कुछ उपकरणों में विज्ञापन से लौटने के बाद (एक श्रोता के माध्यम से विज्ञापन घटनाओं में) getActivity () शून्य है। लेकिन मुझे काम खत्म करने के लिए काम का दूसरा हिस्सा जारी रखने की जरूरत है। क्या आपका मतलब है कि इसका कोई हल नहीं है?
Notbad

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

यह इस विषय के 100s SO प्रश्नों का सही सामान्य उत्तर प्रतीत होता है।
मैनुअल

सबसे बढ़िया उत्तर। एसओ पर एंड्रॉइड के लिए बहुत सारे बैंडेड समाधान हैं।
मैक्सब्यूडॉइन

इसलिए यदि मैं कुछ ऑपरेशन करना चाहता हूं, तो गेटअक्टिविटी () उपलब्ध होने के बाद मैं कैसे निष्पादित कर सकता हूं (यदि यह बिल्कुल है)।
श्रीकांत करुमनघाट

17

Android API स्तर 23 के बाद से, onAttach (गतिविधि गतिविधि) को हटा दिया गया है। आपको onAttach (संदर्भ संदर्भ) का उपयोग करने की आवश्यकता है। http://developer.android.com/reference/android/app/Fragment.html#onAttach(android.app.Activity)

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

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    Activity a;

    if (context instanceof Activity){
        a=(Activity) context;
    }

}


10

PJL सही है। मैंने उनके सुझाव का उपयोग किया है और यही मैंने किया है:

  1. खंड के लिए परिभाषित वैश्विक चर:

    private final Object attachingActivityLock = new Object();

    private boolean syncVariable = false;

  2. कार्यान्वित

@Override
public void onAttach(Activity activity) {
  super.onAttach(activity);
  synchronized (attachingActivityLock) {
      syncVariable = true;
      attachingActivityLock.notifyAll();
  }
}

३। मैंने अपने फ़ंक्शन को लपेट लिया, जहां मुझे थ्रेड में गेटएक्टिविटी () को कॉल करने की आवश्यकता है, क्योंकि अगर यह मुख्य धागे पर चलेगा, तो मैं थ्रेड को चरण 4 के साथ ब्लॉक कर दूंगा और onAttach () को कभी नहीं बुलाया जाएगा।

    Thread processImage = new Thread(new Runnable() {

        @Override
        public void run() {
            processImage();
        }
    });
    processImage.start();

४। मेरे फ़ंक्शन में जहां मुझे getActivity () कॉल करने की आवश्यकता है, मैं इसका उपयोग करता हूं (कॉल getActivity से पहले) ()

    synchronized (attachingActivityLock) {
        while(!syncVariable){
            try {
                attachingActivityLock.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

यदि आपके पास कुछ UI अपडेट हैं, तो उन्हें UI थ्रेड पर चलाना याद रखें। मुझे ImgeView को अपडेट करने की आवश्यकता है इसलिए मैंने किया:

image.post(new Runnable() {

    @Override
    public void run() {
        image.setImageBitmap(imageToShow);
    }
});

7

आदेश जिसमें कॉलबैक को कमिट के बाद कहा जाता है ():

  1. जो भी विधि आप मैन्युअल रूप से सही होने के बाद कहते हैं ()
  2. onAttach ()
  3. onCreateView ()
  4. onActivityCreated ()

मुझे कुछ काम करने की ज़रूरत थी, जिसमें कुछ दृश्य शामिल थे, इसलिए onAttach () ने मेरे लिए काम नहीं किया; यह दुर्घटनाग्रस्त हो गया। इसलिए मैंने अपने कोड का एक हिस्सा ले लिया, जो कि कमिटमेंट के बाद राइट () (1.) नामक एक विधि के अंदर कुछ पैरामेट्स सेट कर रहा था, फिर कोड का दूसरा हिस्सा जो ऑनक्रिएट व्यू () (3.) के अंदर व्यू को हैंडल करता था।


3

मैं OkHttp का उपयोग कर रहा हूं और मैंने अभी इस मुद्दे का सामना किया है।


पहले भाग के लिए @thucnguyen सही रास्ते पर था

यह तब होता है जब आप getActivity () को किसी अन्य थ्रेड में कॉल करते हैं जो टुकड़े को हटा दिए जाने के बाद समाप्त हो जाता है। जब HTTP अनुरोध समाप्त हो जाता है (उदाहरण के लिए onResponse में) तो विशिष्ट मामला getActivity () (एक टोस्ट के लिए) कह रहा है।

गतिविधि बंद होने के बाद भी कुछ HTTP कॉल निष्पादित की जा रही थीं (क्योंकि HTTP अनुरोध पूरा होने में कुछ समय लग सकता है)। मैंने तब, HttpCallbackकुछ फ्रैगमेंट फ़ील्ड को अपडेट करने की कोशिश की और nullजब कोशिश कर रहा था तो अपवाद मिला getActivity()

http.newCall(request).enqueue(new Callback(...
  onResponse(Call call, Response response) {
    ...
    getActivity().runOnUiThread(...) // <-- getActivity() was null when it had been destroyed already

IMO समाधान कॉलबैक को रोकने के लिए होता है जब टुकड़ा अब और जीवित नहीं होता है (और यह सिर्फ Okhttp के साथ नहीं है)।

तय: रोकथाम।

यदि आपके पास खंड जीवन चक्र (अधिक जानकारी यहाँ ) पर एक नज़र है , तो आप देखेंगे कि वहाँ onAttach(Context context)और onDetach()विधियाँ हैं। ये फ्रैगमेंट एक गतिविधि के अंतर्गत आने के बाद कहलाते हैं और क्रमशः होने से पहले बंद हो जाते हैं।

इसका मतलब है कि हम उस कॉलबैक को onDetachविधि में नियंत्रित करके होने से रोक सकते हैं ।

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    // Initialize HTTP we're going to use later.
    http = new OkHttpClient.Builder().build();
}

@Override
public void onDetach() {
    super.onDetach();

    // We don't want to receive any more information about the current HTTP calls after this point.
    // With Okhttp we can simply cancel the on-going ones (credits to https://github.com/square/okhttp/issues/2205#issuecomment-169363942).
    for (Call call : http.dispatcher().queuedCalls()) {
        call.cancel();
    }
    for (Call call : http.dispatcher().runningCalls()) {
        call.cancel();
    }
}

2

आप इस फ़ंक्शन को कहां कहते हैं? यदि आप इसे कंस्ट्रक्टर में कहते हैं Fragment, तो यह वापस आ जाएगा null

getActivity()जब विधि onCreateView()निष्पादित की जाती है तो बस कॉल करें ।


1

इस प्रकार करें। मुझे लगता है कि यह आपके लिए मददगार होगा।

private boolean isVisibleToUser = false;
private boolean isExecutedOnce = false;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = inflater.inflate(R.layout.fragment_my, container, false);
    if (isVisibleToUser && !isExecutedOnce) {
        executeWithActivity(getActivity());
    }
    return root;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    this.isVisibleToUser = isVisibleToUser;
    if (isVisibleToUser && getActivity()!=null) {
        isExecutedOnce =true;
        executeWithActivity(getActivity());
    }
}


private void executeWithActivity(Activity activity){
    //Do what you have to do when page is loaded with activity

}

1

जिन लोगों को अभी भी onAttach (गतिविधि गतिविधि) की समस्या है, इसका सिर्फ प्रसंग बदल गया है -

    @Override
public void onAttach(Context context) {
    super.onAttach(context);
    this.context = context;
}

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

 @Override
public void onAttach(Context context) {
    super.onAttach(context);
    mActivity a; //Your activity class - will probably be a global var.
    if (context instanceof mActivity){
        a=(mActivity) context;
    }
}

जैसा कि user1868713 ने सुझाया है।


0

आप onAttach का उपयोग कर सकते हैं या यदि आप हर जगह onAachach नहीं लगाना चाहते हैं तो आप एक तरीका रख सकते हैं जो ApplicationContext को मुख्य ऐप क्लास पर लौटा दे:

public class App {
    ...  
    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context = this;
    }

    public static Context getContext() {
        return context;
    }
    ...
}

उसके बाद आप इसे अपने प्रोजेक्ट में इस तरह से हर जगह फिर से इस्तेमाल कर सकते हैं:

App.getContext().getString(id)

कृपया मुझे बताएं कि क्या यह आपके लिए काम नहीं करता है।


0

एक और अच्छा समाधान एमवीवीएम आर्किटेक्चर के साथ एंड्रॉइड के लाइवडेटा का उपयोग करना होगा। आप अपने ViewModel के अंदर एक LiveData ऑब्जेक्ट को परिभाषित करेंगे और इसे अपने टुकड़े में देखेंगे, और जब LiveData मान को बदल दिया जाता है, तो यह आपके पर्यवेक्षक (इस मामले में टुकड़ा) को केवल तभी सूचित करेगा जब आपका टुकड़ा सक्रिय स्थिति में होगा, इसलिए यह गारंटी होगी कि आप आपका UI कार्य करता है और गतिविधि को तभी एक्सेस कर सकता है जब आपका टुकड़ा सक्रिय अवस्था में हो। यह एक लाभ है जो LiveData के साथ आता है

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


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