অ্যান্ড্রয়েডে স্ক্রিন রোটেশনে ডায়লগ বরখাস্ত হওয়া রোধ করুন


94

ক্রিয়াকলাপটি পুনরায় চালু করা হলে আমি সতর্কতা নির্মাতার সাথে নির্মিত ডায়লগগুলিকে বরখাস্ত হতে বাধা দেওয়ার চেষ্টা করছি।

যদি আমি onCfigrationChanged পদ্ধতিতে ওভারলোড করি তবে আমি সফলভাবে এটি করতে পারি এবং অরিয়েন্টেশনটি সংশোধন করার জন্য লেআউটটিকে পুনরায় সেট করতে পারি তবে আমি সম্পাদনাটির টেক্সট বৈশিষ্ট্যটি হারাব। তাই ডায়ালগ সমস্যা সমাধানে আমি এই সম্পাদনাটি সমস্যা তৈরি করেছি।

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

আমার ডায়ালগ সমস্যা বা এডিটেক্সট সমস্যাটি সত্যিই সমাধান করা দরকার।

সাহায্যের জন্য ধন্যবাদ.


4
আপনি সম্পাদিত সম্পাদনা পাঠ্য সামগ্রীটি কীভাবে সংরক্ষণ / পুনরুদ্ধার করবেন? আপনি কিছু কোড প্রদর্শন করতে পারেন?
পিটার কেঙ্গো

আমি এটির সাথে সমস্যাটি বের করেছিলাম, আমি লেআউটটি পুনরায় সেট করার পরে আইডির মাধ্যমে আবার ভিউটি ভুলে যাচ্ছিলাম।
ড্রাক্সিয়া

উত্তর:


134

আজকাল এই সমস্যা এড়ানোর সর্বোত্তম উপায় হ'ল একটি ব্যবহার করে DialogFragment

প্রসারিত একটি নতুন শ্রেণি তৈরি করুন DialogFragment। ওভাররাইড onCreateDialogএবং আপনার পুরানো Dialogবা একটি ফিরে AlertDialog

তারপরে আপনি এটি দিয়ে দেখাতে পারেন DialogFragment.show(fragmentManager, tag)

এখানে একটি সহ একটি উদাহরণ Listener:

public class MyDialogFragment extends DialogFragment {

    public interface YesNoListener {
        void onYes();

        void onNo();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (!(activity instanceof YesNoListener)) {
            throw new ClassCastException(activity.toString() + " must implement YesNoListener");
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.dialog_my_title)
                .setMessage(R.string.dialog_my_message)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((YesNoListener) getActivity()).onYes();
                    }
                })
                .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((YesNoListener) getActivity()).onNo();
                    }
                })
                .create();
    }
}

এবং ক্রিয়াকলাপে আপনি কল করেছেন:

new MyDialogFragment().show(getSupportFragmentManager(), "tag"); // or getFragmentManager() in API 11+

এই উত্তরটি এই আরও তিনটি প্রশ্নের (এবং তাদের উত্তর) ব্যাখ্যা করতে সহায়তা করে:


আমার অ্যাপ্লিকেশনটিতে একটি বোতাম রয়েছে .শো () বলার জন্য, আমাকে সতর্কতা ডায়ালগের অবস্থাটি স্মরণ করতে হবে, দেখানো / বরখাস্ত করা হবে। .Show () না কল করে ডায়ালগ রাখার উপায় আছে কি?
আলফা হুয়াং

4
এটি বলে যে onAttachএটি এখন অবচয় করা হয়েছে। পরিবর্তে কি করা উচিত?
ফারাহাম

4
@ ফারাজ_হমেদ_কামরান, আপনার ব্যবহার করা উচিত onAttach(Context context)এবং android.support.v4.app.DialogFragmentonAttachপদ্ধতি লাগে contextপরিবর্তে activityহিসাবে একটি প্যারামিটার এখন।
স্ট্যান মটস

YesNoListenerযদিও এর জন্য সম্ভবত কোনও প্রয়োজন নেই । এই উত্তর দেখুন ।
মাইগড

