পিছনের স্ট্যাকটিতে যুক্ত হওয়ার পরে আমি কীভাবে খন্ডের রাজ্য বজায় রাখতে পারি?


160

আমি একটি ছদ্মবেশী ক্রিয়াকলাপ লিখেছি যা দুটি টুকরোর মধ্যে পরিবর্তন করে। আপনি যখন ফ্র্যাগমেন্টএ থেকে ফ্রেগমেন্টবিতে যান, ফ্রেগমেন্টএ ব্যাক স্ট্যাকটিতে যুক্ত হয়। যাইহোক, আমি যখন ফ্র্যাগমেন্টএ এ ফিরে এসেছি (পিছনে টিপে), তখন একটি সম্পূর্ণ নতুন ফ্রেগমেন্টএ তৈরি হয় এবং যে রাষ্ট্রটি ছিল সেটি হারিয়ে যায়। আমি এই প্রশ্নের মতো একই জিনিসটির পরেও অনুভূতি পেয়েছি , তবে সমস্যাটি নির্মূল করার জন্য আমি একটি সম্পূর্ণ কোড নমুনা অন্তর্ভুক্ত করেছি:

public class FooActivity extends Activity {
  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentA());
    transaction.commit();
  }

  public void nextFragment() {
    final FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(android.R.id.content, new FragmentB());
    transaction.addToBackStack(null);
    transaction.commit();
  }

  public static class FragmentA extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      final View main = inflater.inflate(R.layout.main, container, false);
      main.findViewById(R.id.next_fragment_button).setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
          ((FooActivity) getActivity()).nextFragment();
        }
      });
      return main;
    }

    @Override public void onSaveInstanceState(Bundle outState) {
      super.onSaveInstanceState(outState);
      // Save some state!
    }
  }

  public static class FragmentB extends Fragment {
    @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
      return inflater.inflate(R.layout.b, container, false);
    }
  }
}

কিছু লগ বার্তা যুক্ত করা সহ:

07-05 14:28:59.722 D/OMG     ( 1260): FooActivity.onCreate
07-05 14:28:59.742 D/OMG     ( 1260): FragmentA.onCreateView
07-05 14:28:59.742 D/OMG     ( 1260): FooActivity.onResume
<Tap Button on FragmentA>
07-05 14:29:12.842 D/OMG     ( 1260): FooActivity.nextFragment
07-05 14:29:12.852 D/OMG     ( 1260): FragmentB.onCreateView
<Tap 'Back'>
07-05 14:29:16.792 D/OMG     ( 1260): FragmentA.onCreateView

এটি কখনই ফ্রেগমেন্টএ.অনসেভআইনস্ট্যান্স স্টেটকে কল করে না এবং আপনি পিছনে আঘাত করলে এটি একটি নতুন ফ্রেগমেন্টএ তৈরি করে। তবে, আমি যদি ফ্র্যাগমেন্টএ এ থাকি এবং আমি স্ক্রিনটি লক করি তবে ফ্রেগমেন্টএ.অনস্যাভআইভান্সস্ট্যান্সেট কল হবে না। এত অদ্ভুত ... আমি পুনরায় তৈরির প্রয়োজন নেই এমন ব্যাক স্ট্যাকের সাথে কোনও টুকরো যোগ করার আশা করা কি ভুল? ডক্স যা বলে তা এখানে :

অন্যদিকে, যদি কোনও খণ্ড অপসারণের সময় আপনি যদি addToBackStack () কল করেন তবে খণ্ডটি বন্ধ হয়ে গেছে এবং যদি ব্যবহারকারী ফিরে যান তবে পুনরায় শুরু হবে।


3
@ জান-হেনক যে জিনিসগুলি আনতে হবে সেগুলি সম্পর্কে কী? উদাহরণস্বরূপ, এর স্ক্রোল অবস্থান ListView। কোনও স্ক্রোল শ্রোতাকে সংযুক্ত করতে এবং একটি উদাহরণ ভেরিয়েবল আপডেট করার জন্য অনেক বেশি হুপ-জাম্পিংয়ের মতো মনে হচ্ছে।
জ্যাক ওয়ার্টন

2
@ জ্যাকওয়ার্টন আমি সম্মতি জানাই এটি সহজ হওয়া উচিত, তবে যতদূর আমি জানি এর আশেপাশে কোনও উপায় নেই কারণ অনক্রিটভিউ বলা হয় যখন ব্যাকস্ট্যাক থেকে কোনও খণ্ড পুনঃস্থাপন করা হয়। তবে আমি ভুল হতে পারি :)
জান-হেন্ক

1
onCreate কল হয় না। সুতরাং দৃশ্যত এটি একই উদাহরণটি আবার ব্যবহার করছে তবে আবার ক্রেটভিউকে কল করছে? পঙ্গু. আমার ধারণা আমি অনক্রিয়েটভিউয়ের ফলাফলটি কেবলই ক্যাশে করতে পারি এবং যদি অনক্রিটভিউ আবার কল হয় তবে কেবল বিদ্যমান ভিউটি ফিরিয়ে আনতে পারি।
এরিক

