OnActivityResult से DialogFragment दिखाएँ


82

मेरा एक टुकड़ा के लिए मेरे onActivityResult में निम्नलिखित कोड है:

onActivityResult(int requestCode, int resultCode, Intent data){
   //other code
   ProgressFragment progFragment = new ProgressFragment();  
   progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);
   // other code
}

हालाँकि, मुझे निम्न त्रुटि मिल रही है:

Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState   

किसी को पता है कि क्या चल रहा है, या मैं इसे कैसे ठीक कर सकता हूं? मुझे ध्यान देना चाहिए कि मैं एंड्रॉइड सपोर्ट पैकेज का उपयोग कर रहा हूं।

जवाबों:


75

यदि आप Android समर्थन लाइब्रेरी का उपयोग करते हैं, तो onResume विधि सही जगह नहीं है, जहां टुकड़े के साथ खेलना है। आपको इसे onResumeFragments विधि में करना चाहिए, onResume विधि विवरण देखें: http://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onResume%28%29

तो मेरे दृष्टिकोण से सही कोड होना चाहिए:

private boolean mShowDialog = false;

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

  // remember that dialog should be shown
  mShowDialog = true;
}

@Override
protected void onResumeFragments() {
  super.onResumeFragments();

  // play with fragments here
  if (mShowDialog) {
    mShowDialog = false;

    // Show only if is necessary, otherwise FragmentManager will take care
    if (getSupportFragmentManager().findFragmentByTag(PROG_DIALOG_TAG) == null) {
      new ProgressFragment().show(getSupportFragmentManager(), PROG_DIALOG_TAG);
    }
  }
}

13
+1, यह सही उत्तर है। ध्यान दें कि कक्षा onResumeFragments()में मौजूद नहीं है Activity। यदि आप एक मूल का उपयोग कर रहे हैं Activity, तो आपको onPostResume()इसके बजाय उपयोग करना चाहिए ।
एलेक्स लॉकवुड

3
इस समाधान को लागू करने से पहले, कृपया यह देखने के लिए इसे पढ़ें कि यह हैक क्यों है। इस प्रश्न में एक और समाधान की टिप्पणियों में बहुत सरल समाधान छिपा है।
टहनी

1
Super.onActivityResult को कॉल करना IllegalStateException को रोकता नहीं है, इसलिए यह सबज ठीक नहीं है। समस्या
डेमाकसी

1
यह प्रश्न इस समस्या के लिए Google पर पहली हिट है, लेकिन स्वीकृत उत्तर मेरी राय में सबसे अच्छा नहीं है। इस जवाब को इसके बजाय स्वीकार किया जाना चाहिए: stackoverflow.com/a/30429551/1226020
JHH

27

संपादित करें: बग नहीं, लेकिन टुकड़े के ढांचे में कमी। इस प्रश्न का बेहतर उत्तर ऊपर दिए गए @Arcao द्वारा दिया गया है।

---- मूल पोस्ट ----

वास्तव में यह सपोर्ट पैकेज के साथ एक ज्ञात बग है (संपादित करें: वास्तव में बग नहीं। @ एलेक्स-लॉकवुड की टिप्पणी देखें)। बग रिपोर्ट की टिप्पणियों में चारों ओर एक पोस्ट किया गया काम संवाद के स्रोत को संशोधित करना है जैसे:

public int show(FragmentTransaction transaction, String tag) {
    return show(transaction, tag, false);
}


public int show(FragmentTransaction transaction, String tag, boolean allowStateLoss) {
    transaction.add(this, tag);
    mRemoved = false;
    mBackStackId = allowStateLoss ? transaction.commitAllowingStateLoss() : transaction.commit();
    return mBackStackId;
}

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

public static class PlayerPasswordFragment extends DialogFragment{

 Player toJoin;
 EditText passwordEdit;
 Button okButton;
 PlayerListFragment playerListFragment = null;