46
// Prevent dialog dismiss when orientation changes
private static void doKeepDialog(Dialog dialog){
    WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
    lp.copyFrom(dialog.getWindow().getAttributes());
    lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
    lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
    dialog.getWindow().setAttributes(lp);
}
public static void doLogout(final Context context){     
        final AlertDialog dialog = new AlertDialog.Builder(context)
        .setIcon(android.R.drawable.ic_dialog_alert)
        .setTitle(R.string.titlelogout)
        .setMessage(R.string.logoutconfirm)
        .setPositiveButton("Yes", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                ...   
            }

        })
        .setNegativeButton("No", null)      
        .show();    

        doKeepDialog(dialog);
    }

4
যাদের কাছে আমার কোডটি দরকারী না তা খুঁজে পেতে ক্লিক করুন :-)
চুং আইডাব্লু

6
কাজ করে, জানেন না তবে কীভাবে এটি কাজ করে! সহজ এবং বিমূর্ত সমাধান পরিষ্কার করুন, ধন্যবাদ।
nmvictor

4
আমি মনে করি এই কোডটি খারাপ। doLogout () এর ক্রিয়াকলাপের একটি উল্লেখ রয়েছে যা ক্রিয়াকলাপটিকে অন্তর্ভুক্ত করে / রাখে। ক্রিয়াকলাপটি ধ্বংস করা যায় না যা মেমরি ফাঁস হতে পারে। আমি স্থিতিশীল প্রসঙ্গ থেকে সতর্কতা ডায়ালগ ব্যবহার করার সম্ভাবনা খুঁজছিলাম কিন্তু এখন আমি নিশ্চিত যে এটি অসম্ভব। ফলাফলটি কেবল আমার মনে হয় আবর্জনা হতে পারে।
অবিশ্বাস্য জানুয়ারী

4
দেখে মনে হচ্ছে এটি কাজ করে। কথোপকথনটি উন্মুক্ত থাকে, তবে নতুন তৈরি করা ক্রিয়াকলাপ বা খণ্ডের সাথে এর কোনও সংযোগ নেই (এটি প্রতিটি ওরিয়েন্টেশন পরিবর্তনে নতুন তৈরি হয়)। সুতরাং আপনি এমন কিছু করতে পারবেন না যার জন্য Contextডায়ালগ বোতামগুলির অভ্যন্তরের প্রয়োজন OnClickListener
উদো ক্লিমাশেউস্কি

4
এই কোডটি কাজ করে তবে একেবারেই সুপারিশ করে না। এটি ক্রিয়াকলাপের রেফারেন্স ফাঁস করে, এজন্য ডায়ালগটি অবিরাম থাকতে পারে। এটি একটি খুব খারাপ অনুশীলন যা মেমরি ফাঁস হতে পারে।
Hexise

4

আপনি যদি ওরিয়েন্টেশন পরিবর্তনের উপর বিন্যাস পরিবর্তন করেন তবে আমি android:configChanges="orientation"আপনার ম্যানিফেস্টে রাখব না কারণ আপনি যেভাবেই মতামত পুনরায় তৈরি করছেন।

এই পদ্ধতিগুলি ব্যবহার করে আপনার ক্রিয়াকলাপের বর্তমান অবস্থা (যেমন পাঠ্য প্রবেশ করানো, প্রদর্শিত ডায়ালগ, ডেটা প্রদর্শিত ইত্যাদি) সংরক্ষণ করুন:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
}

এইভাবে আবার ক্রিয়াকলাপটি অনক্রিটের মধ্য দিয়ে যায় এবং তারপরে অনরেস্টোরইনস্ট্যান্সস্টেট পদ্ধতিতে কল করে যেখানে আপনি নিজের সম্পাদনা পাঠ্য মানটি আবার সেট করতে পারেন।

আপনি যদি আরও জটিল অবজেক্টগুলি সঞ্চয় করতে চান তবে আপনি ব্যবহার করতে পারেন

@Override
public Object onRetainNonConfigurationInstance() {
}

এখানে আপনি যে কোনও অবজেক্ট সংরক্ষণ করতে পারেন এবং অনক্রিটে আপনাকে কেবল অবজেক্টটি getLastNonConfigurationInstance();পেতে কল করতে হবে।


4
OnRetainNonConfigurationInstance()এখন ডক হিসাবে অবচিত বলেছেন: developer.android.com/reference/android/app/... setRetainInstance(boolean retain) পরিবর্তে ব্যবহার হওয়া উচিত: developer.android.com/reference/android/app/...
ForceMagic