1
ঠিক কী আমি ঘন্টার পর ঘন্টা সন্ধান করছিলাম। আপনি উদাহরণ ভেরিয়েবল ব্যবহার করে এটি কীভাবে অর্জন করেছেন তা পোস্ট করতে পারেন?
উমা

1
তাই আমি সম্প্রতি github.com/frostymarvelous/Folio এ নিজস্ব বাস্তবায়ন শুরু করেছি এবং একটি সমস্যা জুড়ে এসেছি। আমি ওওএম ক্রাশ হওয়া শুরু করার আগে আমি প্রায় 5 টি জটিল পৃষ্ঠা / টুকরো তৈরি করতে সক্ষম। এটাই আমাকে এখানে নিয়ে গেছে। লুকানো এবং দেখানো কেবল যথেষ্ট নয়। ভিউগুলি খুব স্মৃতি ভারী।
হিমশীতল

উত্তর:


120

তা না টুকরা পুনরায় তৈরি কিন্তু সঙ্গে একই উদাহরণস্বরূপ এবং শুরু হয় পুনরায় ব্যবহার আপনাকে ফেরত স্ট্যাক থেকে একটি টুকরা ফিরে আসতে পারেন onCreateView()টুকরা জীবনচক্র মধ্যে দেখতে অসম্পূর্ণ অংশ জীবনচক্র

সুতরাং আপনি যদি স্টেট সংরক্ষণ করতে চান তবে আপনার উদাহরণ ভেরিয়েবলগুলি ব্যবহার করা উচিত এবং নির্ভর করা উচিত নয়onSaveInstanceState()


32
ডকুমেন্টেশনের বর্তমান সংস্করণ এই দাবির বিরোধিতা করে। ফ্লোচার্ট আপনাকে কী বলেছে তা বলেছে, তবে পৃষ্ঠার মূল অঞ্চলে পাঠ্যটি অনক্রিটভিউ () কে কেবল প্রথম বার বলা হয়েছে যখন খণ্ডটি প্রদর্শিত হবে: বিকাশকারী / অ্যান্ড্রয়েড.com/guide/compferences/frations.html আমি এই লড়াই করছি এখনই ইস্যু করুন, এবং আমি ব্যাকস্ট্যাক থেকে কোনও টুকরো ফেরত দেওয়ার সময় কল করা কোনও পদ্ধতি দেখতে পাচ্ছি না। (অ্যান্ড্রয়েড 4.2)
কলিন এম

10
এর আচরণ লগ করার চেষ্টা করেছিল। যখন খণ্ডটি প্রদর্শিত হচ্ছে তখন সর্বদা অনক্রিটভিউ () বলা হয়।
প্রিন্সপিয়ারো

4
@ColinM। সমস্যার কোন সমাধান?
বরফখণ্ড

9
এটি আমার পক্ষে কাজ করে না। আমার উদাহরণের ভেরিয়েবলগুলি খণ্ডটিতে ফিরে আসার জন্য বাতিল! আমি কীভাবে রাষ্ট্রকে বাঁচাতে পারি?
ডন রুম্মি

5
সুতরাং যদি আমাদের সংরক্ষণের উপর রিলে না করা যায় তবে খণ্ডের স্থিতি এবং ডেটা কীভাবে সংরক্ষণ করা উচিত?
মাহদি

80

অ্যাপলের UINavigationControllerএবং তুলনায় UIViewControllerগুগল অ্যান্ড্রয়েড সফ্টওয়্যার আর্কিটেকচারে ভাল করে না। এবং এন্ড্রয়েডের দস্তাবেজগুলি Fragmentতেমন সাহায্য করে না।

আপনি যখন ফ্র্যাগমেন্টএ থেকে ফ্রেগমেন্টবি প্রবেশ করেন, বিদ্যমান ফ্রেগমেন্টএ উদাহরণটি ধ্বংস হয় না। আপনি যখন আবার ফ্র্যাগমেন্টবিতে চাপুন এবং ফ্রেগমেন্টএতে ফিরে আসেন, আমরা কোনও নতুন ফ্রেগমেন্টএ উদাহরণ তৈরি করি না। বিদ্যমান ফ্রেগমেন্টএ উদাহরণগুলি কল করা onCreateView()হবে।

মূল বিষয় হ'ল আমাদের আবার ফ্র্যাগমেন্টএ'র দৃষ্টিভঙ্গি করা উচিত নয় onCreateView(), কারণ আমরা বিদ্যমান ফ্রেগমেন্টএর উদাহরণটি ব্যবহার করছি। আমাদের রুটভিউ সংরক্ষণ এবং পুনরায় ব্যবহার করতে হবে।

নিম্নলিখিত কোডটি ভাল কাজ করে। এটি কেবল খণ্ডের স্থিতিই রাখে না, র‌্যাম এবং সিপিইউ লোডও হ্রাস করে (কারণ আমরা প্রয়োজনে কেবলমাত্র লেআউটকে স্ফীত করি)। আমি বিশ্বাস করতে পারি না গুগলের নমুনা কোড এবং দস্তাবেজটি এর উল্লেখ কখনওই করে না তবে সর্বদা লেফটকে স্ফীত করে

