क्या कोई ऐसा तरीका है जो परिणाम के लिए काम शुरू करने जैसा है?


95

वर्तमान में मेरे पास एक ओवरले में एक टुकड़ा है। यह सेवा पर हस्ताक्षर करने के लिए है। फोन ऐप में, ओवरले में मेरे द्वारा दिखाए जाने वाले प्रत्येक चरण की अपनी स्क्रीन और गतिविधियां हैं। साइन-इन प्रक्रिया के 3 भाग हैं और प्रत्येक की अपनी गतिविधि थी जिसे startActivityForResult () के साथ बुलाया गया था।

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

जवाबों:


58

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

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


11
इसके अलावा जब एक टुकड़े को दूसरे से लोड किया जाता है तो आप लक्ष्य टुकड़ा सेट कर सकते हैं और onActivityResultयदि आप चाहें तो माता-पिता के टुकड़े की विधि पर वापस कॉल कर सकते हैं ।
PJL

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

1
ठीक है, यह 'परिणाम के लिए टुकड़ा शुरू' कहने के लिए समझ में आता है क्योंकि यह बहुत अधिक लचीलापन देगा -> एक बच्चे के रूप में टुकड़ा अपने माता-पिता के बारे में क्यों जानना चाहिए? टुकड़े के लिए ज्यादा साफ-सुथरा नहीं होगा बस अपना काम करें और परिणाम की परवाह किए बिना कि वह किस गतिविधि में रहता है। विशेष रूप से एकल गतिविधि ऐप्स के संदर्भ में।
daneejela

60

यदि आप चाहें, तो टुकड़े के बीच संचार के लिए कुछ तरीके हैं,

setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()

आप इनका उपयोग करके कॉलबैक कर सकते हैं।

Fragment invoker = getTargetFragment();
if(invoker != null) {
    invoker.callPublicMethod();
}

मैंने इसकी पुष्टि नहीं की है, लेकिन शायद यह काम करता है। इसलिए, आपको दुरुपयोग के संदर्भ में परिपत्र संदर्भ के कारण स्मृति लीक के बारे में ध्यान रखना चाहिए setTargetFragment()
नागोया0

3
अब तक का सबसे अच्छा समाधान! जब एक गतिविधि और टुकड़ों का एक ढेर होता है, जहां अधिसूचित करने के लिए सही टुकड़ा खोजने की कोशिश करना दुःस्वप्न होगा। धन्यवाद
डेमियन प्राका

1
@ userSeven7s इस मामले को बदलने के लिए काम नहीं करेगा, लेकिन छिपाने के मामले में काम करना चाहिए
मुहम्मद बाबर

1
@ nagoya0 बेहतर होता है अगर हम लक्ष्य विखंडन के लिए WeakReference का उपयोग करते हैं
quangson91

जबकि यह काम करता है, setTargetFragmentवर्तमान में पदावनत है। यहां stackoverflow.com/a/61881149/2914140setResultListener में देखें ।
CoolMind

11

हम केवल टुकड़ों के बीच एक ही ViewModel साझा कर सकते हैं

SharedViewModel

import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel

class SharedViewModel : ViewModel() {

    val stringData: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

}

FirstFragment

import android.arch.lifecycle.Observer
import android.os.Bundle
import android.arch.lifecycle.ViewModelProviders
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

class FirstFragment : Fragment() {

    private lateinit var sharedViewModel: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activity?.run {
            sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java)
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        sharedViewModel.stringData.observe(this, Observer { dateString ->
            // get the changed String
        })

    }

}

SecondFragment

import android.arch.lifecycle.ViewModelProviders
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGrou

class SecondFragment : Fragment() {

    private lateinit var sharedViewModel: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        activity?.run {
            sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java)
        }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_first, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        changeString()
    }

    private fun changeString() {
        sharedViewModel.stringData.value = "Test"
    }

}