 public void onCreate(Bundle icicle){
   super.onCreate(icicle);
   toJoin = Player.unbundle(getArguments());
   Log.d(TAG, "Player id in PasswordFragment: " + toJoin.getId());
 }

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle){
     View v = inflater.inflate(R.layout.player_password, container, false);
     passwordEdit = (EditText)v.findViewById(R.id.player_password_edit);
     okButton = (Button)v.findViewById(R.id.ok_button);
     okButton.setOnClickListener(new View.OnClickListener(){
       public void onClick(View v){
         passwordEntered();
       }
     });
     getDialog().setTitle(R.string.password_required);
     return v;
 }

 public void passwordEntered(){
   //TODO handle if they didn't type anything in
   playerListFragment.joinPlayer(toJoin, passwordEdit.getText().toString());
   dismiss();
 }

 public void registerPasswordEnteredListener(PlayerListFragment playerListFragment){
   this.playerListFragment = playerListFragment;
 }

 public void unregisterPasswordEnteredListener(){
   this.playerListFragment = null;
 }
}

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


3
एक समाधान जिसे स्रोत की प्रतिलिपि बनाने की आवश्यकता नहीं है ... बस ओवरराइड करें show(), और इसे पकड़ें IllegalStateException
जेफरी ब्लाटमैन

1
DialogFragment के स्रोत को कैसे संशोधित करें? या आप अपने पोस्ट के अंत में उल्लिखित अपने समाधान को पोस्ट कर सकते हैं?
पियोट्र

1
@PeterSlesarew मैंने अपना (बल्कि विशिष्ट) समाधान पोस्ट किया है।
कुर्टिस नुसबम K

9
वाह, यह बग नहीं है! एंड्रॉइड फ्रेमवर्क उद्देश्य पर अपवाद को फेंक रहा है क्योंकि यह अंदर खंड लेनदेन करने के लिए सुरक्षित नहीं है onActivityResult()! इसके बजाय इस समाधान का प्रयास करें: stackoverflow.com/questions/16265733/…
एलेक्स लॉकवुड

2
@AlexLockwood प्रलेखन ने इस बारे में चेतावनी नहीं दी जब यह प्रश्न पूछा गया था। इसके अतिरिक्त, जबकि आपका समाधान अभी अच्छा लग रहा है , यह अप्रैल 2012 में वापस काम नहीं किया था। onPostResumeऔर onResumeFragmentsसमर्थन पुस्तकालय के लिए दोनों अपेक्षाकृत नए जोड़ हैं।
hrnt

24

@Natix द्वारा छोड़ी गई टिप्पणी एक त्वरित एक-लाइनर है जिसे कुछ लोगों ने हटाया हो सकता है।

इस समस्या का सबसे सरल समाधान सुपर.ऑनएक्टिविटीResult () से पहले अपना कोड चलाना है। यह परवाह किए बिना काम करता है कि आप समर्थन पुस्तकालय का उपयोग कर रहे हैं या नहीं और आपकी गतिविधि में व्यवहारिक स्थिरता बनाए रखता है।

वहाँ है:

जितना अधिक मैंने इसे पढ़ा है उतना अधिक पागल हैक मैंने देखा है।

यदि आप अभी भी मुद्दों में भाग रहे हैं, तो एलेक्स लॉकवुड द्वारा एक को जांचना है।


यदि आपकी विरासत में क्या होता है? सुपर.ऑनएक्टिविटीResult () कॉल करना एक समस्या हो सकती है यदि आप कॉल सुपर से पहले अपना कोड चलाना चाहते हैं, सुपर क्लास onActivityResult के अंदर अपना कोड रख सकता है, सावधान रहें।
रिकार्ड

मैं super.onActivityResult(requestCode, resultCode, data)अपने किसी भी कोड से पहले जोड़ रहा हूं , इसने मेरा मुद्दा ठीक कर दिया है। लेकिन जब विरासत को जोड़ते हैं या डिफ़ॉल्ट onActivityResult को ओवरराइड करते हैं, तो हमें onStart / onResume को मैन्युअल रूप से संभालना चाहिए
mochadwi