সংস্করণ 1 (সংস্করণ 1 ব্যবহার করবেন না। সংস্করণ 2 ব্যবহার করুন)

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // (it will be added back).
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        return _rootView;
    }
}

------ 3 মে 2005-এ আপডেট: -------

মতামত উল্লিখিত হিসাবে, কখনও কখনও _rootView.getParent()শূন্য হয় onCreateView, যার ফলে ক্রাশ ঘটে। সংস্করণ 2 ডেল 116 এর পরামর্শ অনুসারে, অনটাস্ট্রয়ভিউ () এ _রোটভিউ সরিয়েছে। অ্যান্ড্রয়েড 4.0.3, 4.4.4, 5.1.0 এ পরীক্ষিত।

সংস্করণ 2

public class FragmentA extends Fragment {
    View _rootView;
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        if (_rootView == null) {
            // Inflate the layout for this fragment
            _rootView = inflater.inflate(R.layout.fragment_a, container, false);
            // Find and setup subviews
            _listView = (ListView)_rootView.findViewById(R.id.listView);
            ...
        } else {
            // Do not inflate the layout again.
            // The returned View of onCreateView will be added into the fragment.
            // However it is not allowed to be added twice even if the parent is same.
            // So we must remove _rootView from the existing parent view group
            // in onDestroyView() (it will be added back).
        }
        return _rootView;
    }

    @Override
    public void onDestroyView() {
        if (_rootView.getParent() != null) {
            ((ViewGroup)_rootView.getParent()).removeView(_rootView);
        }
        super.onDestroyView();
    }
}

সতর্কতামূলক !!!

এটি একটি হ্যাক! যদিও আমি এটি আমার অ্যাপ্লিকেশনটিতে ব্যবহার করছি, আপনার মন্তব্যগুলি সাবধানতার সাথে পরীক্ষা করা এবং পড়া দরকার।


38
পুরো খণ্ডের রুটভিউতে একটি রেফারেন্স রাখা একটি খারাপ ধারণা আইএমও। যদি আপনি ক্রমাগত ব্যাকস্ট্যাকটিতে বেশ কয়েকটি টুকরো যোগ করে চলেছেন এবং সেগুলির সমস্তই এর রুটভিউ ধরে রাখছেন (যার বেশিরভাগ মেমরির পদচিহ্ন রয়েছে) তবে আপনি আউটআফমিউরিওর দিয়ে শেষ হওয়ার সম্ভাবনা রয়েছে কারণ সমস্ত টুকরো রুটভিউ রেফারেন্স এবং জিসি ক্যান্ট ধারণ করে না since এটা সংগ্রহ কর. আমি মনে করি আরও ভাল পন্থাটি সর্বদা ভিউতে স্ফীত করা হয় (এবং অ্যান্ড্রয়েড সিস্টেমটি এর দর্শনটি তৈরি / ধ্বংস করতে পরিচালনা করে) এবং অ্যাক্টিভিটি ক্রিয়েটেড / অনভিউ ক্রিয়েটেড চেক করে যদি আপনার ডেটা শূন্য থাকে। যদি হ্যাঁ, তবে এটি লোড করুন, অন্যথায় ডেটা দর্শনে সেট করুন।
traninho

15
এটা করবেন না! যখন খণ্ডের দর্শন শ্রেণিবদ্ধ তৈরি করা হয়, তখন এতে ক্রিয়াকলাপের অভ্যন্তরীণ উল্লেখ রয়েছে যা সেই সময়ের মধ্যে খণ্ডটি রেখেছিল। যখন একটি কনফিগারেশন পরিবর্তন ঘটে, ক্রিয়াকলাপটি প্রায়শই পুনরায় তৈরি করা হয়। পুরানো লেআউটটি পুনরায় ব্যবহার করা সেই জম্বি ক্রিয়াকলাপটিকে মেমরির সাথে রাখে যা কিছু বস্তুর সাথে এটি উল্লেখ করে। এর মতো স্মৃতি নষ্ট করা পারফরম্যান্সকে বাধা দেয় এবং অগ্রণীভূমিতে না থাকলে আপনার অ্যাপটিকে তাত্ক্ষণিক সমাপ্তির জন্য শীর্ষ প্রার্থী করে তোলে।
ক্রিলেজ

4
@ AllDayAmading এটি একটি ভাল বিষয়। সত্যি কথা বলতে কি আমি এখনই খুব বিভ্রান্ত। যে কোনও অংশের রুটভিউয়ের জন্য একটি রেফারেন্স রাখা ঠিক নয় তবে কেবলমাত্র রাউটভিউয়ের কোনও সন্তানের (যেভাবেই রুটভিউয়ের একটি রেফারেন্স আছে) বাচ্চার জন্য একটি রেফারেন্স রাখা কেন ঠিক তা বোঝানোর চেষ্টা করতে পারেন?
ট্রানিনহো

