2012-11-27 18 views
73

में नहीं बुलाया गया है, मैं नए nested fragment एपीआई का उपयोग कर रहा हूं जिसमें एंड्रॉइड समर्थन पुस्तकालय में शामिल है।onActivityResult() को नए नेस्टेड खंड एपीआई

समस्या यह है कि मैं नेस्टेड टुकड़े के साथ सामना करना पड़ रहा हूँ कि, एक नेस्टेड टुकड़ा है (यानि, एक टुकड़ा है कि getChildFragmentManager() द्वारा दिया FragmentManager के माध्यम से एक और टुकड़ा करने के लिए जोड़ दिया गया है) कॉल startActivityForResult(), नेस्टेड टुकड़ा के onActivityResult() तरीका नहीं है अगर है बुलाया। हालांकि, दोनों माता-पिता खंड onActivityResult() और गतिविधि के onActivityResult() दोनों कॉल किए जाते हैं।

मुझे नहीं पता कि मुझे घोंसले के टुकड़ों के बारे में कुछ याद आ रहा है, लेकिन मुझे वर्णित व्यवहार की उम्मीद नहीं थी। नीचे वह कोड है जो इस समस्या को पुन: उत्पन्न करता है। मैं बहुत ज्यादा अगर किसी ने मुझे सही दिशा में बात कर सकते हैं की सराहना करते हैं और मुझे समझा मैं गलत क्या कर रहा हूँ:

package com.example.nestedfragmentactivityresult; 

import android.media.RingtoneManager; 
import android.os.Bundle; 
import android.content.Intent; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.Toast; 