@ ফোরস ম্যাজিক setRetainInstanceসম্পূর্ণ আলাদা: এটি খণ্ডগুলির জন্য এবং এটি আপনাকে গ্যারান্টি দেয় না যে দৃষ্টান্তটি বজায় থাকবে।
মিহা_এক্স 64

3

কেবলমাত্র অ্যান্ড্রয়েড যুক্ত করুন: অ্যান্ড্রয়েড ম্যানিফেস্ট.এক্সএমএলে আপনার ক্রিয়াকলাপের সাথে কনফিগারেশন = "ওরিয়েন্টেশন"

উদাহরণ:

<activity
            android:name=".YourActivity"
            android:configChanges="orientation"
            android:label="@string/app_name"></activity>

এর ফলে কিছু পরিস্থিতিতে ডায়ালগটি ভুলভাবে প্রদর্শিত হতে পারে।
স্যাম

4
অ্যান্ড্রয়েড: কনফিগারেশন = "ওরিয়েন্টেশন | স্ক্রিনসাইজ" দ্রষ্টব্য: যদি আপনার অ্যাপ্লিকেশনটি অ্যান্ড্রয়েড 3.2 (এপিআই স্তর 13) বা তার চেয়ে বেশি উচ্চতর লক্ষ্য করে, তবে আপনার "স্ক্রিনসাইজ" কনফিগারেশনটিও ঘোষণা করা উচিত, কারণ কোনও ডিভাইস প্রতিকৃতি এবং ল্যান্ডস্কেপ ওরিয়েন্টেশনের মধ্যে স্যুইচ করলে এটিও পরিবর্তিত হয়।
tsig

1

একটি খুব সহজ পদ্ধতির পদ্ধতিটি থেকে ডায়ালগগুলি তৈরি করা onCreateDialog()(নীচের নোটটি দেখুন)। আপনি তাদের মাধ্যমে প্রদর্শন করুন showDialog()। এইভাবে, অ্যান্ড্রয়েড আপনার জন্য রোটেশন পরিচালনা করে এবং আপনাকে কল করতে হবে dismiss()নাonPause() একটি WindowLeak এড়াতে এবং তারপর আপনি তন্ন তন্ন ডায়ালগ পুনরুদ্ধার করতে হবে। ডক্স থেকে:

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

দেখুন অ্যানড্রইড ডক্স showDialog () আরও তথ্যের জন্য। আশা করি এটি কাউকে সাহায্য করবে!

নোট: যদি AlertDialog.Builder ব্যবহার করে, কল না show()থেকে onCreateDialog(), কল create()পরিবর্তে। যদি প্রগ্রেসডায়ালগ ব্যবহার করে থাকেন তবে কেবল অবজেক্টটি তৈরি করুন, আপনার প্রয়োজনীয় প্যারামিটারগুলি সেট করুন এবং এটি ফিরিয়ে দিন। উপসংহারে, show()অভ্যন্তরীণ onCreateDialog()সমস্যার সৃষ্টি করে, কেবলমাত্র ডায়ালগ উদাহরণ তৈরি করুন এবং এটিকে ফিরিয়ে দিন। এই কাজ করা উচিত! (অনক্রিট () -রূপে ডায়ালগটি না দেখানো থেকে শোডায়ালগ () ব্যবহার করে আমার সমস্যা হয়েছে, তবে আপনি যদি এটি অনারিউম () বা শ্রোতার কলব্যাকে ব্যবহার করেন তবে এটি ভাল কাজ করে)।


কোন ক্ষেত্রে আপনার কিছু কোড দরকার? অনক্রিটডায়ালগ () বা বিল্ডারের সাথে এটি দেখানো এবং এর কাছে কলিং শো ()?
কেমনস

আমি এটি করতে পেরেছি .. তবে কথাটি হ'ল, ক্রিয়েটডায়ালগ () এখন
অবচয় করা

ঠিক আছে! মনে রাখবেন যে বেশিরভাগ অ্যান্ড্রয়েড ডিভাইস এখনও ২. এক্স সংস্করণ দিয়ে কাজ করে, তাই আপনি যেভাবেই এটি ব্যবহার করতে পারেন! কটাক্ষপাত আছে অ্যান্ড্রয়েড প্ল্যাটফর্ম সংস্করণ ব্যবহার
Caumons