2
আপনি যদি আপনার কোডটি কীভাবে বগিং করছে তার সন্ধান করতে 5 ঘন্টা নষ্ট করতে না চাইলে এদিকেই থাকুন ..... তবে কেবল এটির কারণ খুঁজে বার করুন। এখন আমাকে প্রচুর স্টাফ রিফ্যাক্টর করতে হবে কারণ আমি এই হ্যাকটি ব্যবহার করেছি। ফ্রেমমেন্টের ট্রান্সজেকশন.এডড ব্যবহার করা আরও ভাল যদি আপনি অন্যটিকে দেখার (এমনকি শীর্ষে) আনার সময় এই খণ্ডটির ইউআই-কে কৌশলগত রাখতে চান তবে ফ্রেগমেন্ট ট্রান্সঅ্যাকশন.রেপ্লেস () এর অর্থ ফ্রেগমেন্টের দৃষ্টিভঙ্গি ধ্বংস করা ..... সিস্টেমের সাথে লড়াই করবেন না।
dell116

2
@ ভিনসইয়ান - আমি অ্যান্ড্রয়েড 5.1 এ সর্বশেষতম v7-appcompat গ্রন্থাগারটি দিয়ে পরীক্ষা করেছি এবং এটি আমার ক্রিয়াকলাপের ফ্রেগমেন্টম্যানেজারে অপসারণ করা উচিত ছিল এমন একটি খণ্ডের বামে 6 টি উদাহরণ। এমনকি যদি জিসি এটি সঠিকভাবে পরিচালনা করে (যা আমি এটি বিশ্বাস করি না) এটি আপনার অ্যাপ্লিকেশন এবং সাধারণভাবে ডিভাইসের জন্য মেমরির অপ্রয়োজনীয় চাপ সৃষ্টি করে। কেবলমাত্র .add () ব্যবহার করা এই হ্যাকি কোডের সমস্ত প্রয়োজনকে পুরোপুরি সরিয়ে দেয়। এটি করা সম্পূর্ণরূপে ফ্রেগমেন্টট্রান্সঅ্যাকশন.রেপ্লেস () ব্যবহার করে যা করা হয়েছিল তার বিপরীতে।
dell116

53

আমি মনে করি আপনি যা খুঁজছেন তা অর্জনের বিকল্প উপায় আছে। আমি এর সম্পূর্ণ সমাধান বলি না তবে এটি আমার ক্ষেত্রে উদ্দেশ্যটি কার্যকর করেছিল।

আমি যা করেছি তা হ'ল খণ্ডটি প্রতিস্থাপনের পরিবর্তে আমি কেবলমাত্র লক্ষ্য টুকরা যুক্ত করেছি। সুতরাং মূলত আপনি add()পরিবর্তে পদ্ধতি ব্যবহার করতে যাবেন replace()

আর কি করলাম। আমি আমার বর্তমান খণ্ডটি আড়াল করেছি এবং এটি ব্যাকস্ট্যাকের সাথে যুক্ত করছি।