3
हाय लेवोन, मुझे लगता है कि उपरोक्त कोड समान दृश्य मॉडल उदाहरण साझा नहीं करेगा। आप ViewModelProviders.of (यह) .get (SharedViewModel :: class.java) के लिए यह (टुकड़ा) पास कर रहे हैं। यह टुकड़ों के लिए दो अलग-अलग उदाहरण बनाएगा। आपको गतिविधि देखने की आवश्यकता है ViewModelProviders.of (गतिविधि) .get (SharedViewModel :: class.java)
शैलेन्द्र पाटिल

@ शीलेंद्रपटिल नाइस कैच, मैं इसे अब ठीक करूंगा।
लेवोन पेट्रोसियन

6

हाल ही में, Google ने अभी एक नई क्षमता जोड़ी है, FragmentManagerजिसने FragmentManagerटुकड़े के परिणामों के लिए केंद्रीय स्टोर के रूप में कार्य करने में सक्षम बनाया । हम फ्रेग्मेंट के बीच डेटा को आगे और पीछे आसानी से पास कर सकते हैं।

टुकड़ा शुरू।

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Use the Kotlin extension in the fragment-ktx artifact
    setResultListener("requestKey") { key, bundle ->
        // We use a String here, but any type that can be put in a Bundle is supported
        val result = bundle.getString("bundleKey")
        // Do something with the result...
    }
}

एक टुकड़ा है कि हम परिणाम वापस चाहते हैं।

button.setOnClickListener {
    val result = "result"
    // Use the Kotlin extension in the fragment-ktx artifact
    setResult("requestKey", bundleOf("bundleKey" to result))
}

स्निपेट Google के आधिकारिक दस्तावेजों से लिया गया है। https://developer.android.com/training/basics/fragments/pass-data-between#kotlin

लिखित उत्तर के डेटा पर, यह सुविधा अभी भी जारी है alpha। आप इस निर्भरता का उपयोग करके इसे आज़मा सकते हैं।

androidx.fragment:fragment:1.3.0-alpha05

4

मेरे 2 सेंट।

मैं छिपाने और दिखाने / जोड़ने (मौजूदा / नया) का उपयोग करके एक पुराने टुकड़े को स्वैप करके मधुमक्खी के टुकड़े को स्विच करता हूं। तो यह उत्तर उन देवों के लिए है जो मेरे जैसे टुकड़ों का उपयोग करते हैं।

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

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

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) return;
    Result result = Result.getAndReset();
    if (result == Result.Refresh) {
        refresh();
    }
}

public enum Result {
    Refresh;

    private static Result RESULT;

    public static void set(Result result) {
        if (RESULT == Refresh) {
            // Refresh already requested - no point in setting anything else;
            return;
        }
        RESULT = result;
    }

    public static Result getAndReset() {
        Result result = RESULT;
        RESULT = null;
        return result;
    }
}

getAndReset()विधि क्या है ?
EpicPandaForce

onResume()पहली बर्खास्तगी पर भी नहीं बुलाया जाता है जब दूसरे को खारिज कर दिया जाता है?
PJ_Finnegan

2

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


1

एक एंड्रॉइड लाइब्रेरी है - फ्लोआरआर जो आपको परिणामों के लिए टुकड़े शुरू करने की अनुमति देता है।

परिणाम के लिए एक टुकड़ा शुरू करना।

Flowr.open(RequestFragment.class)
    .displayFragmentForResults(getFragmentId(), REQUEST_CODE);

कॉलिंग टुकड़ा में हैंडलिंग परिणाम।

@Override
protected void onFragmentResults(int requestCode, int resultCode, Bundle data) {
    super.onFragmentResults(requestCode, resultCode, data);

    if (requestCode == REQUEST_CODE) {
        if (resultCode == Activity.RESULT_OK) {
            demoTextView.setText("Result OK");
        } else {
            demoTextView.setText("Result CANCELED");
        }
    }
}