তবুও, অনক্রিটডায়ালগ না থাকলে অন্য বিকল্পটি কী?
neteinstein

4
আপনি বিল্ডার ক্লাসগুলি উদাহরণস্বরূপ ব্যবহার করতে পারেন AlertDialog.Builder। আপনি যদি এটি ভিতরে ব্যবহার করেন তবে onCreateDialog()পরিবর্তে এর show()ফলাফলটি ফেরত দিন create()। অন্যথায়, show()ফিরে আসা সতর্কতা ডায়ালগটিকে ক্রিয়াকলাপের একটি বৈশিষ্ট্যে এবং onPause() dismiss()এটিতে উইন্ডোএলিক এড়ানোর জন্য যদি প্রদর্শিত হয় তবে কল করুন এবং সংরক্ষণ করুন । আশা করি এটা সাহায্য করবে!
কেমনস

1

এই প্রশ্নের উত্তর অনেক আগেই দেওয়া হয়েছিল।

তবুও এটি আমি নিজের জন্য ব্যবহার করি না এমন হ্যাকি এবং সহজ সমাধান।

আমি এই সহায়ক সহায়কটি নিজের জন্য করেছিলাম, তাই আপনিও এটি প্রয়োগ করতে পারেন।

ব্যবহার হ'ল:

PersistentDialogFragment.newInstance(
        getBaseContext(),
        RC_REQUEST_CODE,
        R.string.message_text,
        R.string.positive_btn_text,
        R.string.negative_btn_text)
        .show(getSupportFragmentManager(), PersistentDialogFragment.TAG);

বা

 PersistentDialogFragment.newInstance(
        getBaseContext(),
        RC_EXPLAIN_LOCATION,
        "Dialog title", 
        "Dialog Message", 
        "Positive Button", 
        "Negative Button", 
        false)
    .show(getSupportFragmentManager(), PersistentDialogFragment.TAG);





public class ExampleActivity extends Activity implements PersistentDialogListener{

        @Override
        void onDialogPositiveClicked(int requestCode) {
                switch(requestCode) {
                  case RC_REQUEST_CODE:
                  break;
                }
        }

        @Override
        void onDialogNegativeClicked(int requestCode) {
                switch(requestCode) {
                  case RC_REQUEST_CODE:
                  break;
                }          
        }
}

1

আপনি ডায়ালগের পরিস্থিতি ধরে রাখতে ক্রিয়াকলাপের অন ​​সেভ / অনরেস্টোর পদ্ধতির সাথে ডায়লগের অন সেভ / অনরেস্টোর পদ্ধতিগুলিকে একত্রিত করতে পারেন ।

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

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
     super.onRestoreInstanceState(savedInstanceState);
     myDialog.onRestoreInstanceState(savedInstanceState.getBundle("DIALOG"));
     // Put your codes to retrieve the EditText contents and 
     // assign them to the EditText here.
}

@Override
protected void onSaveInstanceState(Bundle outState) {
     super.onSaveInstanceState(outState);
     // Put your codes to save the EditText contents and put them 
     // to the outState Bundle here.
     outState.putBundle("DIALOG", myDialog.onSaveInstanceState());
}

1

ডায়ালগফ্রেগমেন্ট ব্যবহার করে অবশ্যই সর্বোত্তম পন্থা।

এখানে র‍্যাপার ক্লাসের আমার সমাধানটি যা বিভিন্ন ডায়ালগকে এক টুকরো (বা ছোট রিফ্যাক্টরিং সহ ক্রিয়াকলাপ) এর মধ্যে বরখাস্ত করা থেকে বিরত রাখতে সহায়তা করে। এছাড়াও, কিছু কারণের কারণে AlertDialogsক্রিয়াকলাপ, উপস্থিতি বা অন্য কোনও কিছুর ক্ষেত্রে সামান্য পার্থক্যের সাথে কোডের মধ্যে প্রচুর পরিমাণে ছড়িয়ে ছিটিয়ে থাকলে তা প্রচুর কোড রিফ্যাক্টরিং এড়াতে সহায়তা করে ।

public class DialogWrapper extends DialogFragment {
    private static final String ARG_DIALOG_ID = "ARG_DIALOG_ID";

    private int mDialogId;