সুতরাং এটি বর্তমান দৃষ্টিভঙ্গিটি বিনষ্ট না করেই নতুন খণ্ডকে ওভারল্যাপ করে ((পরীক্ষা করুন এটির onDestroyView()পদ্ধতিটি বলা হচ্ছে না Plus প্লাস এটি যুক্ত করে backstateআমাকে খণ্ডটি পুনরায় চালু করার সুবিধা দেয়।

কোডটি এখানে:

Fragment fragment=new DestinationFragment();
FragmentManager fragmentManager = getFragmentManager();
android.app.FragmentTransaction ft=fragmentManager.beginTransaction();
ft.add(R.id.content_frame, fragment);
ft.hide(SourceFragment.this);
ft.addToBackStack(SourceFragment.class.getName());
ft.commit();

আফাইক সিস্টেম কেবল তখনই কল করে onCreateView()যদি দৃশ্যটি ধ্বংস হয় বা তৈরি না হয়। তবে এখানে আমরা ভিউটিকে মেমরি থেকে সরিয়ে না রেখে সংরক্ষণ করেছি। সুতরাং এটি একটি নতুন ভিউ তৈরি করবে না।

এবং আপনি যখন গন্তব্য ফ্রেমমেন্ট থেকে ফিরে আসবেন তখন এটি সর্বশেষ FragmentTransactionঅপসারণ শীর্ষ খণ্ডটিকে পপ করবে যা স্ক্রিনের উপরে শীর্ষস্থানীয় (উত্সফ্র্যাগমেন্টের) দৃশ্যকে দেখাবে।

মন্তব্য: যেমনটি আমি বলেছি এটি সম্পূর্ণ সমাধান নয় কারণ এটি উত্স খণ্ডের দৃষ্টিভঙ্গি সরিয়ে দেয় না এবং তাই স্বাভাবিকের চেয়ে বেশি স্মৃতি ধারণ করে। তবুও, উদ্দেশ্য পরিবেশন। এছাড়াও, আমরা ভিউটি পরিবর্তনের পরিবর্তে লুকানোর সম্পূর্ণ ভিন্ন প্রক্রিয়াটি ব্যবহার করছি যা প্রচলিত নয়।

সুতরাং আপনি কীভাবে রাজ্য বজায় রাখবেন তার পক্ষে এটি সত্যই নয়, আপনি কীভাবে দৃষ্টিভঙ্গি বজায় রাখছেন for


আমার ক্ষেত্রে, পোলিং বা অন্য কোনও ধরণের ওয়েব অনুরোধ ব্যবহার করার সময় এই অংশটি প্রতিস্থাপনের পরিবর্তে একটি খণ্ড যুক্ত করার ফলে সমস্যা দেখা দেয়। আমি এই পোলিংটি ফ্রেগমেন্ট এ এ থামাতে চাই যখন খণ্ড বি যুক্ত হবে। এই সম্পর্কে কোন ধারণা?
উমা

আপনি কীভাবে ফার্স্ট ফ্রেমে ভোটদান ব্যবহার করছেন? উভয় টুকরোগুলি স্মৃতিতে থেকে যাওয়ার কারণে আপনাকে এটি ম্যানুয়ালি করতে হবে o সুতরাং প্রয়োজনীয় ক্রিয়া সম্পাদন করতে আপনি তাদের দৃষ্টান্তগুলি ব্যবহার করতে পারেন the সূত্রের পরে, মূল ক্রিয়ায় একটি ইভেন্ট তৈরি করুন যা আপনি দ্বিতীয় খণ্ড যুক্ত করার সময় কিছু করেন। আশা করি এটি সাহায্য করবে।
কাউশাল ত্রিবেদী

1
ক্লু =) এর জন্য আপনাকে ধন্যবাদ। আমি এটা করেছি। তবে এটি কি একমাত্র উপায়? এবং একটি উপযুক্ত উপায়? এছাড়াও আমি যখন হোম বোতাম টিপুন এবং আবার অ্যাপ্লিকেশন চালু করি তখন সমস্ত খণ্ডগুলি আবার সক্রিয় হয়ে যায়। ধরুন আমি এইভাবে খণ্ড খ-এ এসেছি। Activity A{Fragment A --> Fragment B}আমি যখন হোম বোতাম টিপানোর পরে আবার অ্যাপ্লিকেশনটি চালু করি তখন উভয় খণ্ডকে onResume()ডাকা হয় এবং সেজন্য তারা তাদের পোলিং শুরু করে। আমি কীভাবে এটি নিয়ন্ত্রণ করতে পারি?
উমা

1
দুর্ভাগ্যক্রমে আপনি পারবেন না, সিস্টেমটি এইভাবে স্বাভাবিক আচরণে কাজ করে না, এটি উভয় খণ্ডকে ক্রিয়াকলাপের প্রত্যক্ষ শিশু হিসাবে বিবেচনা করবে oughযেহেতু এটি খণ্ডের অবস্থা বজায় রাখার উদ্দেশ্যে কাজ করেছে, অন্যান্য সাধারণ জিনিস পরিচালনা করা খুব কঠিন হয়ে যায় ate এই সমস্ত বিষয়গুলি আবিষ্কার করেছে, এখন আমার পরামর্শটি এই পথে না যাওয়া উচিত s দুঃখিত।
কাউশাল ত্রিবেদী

1
অবশ্যই, শেষ পর্যন্ত আমি বলব যে আপনি অন্য কোনও সমাধান না পাওয়া পর্যন্ত এই পদ্ধতির সাথে না যাবেন B কারণ এটি পরিচালনা করা শক্ত।
কাউশাল ত্রিবেদী

7

আমি খুব সহজ সমাধানের পরামর্শ দেব।

ওয়ানক্রিয়াটভিউতে ভিউ রেফারেন্স ভেরিয়েবল এবং সেট ভিউটি নিন। এই পরিবর্তনশীলটিতে ভিউ ইতিমধ্যে বিদ্যমান কিনা তা পরীক্ষা করুন, তারপরে একই দর্শনটি ফিরিয়ে দিন।

   private View fragmentView;

   public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);

        if (fragmentView != null) {
            return fragmentView;
        }
        View view = inflater.inflate(R.layout.yourfragment, container, false);
        fragmentView = view;
        return view;
    }

1
অ্যানডেস্রয়ে ()
অরুণ প্রধানমন্ত্রী

@ আরুনপিএম কীভাবে অনডেট্রয়ে () তে টুকরো টুকরোটি সরানো যায়? if (_rootView.getParent() != null) { ((ViewGroup)_rootView.getParent()).removeView(_rootView); }স্মৃতি সাফ করার জন্য উপযুক্ত?
মেহমেট গুর