14

मेरा मानना ​​है कि यह एक एंड्रॉइड बग है। असल में एंड्रॉइड onActivityResult को गतिविधि / खंड जीवन चक्र (onStart () से पहले) में एक गलत बिंदु पर कॉल करता है।

बग को https://issuetracker.google.com/issues/36929762 पर सूचित किया गया है

मैंने इसे मूल रूप से एक पैरामीटर के रूप में इंटेंट को संग्रहीत करके हल किया, जिसे मैंने बाद में ओन्यूस्यूम () में संसाधित किया।

[संपादित करें] इस मुद्दे के लिए आजकल बेहतर समाधान हैं जो 2012 में वापस उपलब्ध नहीं थे। अन्य उत्तर देखें।


8
वास्तव में यह वास्तव में एक बग नहीं है। जैसा कि वहाँ टिप्पणियों में बताया गया है, यह स्पष्ट रूप से कहा गया है कि onActivityResult()पहले कहा जाता हैonResume()
कुर्टिस नुसबूम

2
क्या आपने बग पर अंतिम टिप्पणी पढ़ी है? बग यह है कि onActivityResult () को onStart () से पहले कहा जाता है, ऐसा नहीं है कि इसे onResume () से पहले कहा जाता है।
घंटाघर

आह हाँ, यह सच भी है। याद किया कि हालांकि मुझे अभी भी विश्वास है कि अन्य बग रिपोर्ट मेरे मुद्दे से थोड़ी अधिक प्रासंगिक है।
कुर्तिस नुसबम

यह अच्छी तरह से परिभाषित है जब onActivityResult कहा जाता है। इसलिए, यह बग नहीं हो सकता है, भले ही यह कुछ मामलों में अनुचित लग सकता है।
sstn

1
@ sstn, क्या आप विस्तृत कर सकते हैं? यह अच्छी तरह से परिभाषित किया गया है जब onActivityResult कहा जाता है (= onResume से ठीक पहले)। एंड्रॉइड onActivityResult को onResume से तुरंत पहले कॉल नहीं करता है। इस प्रकार, यह एक बग है।
hrnt

11

संपादित करें: अभी तक एक और विकल्प, और संभवतः सबसे अच्छा अभी तक (या, कम से कम समर्थन पुस्तकालय क्या उम्मीद करता है ...)

यदि आप Android समर्थन लाइब्रेरी के साथ DialogFragments का उपयोग कर रहे हैं, तो आपको FragmentActivity के उपवर्ग का उपयोग करना चाहिए। निम्नलिखित प्रयास करें:

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

   super.onActivityResult(requestCode, resultCode, intent);
   //other code

   ProgressFragment progFragment = new ProgressFragment();  
   progFragment.show(getActivity().getSupportFragmentManager(), PROG_DIALOG_TAG);

   // other code
}

मैंने FragmentActivity के लिए स्रोत पर एक नज़र डाली, और ऐसा लग रहा है कि यह राज्य को खोए बिना टुकड़ों को फिर से शुरू करने के लिए एक आंतरिक टुकड़ा प्रबंधक को बुला रहा है।


मुझे एक समाधान मिला जो यहां सूचीबद्ध नहीं है। मैं एक हैंडलर बनाता हूं, और हैंडलर में डायलॉग टुकड़ा शुरू करता हूं। इसलिए, अपने कोड को थोड़ा संपादित करें:

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

   //other code

   final FragmentManager manager = getActivity().getSupportFragmentManager();
   Handler handler = new Handler();
   handler.post(new Runnable() {
       public void run() {
           ProgressFragment progFragment = new ProgressFragment();  
           progFragment.show(manager, PROG_DIALOG_TAG);
       }
   }); 

  // other code
}

यह मुझे साफ-सुथरा और कम हॅसी लगता है।