public class MainActivity extends FragmentActivity 
{ 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     this.getSupportFragmentManager() 
      .beginTransaction() 
      .add(android.R.id.content, new ContainerFragment()) 
      .commit(); 
    } 

    public void onActivityResult(int requestCode, int resultCode, Intent data) 
    { 
     super.onActivityResult(requestCode, resultCode, data); 

     // This is called 
     Toast.makeText(getApplication(), 
      "Consumed by activity", 
      Toast.LENGTH_SHORT).show(); 
    } 

    public static class ContainerFragment extends Fragment 
    { 
     public final View onCreateView(LayoutInflater inflater, 
             ViewGroup container, 
             Bundle savedInstanceState) 
     { 
      View result = inflater.inflate(R.layout.test_nested_fragment_container, 
       container, 
       false); 

      return result; 
     } 

     public void onActivityCreated(Bundle savedInstanceState) 
     { 
      super.onActivityCreated(savedInstanceState); 
      getChildFragmentManager().beginTransaction() 
       .add(R.id.content, new NestedFragment()) 
       .commit(); 
     } 

     public void onActivityResult(int requestCode, 
            int resultCode, 
            Intent data) 
     { 
      super.onActivityResult(requestCode, resultCode, data); 

      // This is called 
      Toast.makeText(getActivity(), 
       "Consumed by parent fragment", 
       Toast.LENGTH_SHORT).show(); 
     } 
    } 

    public static class NestedFragment extends Fragment 
    { 
     public final View onCreateView(LayoutInflater inflater, 
             ViewGroup container, 
             Bundle savedInstanceState) 
     { 
      Button button = new Button(getActivity()); 
      button.setText("Click me!"); 
      button.setOnClickListener(new View.OnClickListener() 
      { 
       public void onClick(View v) 
       { 
        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER); 
        startActivityForResult(intent, 0); 
       } 
      }); 

      return button; 
     } 

     public void onActivityResult(int requestCode, 
            int resultCode, 
            Intent data) 
     { 
      super.onActivityResult(requestCode, resultCode, data); 

      // This is NOT called 
      Toast.makeText(getActivity(), 
       "Consumed by nested fragment", 
       Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 

test_nested_fragment_container.xml है:

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/content" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

</FrameLayout> 
+0

एक सप्ताह पहले एक ही बग मिला। नेस्टेड फ्रैगमेंट पर मैन्युअल रूप सेActivityResult() पर कॉल करना पड़ा। व्यक्तिगत रूप से, मुझे लगता है कि यह एक बग है। वास्तव में यह देखने के लिए जांच नहीं की गई है कि यह ढांचे से करने योग्य है, लेकिन मुझे लगता है कि यह हो सकता है। उन्हें केवल शीर्ष स्तर के टुकड़े के लिए सभी बच्चे के टुकड़ों की जांच करने की आवश्यकता है और उनमें से प्रत्येक पर सक्रियताResult() पर कॉल करें। अगर ढांचे के भीतर से ऐसा करने का कोई तरीका नहीं है, तो ठीक है, यही वह है। लेकिन अगर ऐसा है, तो मैं गंभीरता से यह एक बग मानता हूं। –

उत्तर

57

हाँ, नेस्टेड टुकड़ा में onActivityResult() इस तरह से नहीं बुलाया जाएगा।

onActivityResult की बुला अनुक्रम (एंड्रॉयड समर्थन पुस्तकालय में)

  1. Activity.dispatchActivityResult() है।
  2. FragmentActivity.onActivityResult()
  3. Fragment.onActivityResult()

तीसरे चरण में, खंड Activity के FragmentMananger में पाया जाता है। तो आपके उदाहरण में, यह onActivityResult() प्रेषण करने वाला कंटेनर खंड है, नेस्टेड टुकड़ा कभी भी ईवेंट प्राप्त नहीं कर सका।

मुझे लगता है कि आपको ContainerFragment.onActivityResult() में अपना खुद का प्रेषण लागू करना है, नेस्टेड टुकड़े को ढूंढें और परिणाम और डेटा को पास करने का आह्वान करें।

+2

ठीक है, तो सवाल यह है ... क्या यह एक इरादा व्यवहार है, या यह किसी प्रकार की बग है? मेरे लिए यह कम से कम काउंटर अंतर्ज्ञानी है कि नेस्टेड टुकड़े गतिविधि के परिणाम प्राप्त नहीं करता है। –

+0

ठीक है .. आप इसे एक बग के रूप में मान सकते हैं, क्योंकि न तो एंड्रॉइड समर्थन लाइब्रेरी और न ही संस्करण 4.2 का मूल कोड परिणाम को नेस्टेड खंड में भेज सकता है। अपने आप को हल करने का प्रयास करें, बहुत कठिन नहीं ... – faylon

+0

अच्छा, मुझे लगता है कि मैं यही करूँगा। मैंने इस से बचने की कोशिश की ताकि होस्टिंग गतिविधि और उसके टुकड़ों के बीच अधिक युग्मन न किया जा सके। –

8

यहां मैंने इसे हल किया है।

गतिविधि में:

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    List<Fragment> frags = getSupportFragmentManager().getFragments(); 
    if (frags != null) { 
     for (Fragment f : frags) { 
      if (f != null) 
       handleResult(f, requestCode, resultCode, data); 
     } 
    } 
} 

private void handleResult(Fragment frag, int requestCode, int resultCode, Intent data) { 
    if (frag instanceof IHandleActivityResult) { // custom interface with no signitures 
     frag.onActivityResult(requestCode, resultCode, data); 
    } 
    List<Fragment> frags = frag.getChildFragmentManager().getFragments(); 
    if (frags != null) { 
     for (Fragment f : frags) { 
      if (f != null) 
       handleResult(f, requestCode, resultCode, data); 
     } 
    } 
} 
+0

आपकी चाल के लिए धन्यवाद! लेकिन क्या आप अपने उत्तर को संपादित करके कोड में _IHandleActivityResult_ इंटरफ़ेस क्या समझा सकते हैं? +1 –

+1

IHandleActivityResult बस एक खाली इंटरफ़ेस है। टुकड़े जो हैंडल चाहते हैं रीसेट इसे पारित कर सकते हैं खाली इंटरफ़ेस को कार्यान्वित कर सकते हैं। यह अनियंत्रित है लेकिन मुझे यह उपयोगी लगता है कि सभी टुकड़े कॉलबैक नहीं मिल रहे थे। – whizzle

-2

मैं एक ही समस्या का सामना करना पड़ा! मैं, ParentFragment में स्थिर ChildFragment का उपयोग करके इसे हल इस तरह:

private static ChildFragment mChildFragment; 

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 

    mChildFragment.onActivityResult(int requestCode, int resultCode, Intent data); 

} 
+1

mChildFragment अनावश्यक रूप से स्थिर है। – foo64

+4

भयानक समाधान – swooby

136

मैं (समर्थन पुस्तकालय प्रयोग किया जाता है) निम्न कोड के साथ इस समस्या का समाधान:

कंटेनर टुकड़ा में इस तरह से onActivityResult ओवरराइड:

@Override 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 

     List<Fragment> fragments = getChildFragmentManager().getFragments(); 
     if (fragments != null) { 
      for (Fragment fragment : fragments) { 
       fragment.onActivityResult(requestCode, resultCode, data); 
      } 
     } 
    } 

अब घोंसला वाला टुकड़ा एक्टिविटी रिसेट विधि पर कॉल प्राप्त करेगा।

इसके अलावा, notedEric Brynsvold इसी तरह के प्रश्न में, नेस्टेड टुकड़े को इसके मूल खंड का उपयोग करके गतिविधि शुरू करनी चाहिए, न कि सरल शुरुआत एक्टिविटीफॉर रिसेट() कॉल।

getParentFragment().startActivityForResult(intent, requestCode); 
+0

getParentFragment() !! के लिए धन्यवाद +100000, लेकिन एक्टिविटी रिसर्च कार्यान्वयन त्रुटि दे रहा है !! http://paste.ubuntu.com/6565045/ लेकिन गतिविधि में श्री विजिले (उत्तर में से एक) जैसी चीज को लागू करने के लिए मेरे लिए काम किया! –

+2

एफवाईआई मैं पहले फ्रेगमेंट में व्यूपार्जर के साथ पेजरबैस्ट्रिप का उपयोग कर रहा हूं और व्यूपर –

+1

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

4

यह समस्या के बाद Android Support Library 23.2 में तय किया गया है: तो, नेस्टेड टुकड़ा में साथ गतिविधि शुरू करते हैं। हमें Android समर्थन लाइब्रेरी 23.2+ में Fragment के साथ और कुछ भी अतिरिक्त करने की ज़रूरत नहीं है। onActivityResult() अब अनुमानित रूप से नेस्टेड Fragment में कॉल किया गया है।

मैंने अभी एंड्रॉइड सपोर्ट लाइब्रेरी 23.2.1 का उपयोग करके इसका परीक्षण किया है और यह काम करता है। अंत में मैं क्लीनर कोड हो सकता है!

तो, समाधान नवीनतम एंड्रॉइड समर्थन लाइब्रेरी का उपयोग शुरू करना है।

+0

क्या आप इस के लिए कोई आधिकारिक लिंक साझा कर सकते हैं? –

+1

@RaviRupareliya मैंने लिंक के साथ जवाब अपडेट किया है। –

+3

क्या स्वीकृत उत्तर इस में बदला जाना चाहिए? – kaay

0

मुख्य गतिविधि के लिए आप OnActivityForResult सुपर वर्ग के साथ की तरह के रूप में

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent result) { 
    super.onActivityResult(requestCode, resultCode, result); 
    if (requestCode == Crop.REQUEST_PICK && resultCode == RESULT_OK) { 
     beginCrop(result.getData()); 
    } } 

getActivity() बिना टुकड़ा के लिए लिखने के इरादे गतिविधि लिखने के लिए की तरह के रूप में

Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")); 
     pickContactIntent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers 
     startActivityForResult(pickContactIntent, 103); 

OnActivityResult

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (requestCode == 101 && resultCode == getActivity().RESULT_OK && null != data) { 

}}

3

मैंने फ्रैगमेंट एक्टिविटी स्रोत खोजा है। मुझे ये तथ्य मिलते हैं।

  1. टुकड़ा कॉल startActivityForResult(), यह वास्तव में उसके माता-पिता FragmentActivity के startAcitivityFromFragment फोन जब()।
  2. जब खंड के परिणामस्वरूप गतिविधि शुरू होती है, तो अनुरोध कोड 65536 (16 बिट) से नीचे होना चाहिए।
  3. फ्रैगमेंट एक्टिविटी की शुरुआत में एक्टिविटी फ्रॉमफ्रैगमेंट(), यह गतिविधि .startActivityForResult() को कॉल करता है, इस फ़ंक्शन को अनुरोध कोड की भी आवश्यकता होती है, लेकिन यह अनुरोध कोड मूल अनुरोध कोड के बराबर नहीं है।
  4. वास्तव में अनुरोध FragmentActivity में कोड दो भाग है। उच्च 16 बिट मान (FragmentManager में खंड का सूचकांक) + 1. निचला 16 बिट मूल अनुरोध कोड के बराबर है। यही कारण है कि अनुरोध कोड 65536 से नीचे होना चाहिए।