1
@ মেহমেটগার আমি এই সমাধানটি বহুবার ব্যবহার করছি। এখনও অবধি আমি কোনও মেমরি ফাঁস ত্রুটি পাইনি। আপনি যদি চান তবে এটি দিয়ে অরুণপিএম সমাধানটি ব্যবহার করতে পারেন। আমার মনে হয় তিনি অনডেস্ট্রয় () পদ্ধতিতে খণ্ডনভিউ সেট করতে বলছেন।
মনদীপ সিং

1
আমি যখন এই পদ্ধতিটি অনুসরণ করেছি তখন আমি মেমরির ফাঁস এবং এর ছোঁড়া ফোটা তথ্য সনাক্ত করার জন্য লিক কানারি ব্যবহার করছি । তবে মন্তব্যে @ মনদীপ দীর্ঘশ্বাস যেমন উল্লেখ করেছেন আমরা পদ্ধতিতে পরিবর্তনশীলকে নিয়োগ nullদিয়ে আমরা এই সমস্যাটি কাটিয়ে উঠতে পারি । fragmentViewonDestroy()
অরুণ প্রধানমন্ত্রী

1
আমার জ্ঞান অনুসারে, যখন কোনও খণ্ড নষ্ট হয়ে যায় তখন খণ্ডের সাথে যুক্ত দৃশ্যটি পরিষ্কার হয়ে যায় onDestroyView()। এই ক্লিয়ারিংটি আমাদের ব্যাকআপ ভিউ ভেরিয়েবলের জন্য ঘটছে না (এখানে fragmentView ) এবং খণ্ডটি যখন স্ট্যাকড / নষ্ট হয়ে যায় তখন এটি মেমরি ফাঁসের কারণ হয়ে দাঁড়ায়। আপনি একই স্মৃতি [মেমরি ফাঁসের সাধারণ কারণসমূহ] ( স্কোয়ার.github.io/leakcanary/fundamentals/… ) তে LeakCanery প্রবর্তনে খুঁজে পেতে পারেন।
অরুণ প্রধানমন্ত্রী

6

আমি এই সমস্যাটি একটি মানচিত্রে থাকা একটি খণ্ডে এসে পৌঁছেছি, এতে সংরক্ষণ / পুনরায় লোড করার জন্য অনেক সেটআপ বিশদ রয়েছে। আমার সমাধানটি হ'ল মূলত এই খণ্ডটিকে পুরো সময় সক্রিয় রাখা (@ কাউশাল যা উল্লেখ করেছেন তার অনুরূপ)।

বলুন যে আপনার বর্তমান খণ্ড A রয়েছে এবং ফলাফল টুকরোটি সংক্ষেপে বিভক্ত বি প্রদর্শন করতে চান:

  • প্রতিস্থাপন () - টুকরো টুকরো এটিকে সরিয়ে ফিগ্রেট বি দিয়ে প্রতিস্থাপন করুন ফ্র্যাগমেন্ট এ আবার একবার সামনে এলে পুনরায় তৈরি করা হবে
  • যোগ করুন () - (তৈরি এবং) একটি খণ্ড বি যোগ করুন এবং এটি ফ্র্যাগমেন্ট এটিকে ওভারল্যাপ করে, যা এখনও পটভূমিতে সক্রিয়
  • অপসারণ () - বিভাজন বি অপসারণ করতে এবং এ এ ফিরে আসতে ব্যবহার করতে পারে ফ্রেগমেন্ট বি পরে ডাকা হলে পুনরায় তৈরি করা হবে

অতএব, আপনি যদি উভয় খণ্ডকে "সংরক্ষিত" রাখতে চান তবে কেবল সেগুলি লুকান () / প্রদর্শন () ব্যবহার করে টগল করুন।

পেশাদাররা : একাধিক টুকরোগুলি চলমান রাখার সহজ এবং সহজ পদ্ধতি
কনস : আপনি সেগুলি চালিয়ে যেতে আরও অনেক বেশি মেমরি ব্যবহার করেন। সমস্যার মধ্যে দৌড়াতে পারে, উদাহরণস্বরূপ অনেক বড় বিটম্যাপ প্রদর্শন করা


আপনি কি দয়া করে আমাকে বলতে পারবেন যখন আমরা খণ্ড খ বি সরান এবং A তে ফিরে আসি তখন কোন পদ্ধতিটি খণ্ড A তে বলা হয়? আমি খণ্ড বি বি সরানোর সময় আমি কিছু পদক্ষেপ নিতে চাই
গুগল

5

onSaveInstanceState() কনফিগারেশন পরিবর্তন আছে শুধুমাত্র যদি বলা হয়।

যেহেতু এক টুকরো থেকে অন্য খণ্ডে পরিবর্তন রয়েছে তাই কোনও কনফিগারেশন পরিবর্তন নেই তাই কল করার কোনও কল onSaveInstanceState()নেই। কোন রাষ্ট্র বাঁচানো হচ্ছে না? আপনি নির্দিষ্ট করতে পারেন?

আপনি সম্পাদনা পাঠ্যে কিছু পাঠ্য লিখলে তা স্বয়ংক্রিয়ভাবে সংরক্ষণ করা হবে। কোনও আইডি ছাড়াই যে কোনও ইউআই আইটেম হ'ল সেই আইটেমটি যার দর্শনীয় স্থিতি সংরক্ষণ করা যাবে না।