5
इस समस्या को हल करने के लिए एक हैंडलर का उपयोग केवल एक देरी जोड़ता है, इसलिए यह अधिक संभावना नहीं बनाता है कि समस्या होगी। लेकिन यह इस बात पर ध्यान नहीं देता कि समस्या दूर हो जाएगी! यह दौड़ स्थितियों का उपयोग करके हल करने जैसा है Thread#sleep()
एलेक्स लॉकवुड

27
कॉलिंग super.onActivityResult()सबसे सरल कार्य समाधान है और यह संभवतः स्वीकृत उत्तर होना चाहिए! मैंने दुर्घटना से गायब सुपर कॉल को देखा और सुखद आश्चर्यचकित था कि इसे बस काम कर रहा था। इसने मुझे इस पृष्ठ में वर्णित पुराने हैक में से एक को हटाने की अनुमति दी (संवाद को एक अस्थायी चर में सहेजकर और इसे दिखाते हुए onResume())।
नैटिक्स

अच्छा समाधान है। एकमात्र समस्या यह है कि onActivityResult()किसी भी मूल्य को वापस नहीं करता है जो इंगित करता है कि टुकड़ों ने परिणाम को संभाला है या नहीं।
माइकल

Super.onActivityResult () कॉल करने से मेरी परियोजना में
अवैध उत्खनन की

9

दो DialogFragment शो () विधियाँ हैं - show(FragmentManager manager, String tag)और show(FragmentTransaction transaction, String tag)

यदि आप विधि के FragmentManager संस्करण (मूल प्रश्न के अनुसार) का उपयोग करना चाहते हैं, तो एक आसान उपाय इस विधि को ओवरराइड करना है और कमिटेशन StateLoss का उपयोग करना है:

public class MyDialogFragment extends DialogFragment {

  @Override 
  public void show(FragmentManager manager, String tag) {
      FragmentTransaction ft = manager.beginTransaction();
      ft.add(this, tag);
      ft.commitAllowingStateLoss();
  }

}

show(FragmentTransaction, String)इस तरह से ओवरराइड करना इतना आसान नहीं है क्योंकि इसे मूल डायलॉगफ्रेगमेंट कोड के भीतर कुछ आंतरिक चर को भी संशोधित करना चाहिए, इसलिए मैं इसकी सिफारिश नहीं करूंगा - यदि आप उस पद्धति का उपयोग करना चाहते हैं, तो स्वीकृत उत्तर में सुझावों का प्रयास करें (या टिप्पणी से) जेफरी ब्लाटमैन)।

कमिशनिंग स्टेटमेंट का उपयोग करने में कुछ जोखिम है - प्रलेखन में कहा गया है, "पसंद कमिट () लेकिन किसी गतिविधि की स्थिति से बचने के बाद कमिट को निष्पादित करने की अनुमति देता है। यह खतरनाक है क्योंकि अगर बाद में इसके राज्य में गतिविधि को बहाल करने की आवश्यकता होती है तो कमिट खो सकता है। , इसलिए इसका उपयोग केवल उन मामलों के लिए किया जाना चाहिए जहां उपयोगकर्ता पर अप्रत्याशित रूप से बदलने के लिए UI स्थिति के लिए ठीक है। "


4

संलग्न गतिविधि के बाद आप डायलॉग नहीं दिखा सकते हैं, इसका तरीका onSaveInstanceState () है। जाहिर है, onSaveInstanceState () onActivityResult () से पहले कहा जाता है। तो आपको इस कॉलबैक विधि OnResumeFragment () में अपना संवाद दिखाना चाहिए, आपको DialogFragment के शो () विधि को ओवरराइड करने की आवश्यकता नहीं है। आशा है कि यह आपकी मदद करेगा।


3

मैं एक तीसरे समाधान के साथ आया, आंशिक रूप से एचएमटी के समाधान से आधारित। मूल रूप से, डायलॉगफ्रैगमेंट्स का एक एट्रेलिस्ट बनाएं, जिसे ओन्यूसम () पर दिखाया जाए;