परिणाम को फ्रैगमेंट में सेट करना।

Flowr.closeWithResults(getResultsResponse(resultCode, resultData));

1

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

सबसे पहले, एक इंटरफ़ेस बनाएँ ActionHandler:

interface ActionHandler {
    fun handleAction(actionCode: String, result: Int)
}

इसके बाद, इसे अपने बच्चे (इस मामले में, आपके टुकड़े से) पर कॉल करें:

companion object {
    const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed"
}

fun closeFragment() {
    try {
        (activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234)
    } catch (e: ClassCastException) {
        Timber.e("Calling activity can't get callback!")
    }
    dismiss()
}

अंत में, कॉलबैक प्राप्त करने के लिए अपने माता-पिता में इसे लागू करें (इस मामले में, आपकी गतिविधि):

class MainActivity: ActionHandler { 
    override fun handleAction(actionCode: String, result: Int) {
        when {
            actionCode == FragmentA.FRAGMENT_A_CLOSED -> {
                doSomething(result)
            }
            actionCode == FragmentB.FRAGMENT_B_CLOSED -> {
                doSomethingElse(result)
            }
            actionCode == FragmentC.FRAGMENT_C_CLOSED -> {
                doAnotherThing(result)
            }
        }
    }

0

डेटा वापस पास करने का सबसे आसान तरीका सेटआर्गुमेंट () है। उदाहरण के लिए, आपके पास fragment1 है, जो fragment2 को कॉल करता है, जो fragment3 को कॉल करता है, fragment1 -> framgnet2 -> Bact3

खंड १ में

public void navigateToFragment2() {
    if (fragmentManager == null) return;

    Fragment2 fragment = Fragment2.newInstance();
    String tag = "Fragment 2 here";
    fragmentManager.beginTransaction()
            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
            .add(R.id.flContent, fragment, tag)
            .addToBackStack(null)
            .commitAllowingStateLoss();
}

खंड 2 में हम हमेशा की तरह अंश 3 कहते हैं

private void navigateToFragment3() {
    if (fragmentManager == null) return;
    Fragment3 fragment = new Fragment3();
    fragmentManager.beginTransaction()
            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
            .replace(R.id.flContent, fragment, tag)
            .addToBackStack(null)
            .commit();
}

जब हमने खंड 3 में अपना काम पूरा किया तो अब हम इस तरह से कॉल करते हैं:

FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
if (fragmentManager == null) return;
fragmentManager.popBackStack();
Bundle bundle = new Bundle();
bundle.putString("bundle_filter", "data");
fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);

अब खंड 2 में हम आसानी से तर्क कह सकते हैं

@Override
public void onResume() {
    super.onResume();
    Bundle rgs = getArguments();
    if (args != null) 
        String data = rgs.getString("bundle_filter");
}

इस एक के साथ सावधान रहें, यह कुछ मामलों में काम कर सकता है, लेकिन अगर आपके टुकड़े में मूल तर्क (इस उदाहरण में 'टुकड़ा 2') है, तो यह टुकड़ा बनाने के लिए उपयोग किए जाने वाले मूल तर्कों को ओवरराइड करेगा, जिससे असंगत हो सकता है यदि टुकड़ा नष्ट हो जाता है और फिर से बनाया जाता है।
जुआन

0

एक और चीज जो आप अपने आर्किटेक्चर के आधार पर कर सकते हैं, वह है टुकड़ों के बीच एक साझा व्यूमॉडल का उपयोग करना। तो मेरे मामले में FragmentA एक रूप है, और FragmentB एक आइटम चयन दृश्य है जहां उपयोगकर्ता किसी आइटम को खोज सकता है और उसे चुन सकता है, इसे ViewModel में संग्रहीत कर सकता है। फिर जब मैं फ्रेग्मेंटा वापस आता हूं, तो जानकारी पहले से ही संग्रहीत होती है!

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