FragmentActivity में कोड देखें।

public void startActivityFromFragment(Fragment fragment, Intent intent, 
     int requestCode) { 
    if (requestCode == -1) { 
     super.startActivityForResult(intent, -1); 
     return; 
    } 
    if ((requestCode&0xffff0000) != 0) { 
     throw new IllegalArgumentException("Can only use lower 16 bits for requestCode"); 
    } 
    super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff)); 
} 

जब परिणाम back.FragmentActivity onActivityResult समारोह को ओवरराइड, और अगर requestCode की उच्च 16bit, 0 नहीं है की तुलना में अपने बच्चों टुकड़ा करने के लिए onActivityResult पारित की जाँच करें।

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    mFragments.noteStateNotSaved(); 
    int index = requestCode>>16; 
    if (index != 0) { 
     index--; 
     final int activeFragmentsCount = mFragments.getActiveFragmentsCount(); 
     if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) { 
      Log.w(TAG, "Activity result fragment index out of range: 0x" 
        + Integer.toHexString(requestCode)); 
      return; 
     } 
     final List<Fragment> activeFragments = 
       mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount)); 
     Fragment frag = activeFragments.get(index); 
     if (frag == null) { 
      Log.w(TAG, "Activity result no fragment exists for index: 0x" 
        + Integer.toHexString(requestCode)); 
     } else { 
      frag.onActivityResult(requestCode&0xffff, resultCode, data); 
     } 
     return; 
    } 

    super.onActivityResult(requestCode, resultCode, data); 
} 

इस प्रकार फ्रैगमेंट एक्टिविटी एक्टिविटी रिसेट इवेंट पर प्रेषण करता है।

जब आपके पास एक टुकड़ा है सक्रियता, इसमें खंड 1 होता है, और खंड 1 में खंड 2 होता है। तो AtctivityResult केवल खंड 1 तक ही जा सकता है।

और मुझे इस समस्या को हल करने का एक तरीका मिल गया है। सबसे पहले नेस्टेडफ्रैगमेंट का विस्तार करें फ्रैगमेंट स्टार्ट एक्टिविटीफॉर रिसेट फ़ंक्शन को ओवरराइड करें।

public abstract class NestedFragment extends Fragment { 

@Override 
public void startActivityForResult(Intent intent, int requestCode) { 

    List<Fragment> fragments = getFragmentManager().getFragments(); 
    int index = fragments.indexOf(this); 
    if (index >= 0) { 
     if (getParentFragment() != null) { 
      requestCode = ((index + 1) << 8) + requestCode; 
      getParentFragment().startActivityForResult(intent, requestCode); 
     } else { 
      super.startActivityForResult(intent, requestCode); 
     } 

    } 
} 

}

से बनाने MyFragment टुकड़ा समारोह को ओवरराइड onActivityResult का विस्तार।

public abstract class MyFragment extends Fragment { 

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    int index = requestCode >> 8; 
    if (index > 0) { 
     //from nested fragment 
     index--; 

     List<Fragment> fragments = getChildFragmentManager().getFragments(); 
     if (fragments != null && fragments.size() > index) { 
      fragments.get(index).onActivityResult(requestCode & 0x00ff, resultCode, data); 
     } 
    } 
} 

}

बस इतना ही! उपयोग:

  1. खंड 1 MyFragment का विस्तार करें।
  2. खंड 2 नेस्टेडफ्रैगमेंट का विस्तार करें।
  3. कोई और अलग नहीं। बस शुरुआत करेंक्टिविटीफॉर रिसेट() को खंड 2 पर, और atctivityResult() फ़ंक्शन को ओवरराइड करें।

वारिंग !!!!!!!! अनुरोध कोड को 512 (8 बिट) को बोले जाना चाहिए, क्योंकि हमने अनुरोध को 3 भाग

16bit | 8 बिट | 8 बिट

उच्च 16 बिट एंड्रॉइड पहले से ही इस्तेमाल किया गया है, मध्य 8 बिट खंड 1 की मदद करने के लिए है, अपने टुकड़े में खंड 2 ढूंढें मैनेजर सरणी। वह सबसे कम 8 बिट मूल अनुरोध कोड है।