ArrayList<DialogFragment> dialogList=new ArrayList<DialogFragment>();

//Some function, like onActivityResults
{
    DialogFragment dialog=new DialogFragment();
    dialogList.add(dialog);
}


protected void onResume()
{
    super.onResume();
    while (!dialogList.isEmpty())
        dialogList.remove(0).show(getSupportFragmentManager(),"someDialog");
}

3

onActivityResult () onResume () से पहले निष्पादित होता है। आपको अपने यूआई को onResume () या बाद में करने की आवश्यकता है।

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

... बस। सरल।


2

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

इसे संभालने के लिए यह मेरा कोड है, और यह खूबसूरती से काम करता है:

DialogFragment myFrag; //Don't forget to instantiate this
FragmentTransaction trans = getActivity().getSupportFragmentManager().beginTransaction();
trans.add(myFrag, "MyDialogFragmentTag");
trans.commitAllowingStateLoss();

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

उम्मीद है की यह मदद करेगा...


2

यह एक पुराना सवाल है, लेकिन मैंने सबसे सरल तरीके से हल किया है, मुझे लगता है:

getActivity().runOnUiThread(new Runnable() {
    @Override
        public void run() {
            MsgUtils.toast(getString(R.string.msg_img_saved),
                    getActivity().getApplicationContext());
        }
    });

2

ऐसा इसलिए होता है क्योंकि जब #onActivityResult () कहा जाता है, तो पैरेंट एक्टिविटी में पहले से ही #onSaveInstance_ate () कॉल होता है।

मैं #onActivityResult () पर एक्शन (शो डायलॉग) को "सेव" करने के लिए एक रनवेबल का उपयोग करूंगा, जब बाद में एक्टिविटी तैयार हो गई हो।

इस दृष्टिकोण के साथ हम यह सुनिश्चित करते हैं कि हम जो कार्य करना चाहते हैं वह हमेशा काम करेगा

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == YOUR_REQUEST_CODE) {
        mRunnable = new Runnable() {
            @Override
            public void run() {
                showDialog();
            }
        };
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

@Override
public void onStart() {
    super.onStart();
    if (mRunnable != null) {
        mRunnable.run();
        mRunnable = null;
    }
}

0

मैंने पाया सबसे साफ समाधान यह है:

@Override
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
    new Handler().post(new Runnable() {
        @Override
        public void run() {
            onActivityResultDelayed(requestCode, resultCode, data);
        }
    });
}

public void onActivityResultDelayed(int requestCode, int resultCode, Intent data) {
    // Move your onActivityResult() code here.
}

0

मुझे यह त्रुटि .show(getSupportFragmentManager(), "MyDialog");गतिविधि में करते समय मिली ।

.show(getSupportFragmentManager().beginTransaction(), "MyDialog");पहले प्रयास करें ।

यदि फिर भी काम नहीं कर रहा है, तो यह पोस्ट ( onActivityResult से DialogFragment ) समस्या को हल करने में मेरी मदद करता है।


0

दूसरा रास्ता:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case Activity.RESULT_OK:
            new Handler(new Handler.Callback() {
                @Override
                public boolean handleMessage(Message m) {
                    showErrorDialog(msg);
                    return false;
                }
            }).sendEmptyMessage(0);
            break;
        default:
            super.onActivityResult(requestCode, resultCode, data);
    }
}


private void showErrorDialog(String msg) {
    // build and show dialog here
}


-3

जैसा कि आप सभी जानते हैं कि onActivityResult () onstart () से पहले कॉल करने के कारण यह समस्या है, इसलिए onActivityResult () में शुरू में ही onstart () कॉल करें जैसे मैंने इस कोड में किया है

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      onStart();
      //write you code here
}

आपको कभी भी एंड्रॉइड जीवन चक्र विधियों को सीधे कॉल नहीं करना चाहिए । उन्हें केवल सिस्टम द्वारा बुलाया जाना चाहिए।
चैनेल ओस्जो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.