    /**
     * Display dialog fragment.
     * @param invoker  The fragment which will serve as {@link AlertDialog} alert dialog provider
     * @param dialogId The ID of dialog that should be shown
     */
    public static <T extends Fragment & DialogProvider> void show(T invoker, int dialogId) {
        Bundle args = new Bundle();
        args.putInt(ARG_DIALOG_ID, dialogId);
        DialogWrapper dialogWrapper = new DialogWrapper();
        dialogWrapper.setArguments(args);
        dialogWrapper.setTargetFragment(invoker, 0);
        dialogWrapper.show(invoker.getActivity().getSupportFragmentManager(), null);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mDialogId = getArguments().getInt(ARG_DIALOG_ID);
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return getDialogProvider().getDialog(mDialogId);
    }

    private DialogProvider getDialogProvider() {
        return (DialogProvider) getTargetFragment();
    }

    public interface DialogProvider {
        Dialog getDialog(int dialogId);
    }
}

যখন কার্যকলাপের বিষয়টি আসে আপনি getContext()ভিতরে প্রবেশ করতে পারেন onCreateDialog(), এটিকে DialogProviderইন্টারফেসে কাস্ট করতে পারেন এবং নির্দিষ্ট সংলাপের মাধ্যমে অনুরোধ করতে পারেন mDialogId। একটি লক্ষ্য টুকরা নিয়ে কাজ করার সমস্ত যুক্তি মুছে ফেলা উচিত।

খণ্ড থেকে ব্যবহার:

public class MainFragment extends Fragment implements DialogWrapper.DialogProvider {
    private static final int ID_CONFIRMATION_DIALOG = 0;

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Button btnHello = (Button) view.findViewById(R.id.btnConfirm);
        btnHello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DialogWrapper.show(MainFragment.this, ID_CONFIRMATION_DIALOG);
            }
        });
    }

    @Override
    public Dialog getDialog(int dialogId) {
        switch (dialogId) {
            case ID_CONFIRMATION_DIALOG:
                return createConfirmationDialog(); //Your AlertDialog
            default:
                throw new IllegalArgumentException("Unknown dialog id: " + dialogId);
        }
    }
}

আপনি আমার ব্লগে সম্পূর্ণ নিবন্ধটি পড়তে পারেন কীভাবে ডায়ালগকে বরখাস্ত করা যায়? এবং সঙ্গে খেলুন উত্স কোডের


1

দেখে মনে হচ্ছে এটি "এখনও সব কিছু সঠিকভাবে করা" এবং ব্যবহার করার পরেও এটি একটি সমস্যা DialogFragment ইত্যাদির

গুগল ইস্যু ট্র্যাকারে একটি থ্রেড রয়েছে যা দাবি করে যে এটি কোনও পুরানো বরখাস্ত বার্তা বার্তার কাতারে রেখে যাওয়ার কারণে। সরবরাহকৃত কর্মক্ষেত্রটি বেশ সহজ:

    @Override
    public void onDestroyView() {
        /* Bugfix: https://issuetracker.google.com/issues/36929400 */
        if (getDialog() != null && getRetainInstance())
            getDialog().setDismissMessage(null);

        super.onDestroyView();
    }

অবিশ্বাস্য যে সমস্যাটি প্রথম প্রকাশিত হওয়ার 7 বছর পরে এটি এখনও প্রয়োজন।



0

আমার অনুরূপ সমস্যা ছিল: যখন স্ক্রিনের ওরিয়েন্টেশন পরিবর্তন হয়েছিল, তখন ডায়ালগটির onDismissশ্রোতাকে ডাকা হয়েছিল যদিও ব্যবহারকারী ডায়ালগটি খারিজ করেননি didn't আমি onCancelশ্রোতার পরিবর্তে এটিকে ঘিরে কাজ করতে সক্ষম হয়েছি , যা ব্যবহারকারী যখন পিছনের বোতামটি টিপায় এবং ব্যবহারকারী যখন ডায়ালগের বাইরের স্পর্শ করে তখন উভয়ই ট্রিগার করে।


-3

শুধু ব্যবহার

ConfigurationChanges = Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize

এবং অ্যাপ্লিকেশন কীভাবে রোটেশন এবং স্ক্রিনের আকার পরিচালনা করবে তা জানবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.