onSaveInstanceState()সিস্টেমটি ক্রিয়াকলাপ ধ্বংস করে এমন সময়ও বলা হয় কারণ এতে সংস্থার অভাব রয়েছে।
মার্সেল

0

এখানে, যেহেতু onSaveInstanceStateখণ্ডগুলিতে কল করা হয় না যখন আপনি ব্যাকস্ট্যাকে টুকরো যোগ করেন। Backstack মধ্যে টুকরা জীবনচক্র যখন পুনরুদ্ধার শুরু onCreateViewএবং শেষ onDestroyViewকরার সময় onSaveInstanceStateমধ্যে বলা হয় onDestroyViewএবং onDestroy। আমার সমাধান হ'ল দৃষ্টান্ত পরিবর্তনশীল এবং ইন ইন ইন ইন ইন onCreate। কোডের উদাহরণ:

private boolean isDataLoading = true;
private ArrayList<String> listData;
public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     isDataLoading = false;
     // init list at once when create fragment
     listData = new ArrayList();
}

এবং এটি পরীক্ষা করে দেখুন onActivityCreated:

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if(isDataLoading){
         fetchData();
    }else{
         //get saved instance variable listData()
    }
}

private void fetchData(){
     // do fetch data into listData
}

0
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener()
    {
        @Override
        public void onBackStackChanged()
        {
            if (getSupportFragmentManager().getBackStackEntryCount() == 0)
            {
                //setToolbarTitle("Main Activity");
            }
            else
            {
                Log.e("fragment_replace11111", "replace");
            }
        }
    });


YourActivity.java
@Override
public void onBackPressed()
{
 Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.Fragment_content);
  if (fragment instanceof YourFragmentName)
    {
        fragmentReplace(new HomeFragment(),"Home Fragment");
        txt_toolbar_title.setText("Your Fragment");
    }
  else{
     super.onBackPressed();
   }
 }


public void fragmentReplace(Fragment fragment, String fragment_name)
{
    try
    {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.Fragment_content, fragment, fragment_name);
        fragmentTransaction.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
        fragmentTransaction.addToBackStack(fragment_name);
        fragmentTransaction.commitAllowingStateLoss();
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

0

আমার সমস্যাটি একই রকম ছিল কিন্তু আমি টুকরো টিকিয়ে রাখি না আমাকে ছাড়িয়ে। ধরুন আপনার একটি ক্রিয়াকলাপ রয়েছে যাতে 2 টি টুকরো রয়েছে - F1 এবং F2। F1 শুরুতে শুরু করা হয় এবং এর মধ্যে কিছু ব্যবহারকারীর তথ্য থাকে এবং এরপরে কিছু শর্তে ব্যবহারকারীরা অতিরিক্ত গুণাবলী - তাদের ফোন নম্বর পূরণ করতে বলার জন্য F2 পপ করে । এরপরে, আপনি চান যে ফোন নম্বরটি আবার এফ 1 এ চলে যাবে এবং সাইনআপ সম্পূর্ণ করতে পারে তবে আপনি বুঝতে পারবেন যে সমস্ত পূর্ববর্তী ব্যবহারকারীর তথ্য হারিয়ে গেছে এবং আপনার পূর্ববর্তী ডেটা নেই। খণ্ডটি স্ক্র্যাচ থেকে পুনরায় তৈরি করা হয়েছে এমনকি আপনি যদি এই তথ্যটি onSaveInstanceStateবান্ডলে সংরক্ষণ করেন তবে ফিরে আসার পরেও onActivityCreated

সমাধান: কলিং ক্রিয়াকলাপে উদাহরণ পরিবর্তনশীল হিসাবে প্রয়োজনীয় তথ্য সংরক্ষণ করুন। তারপরে আপনার খণ্ডে সেই দৃষ্টান্তটি পরিবর্তন করুন।

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

    Bundle args = getArguments();

    // this will be null the first time F1 is created. 
    // it will be populated once you replace fragment and provide bundle data
    if (args != null) {
        if (args.get("your_info") != null) {
            // do what you want with restored information
        }
    }
}

সুতরাং আমার উদাহরণটি অনুসরণ করে: আমি F2 প্রদর্শন করার আগে একটি কলব্যাক ব্যবহার করে উদাহরণের পরিবর্তনশীলটিতে ব্যবহারকারীর ডেটা সংরক্ষণ করি। তারপরে আমি এফ 2 শুরু করি, ব্যবহারকারী ফোন নম্বর এবং প্রেসগুলি সংরক্ষণ করে। আমি ক্রিয়াকলাপে অন্য কলব্যাক ব্যবহার করি, এই তথ্যটি সংগ্রহ করি এবং আমার খণ্ড F1 প্রতিস্থাপন করি, এবার এটিতে আমি ব্যবহার করতে পারি এমন বান্ডিল ডেটা রয়েছে

@Override
public void onPhoneAdded(String phone) {
        //replace fragment
        F1 f1 = new F1 ();
        Bundle args = new Bundle();
        yourInfo.setPhone(phone);
        args.putSerializable("you_info", yourInfo);
        f1.setArguments(args);

        getFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainer, f1).addToBackStack(null).commit();

    }
}

কলব্যাক সম্পর্কে আরও তথ্য এখানে পাওয়া যাবে: https://developer.android.com/training/basics/fra ابts/communicating.html


0

প্রথম : কেবল ফ্র্যাগমেন্টট্রান্সএশন ক্লাসের পদ্ধতি প্রতিস্থাপনের পরিবর্তে অ্যাড পদ্ধতিটি ব্যবহার করুন তারপরে আপনাকে অ্যাডটোব্যাকস্ট্যাক পদ্ধতিতে স্ট্যাকের জন্য সেকেন্ডফ্র্যাগমেন্ট যুক্ত করতে হবে

দ্বিতীয় : পিছনে ক্লিক করার জন্য আপনাকে পপব্যাকস্ট্যাকআইমিডিয়েট কল করতে হবে ()

Fragment sourceFragment = new SourceFragment ();
final Fragment secondFragment = new SecondFragment();
final FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.child_fragment_container, secondFragment );
ft.hide(sourceFragment );
ft.addToBackStack(NewsShow.class.getName());
ft.commit();
                                
((SecondFragment)secondFragment).backFragmentInstanceClick = new SecondFragment.backFragmentNewsResult()
{
        @Override
        public void backFragmentNewsResult()
        {                                    
            getChildFragmentManager().popBackStackImmediate();                                
        }
};

0

নিম্নলিখিত কোড ব্যবহার করে একটি টুকরো প্রতিস্থাপন করুন:

Fragment fragment = new AddPaymentFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment, "Tag_AddPayment")
                .addToBackStack("Tag_AddPayment")
                .commit();

ক্রিয়াকলাপের অনব্যাকপ্রেসড () হ'ল:

  @Override
public void onBackPressed() {
    android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
    if (fm.getBackStackEntryCount() > 1) {

        fm.popBackStack();
    } else {


        finish();

    }
    Log.e("popping BACKSTRACK===> ",""+fm.getBackStackEntryCount());

}

0
Public void replaceFragment(Fragment mFragment, int id, String tag, boolean addToStack) {
        FragmentTransaction mTransaction = getSupportFragmentManager().beginTransaction();
        mTransaction.replace(id, mFragment);
        hideKeyboard();
        if (addToStack) {
            mTransaction.addToBackStack(tag);
        }
        mTransaction.commitAllowingStateLoss();
    }
replaceFragment(new Splash_Fragment(), R.id.container, null, false);

1
এই কোড স্নিপেটের জন্য আপনাকে ধন্যবাদ, যা কিছু সীমিত, তাত্ক্ষণিক সহায়তা সরবরাহ করতে পারে। একটি সঠিক ব্যাখ্যা কেন এটি সমস্যার একটি ভাল সমাধান তা দেখিয়ে তার দীর্ঘমেয়াদী মানকে ব্যাপকভাবে উন্নত করবে এবং ভবিষ্যতে পাঠকদের আরও অন্যান্য অনুরূপ প্রশ্নের সাথে আরও দরকারী করে তুলবে। আপনার অনুমানগুলি সহ কিছু ব্যাখ্যা যুক্ত করতে দয়া করে আপনার উত্তরটি সম্পাদনা করুন।
মাচাভিটি

0

উপযুক্ত সমাধান যা স্ট্যাকের মধ্যে পুরানো টুকরা খুঁজে বের করে এবং স্ট্যাকের মধ্যে উপস্থিত থাকলে এটি লোড করে।

/**
     * replace or add fragment to the container
     *
     * @param fragment pass android.support.v4.app.Fragment
     * @param bundle pass your extra bundle if any
     * @param popBackStack if true it will clear back stack
     * @param findInStack if true it will load old fragment if found
     */
    public void replaceFragment(Fragment fragment, @Nullable Bundle bundle, boolean popBackStack, boolean findInStack) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        String tag = fragment.getClass().getName();
        Fragment parentFragment;
        if (findInStack && fm.findFragmentByTag(tag) != null) {
            parentFragment = fm.findFragmentByTag(tag);
        } else {
            parentFragment = fragment;
        }
        // if user passes the @bundle in not null, then can be added to the fragment
        if (bundle != null)
            parentFragment.setArguments(bundle);
        else parentFragment.setArguments(null);
        // this is for the very first fragment not to be added into the back stack.
        if (popBackStack) {
            fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        } else {
            ft.addToBackStack(parentFragment.getClass().getName() + "");
        }
        ft.replace(R.id.contenedor_principal, parentFragment, tag);
        ft.commit();
        fm.executePendingTransactions();
    }

এটি পছন্দ করুন

Fragment f = new YourFragment();
replaceFragment(f, null, boolean true, true); 
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.