অ্যান্ড্রয়েড ভিউ উইন্ডো ম্যানেজারের সাথে সংযুক্ত নেই


111

আমি নিম্নলিখিত কিছু ব্যতিক্রম করছি:

java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:191)
at android.view.Window$LocalWindowManager.updateViewLayout(Window.java:428)
at android.app.Dialog.onWindowAttributesChanged(Dialog.java:596)
at android.view.Window.setDefaultWindowFormat(Window.java:1013)
at com.android.internal.policy.impl.PhoneWindow.access$700(PhoneWindow.java:86)
at com.android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.java:1951)
at com.android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.java:1889)
at android.view.ViewRoot.performTraversals(ViewRoot.java:727)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4338)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)

আমি এটি গুগল করে দেখেছি এটি পপআপগুলি এবং স্ক্রিনটি ঘুরিয়ে দেওয়ার সাথে কিছু করার আছে তবে আমার কোডের কোনও রেফারেন্স নেই।

প্রশ্নগুলি হ'ল:

  1. এই সমস্যাটি কখন ঘটছে তা খুঁজে পাওয়ার কোনও উপায় আছে?
  2. স্ক্রিনটি ঘুরিয়ে দেওয়া ছাড়াও, এমন কোনও ঘটনা বা ক্রিয়া আছে যা এই ত্রুটিটিকে ট্রিগার করে?
  3. আমি কীভাবে এটিকে প্রতিরোধ করতে পারি?

1
দেখুন কীভাবে আপনি কীভাবে ম্যানিফেস্টে ক্রিয়াকলাপটি বর্ণনা করা হয় এবং ত্রুটি দেখা দিলে স্ক্রিনে কী ক্রিয়াকলাপ হয় তা ব্যাখ্যা করতে পারি কিনা। আপনি যদি নিজের সমস্যাটিকে ন্যূনতম টেস্টকেস থেকে সরিয়ে দিতে পারেন তবে দেখুন।
জোশ লি

ডাকার আগে আপনি নিজের দৃষ্টিভঙ্গি সংশোধন করার চেষ্টা View#onAttachedToWindow()করছেন?
অ্যালেক্স লকউড

উত্তর:


163

আমার এই সমস্যাটি ছিল যেখানে স্ক্রিন ওরিয়েন্টেশন পরিবর্তনে, অ্যাসিঙ্কটাস্কের আগে অগ্রগতি ডায়ালগটি শেষ হয়ে ক্রিয়াকলাপ শেষ হয়েছিল। আমি ডায়ালগটি বাতিল হয়ে যাওয়ার পরে সমাধান করার চেষ্টা করেছি onPause()এবং বরখাস্ত করার আগে এটি AsyncTask এ পরীক্ষা করে দেখলাম।

@Override
public void onPause() {
    super.onPause();

    if ((mDialog != null) && mDialog.isShowing())
        mDialog.dismiss();
    mDialog = null;
}

... আমার অ্যাসিঙ্কটাস্কে:

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
            true);
}

protected void onPostExecute(Object result) {
   if ((mDialog != null) && mDialog.isShowing()) { 
        mDialog.dismiss();
   }
}

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

8

এই সমস্যাটির সাথে লড়াইয়ের পরে অবশেষে আমি এই কর্মসূচীর সাথে শেষ করব:

/**
 * Dismiss {@link ProgressDialog} with check for nullability and SDK version
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissProgressDialog(ProgressDialog dialog) {
    if (dialog != null && dialog.isShowing()) {

            //get the Context object that was used to great the dialog
            Context context = ((ContextWrapper) dialog.getContext()).getBaseContext();

            // if the Context used here was an activity AND it hasn't been finished or destroyed
            // then dismiss it
            if (context instanceof Activity) {

                // Api >=17
                if (!((Activity) context).isFinishing() {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        if (!((Activity) context).isDestroyed()) {
                            dismissWithExceptionHandling(dialog);
                        }
                    } else { 
                        // Api < 17. Unfortunately cannot check for isDestroyed()
                        dismissWithExceptionHandling(dialog);
                    }
                }
            } else
                // if the Context used wasn't an Activity, then dismiss it too
                dismissWithExceptionHandling(dialog);
        }
        dialog = null;
    }
}

/**
 * Dismiss {@link ProgressDialog} with try catch
 *
 * @param dialog instance of {@link ProgressDialog} to dismiss
 */
public void dismissWithExceptionHandling(ProgressDialog dialog) {
    try {
        dialog.dismiss();
    } catch (final IllegalArgumentException e) {
        // Do nothing.
    } catch (final Exception e) {
        // Do nothing.
    } finally {
        dialog = null;
    }
}

কখনও কখনও, এই সমস্যাটির জন্য আরও ভাল সমাধান না হলে ভাল ব্যতিক্রম হ্যান্ডলিং ভাল কাজ করে।


5

যদি আপনার Activityচারপাশে কোনও বস্তু ঝুলন্ত থাকে তবে আপনি এই isDestroyed()পদ্ধতিটি ব্যবহার করতে পারেন :

Activity activity;

// ...

if (!activity.isDestroyed()) {
    // ...
}

AsyncTaskআপনি যদি বিভিন্ন জায়গায় ব্যবহার করেন এমন কোনও অজ্ঞাতনামা সাবক্লাস থাকে তবে এটি দুর্দান্ত।


3

আমি একটি কাস্টম স্ট্যাটিক ক্লাস ব্যবহার করছি যা একটি কথোপকথন তৈরি করে এবং লুকিয়ে রাখে। এই ক্লাসটি কেবলমাত্র একটি অ্যাক্টিভিয়াই নয় অন্যান্য ক্রিয়াকলাপ দ্বারা ব্যবহৃত হচ্ছে। এখন আপনি যে সমস্যাটি বর্ণনা করেছেন তাও আমার কাছে উপস্থিত হয়েছিল এবং আমি সমাধান খুঁজতে রাতারাতি রয়েছি ...

অবশেষে আমি আপনাকে সমাধান উপস্থাপন!

আপনি যদি কোনও ডায়ালগ প্রদর্শন করতে বা খারিজ করতে চান এবং কোন ক্রিয়াকলাপটি স্পর্শ করার জন্য কোন ক্রিয়াকলাপটি ডায়ালগটি শুরু করেছিল তা আপনি জানেন না তবে নীচের কোডটি আপনার জন্য ..

 static class CustomDialog{

     public static void initDialog(){
         ...
         //init code
         ...
     }

      public static void showDialog(){
         ...
         //init code for show dialog
         ...
     }

     /****This is your Dismiss dialog code :D*******/
     public static void dismissProgressDialog(Context context) {                
            //Can't touch other View of other Activiy..
            //http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-android
            if ( (progressdialog != null) && progressdialog.isShowing()) {

                //is it the same context from the caller ?
                Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());

                Class caller_context= context.getClass();
                Activity call_Act = (Activity)context;
                Class progress_context= progressdialog.getContext().getClass();

                Boolean is_act= ( (progressdialog.getContext()) instanceof  Activity )?true:false;
                Boolean is_ctw= ( (progressdialog.getContext()) instanceof  ContextThemeWrapper )?true:false;

                if (is_ctw) {
                    ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
                    Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() ==  call_Act )?true:false;

                    if (is_same_acivity_with_Caller){
                        progressdialog.dismiss();
                        progressdialog = null;
                    }
                    else {
                        Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
                        progressdialog = null;
                    }
                }


            }
        } 

 }

1

উপরের সমাধানটি আমার পক্ষে কার্যকর হয়নি work তাই আমি যা করেছি তা ProgressDialogবিশ্বব্যাপী গ্রহণ করা এবং তারপরে এটি আমার ক্রিয়াকলাপে যুক্ত করা

@Override
    protected void onDestroy() {
        if (progressDialog != null && progressDialog.isShowing())
            progressDialog.dismiss();
        super.onDestroy();
    }

যাতে যদি কার্যকলাপটি ধ্বংস হয়ে যায় তবে প্রগ্রেস ডায়ালগটিও ধ্বংস হয়ে যাবে।


0

প্রশ্নের জন্য 1):

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

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

আপনি লগ.ডি ("আমার অ্যাপ্লিকেশন", "এখানে কিছু তথ্য যা আপনাকে লগ লাইনটি কোথায়" আপনাকে জানিয়ে দেয়) দিয়ে আপনার অ্যাপ্লিকেশনটি পূরণ করতে পারেন, যা পরে এক্সপিসের লগগ্যাট উইন্ডোতে বার্তা পোস্ট করে। যদি আপনি সেই উইন্ডোটি খুঁজে না পান, তবে এটি উইন্ডো দিয়ে খুলুন -> প্রদর্শন প্রদর্শন -> অন্যান্য ... -> অ্যান্ড্রয়েড -> লগগ্যাট।

আশা করি এইটি কাজ করবে!


7
সমস্যাটি ক্লায়েন্টের ফোনে ঘটছে, তাই আমার কাছে ডিবাগ করার কোনও বিকল্প নেই। এছাড়াও ইস্যুটি সর্বদা
ড্যানিয়েল বেনিডিক্ট

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

4
আমি আগেই বলেছি, সমস্যাটি একটি ক্লায়েন্ট ফোনে ঘটছে এবং আমার এতে অ্যাক্সেস নেই। ক্লায়েন্ট অন্য মহাদেশে থাকতে পারে :)
ড্যানিয়েল বেনিডিক্ট

বাজারে এমন অ্যাপস রয়েছে যা আপনাকে তাদের লগক্যাট ইমেল করবে will
টিম গ্রিন

1
ঠিক তাই আপনি জানেন যে আপনি নামপ্যাড কী 9
রব

0

আমি এই ক্রিয়াকলাপের জন্য ম্যানিফেস্টে নিম্নলিখিতগুলি যুক্ত করেছি

android:configChanges="keyboardHidden|orientation|screenLayout"

19
এটি কোনও সমাধান নয়: অন্যান্য কারণেও সিস্টেম আপনার কার্যকলাপকে ধ্বংস করতে পারে destroy
রোল

1
আপনি আপনার উত্তর ব্যাখ্যা করতে পারেন দয়া করে?
লিবিদেভ

0

উইন্ডো ম্যানেজারের কোড অনুসারে ( এখানে লিঙ্ক করুন ) এটি ঘটে যখন আপনি যে ভিউটি আপডেট করার চেষ্টা করছেন (যা সম্ভবত কোনও ডায়ালগের অন্তর্ভুক্ত তবে প্রয়োজনীয় নয়) উইন্ডোজের আসল মূলের সাথে আর সংযুক্ত থাকে না।

অন্যরা যেমন পরামর্শ দিয়েছে, আপনার ডায়লগগুলিতে বিশেষ ক্রিয়াকলাপ সম্পাদনের আগে আপনার ক্রিয়াকলাপের স্থিতি পরীক্ষা করা উচিত।

এখানে রিলেভেন্ট কোড, যা সমস্যার কারণ (অ্যান্ড্রয়েড উত্স কোড থেকে অনুলিপি করা হয়েছে):

public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
    if (!(params instanceof WindowManager.LayoutParams)) {
        throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
    }

    final WindowManager.LayoutParams wparams
            = (WindowManager.LayoutParams)params;

    view.setLayoutParams(wparams);

    synchronized (this) {
        int index = findViewLocked(view, true);
        ViewRootImpl root = mRoots[index];
        mParams[index] = wparams;
        root.setLayoutParams(wparams, false);
    }
}

private int findViewLocked(View view, boolean required) {
        synchronized (this) {
            final int count = mViews != null ? mViews.length : 0;
            for (int i=0; i<count; i++) {
                if (mViews[i] == view) {
                    return i;
                }
            }
            if (required) {
                throw new IllegalArgumentException(
                        "View not attached to window manager");
            }
            return -1;
        }
    }

আমি এখানে কোড লিখেছি গুগল কি করে। আমি যা লিখেছি তা এই সমস্যার কারণ দেখানোর জন্য।
অ্যান্ড্রয়েড বিকাশকারী

0

আমার অ্যান্ড্রয়েড অ্যাপ্লিকেশনটিতে স্ক্রিন রোটেশনটি অহলক করে আমার সমস্যাটি সমাধান করা হয়েছিল যা আমার সমস্যার কারণ হচ্ছিল এখন পুরোপুরি সঠিকভাবে কাজ করে


0

অন্য বিকল্পটি ডায়ালগটিতে অ্যাচাচডটিউ উইন্ডো () এ ওভাররাইড করে উইন্ডোটিতে সংলাপ না হওয়া পর্যন্ত অ্যাসিঙ্ক টাস্কটি শুরু করা নয়, এইভাবে সর্বদা প্রত্যাখ্যানযোগ্য।


0

বা সহজভাবে আপনি যোগ করতে পারেন

protected void onPreExecute() {
    mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}

যা ProgressDialogবাতিল-সক্ষম না করে তোলে


-2

কেন এইরকম ধরার চেষ্টা করবেন না:

protected void onPostExecute(Object result) {
        try {
            if ((mDialog != null) && mDialog.isShowing()) {
                mDialog.dismiss();
            }
        } catch (Exception ex) {
            Log.e(TAG, ex.getMessage(), ex);
        }
    }

অবৈধভাবে আচরণ করার চেয়ে অবৈধ স্টাটঅফ এক্সসেপশনকে আরও ভাল উপায়ে মোকাবেলা করা উচিত।
লাভাকুশ

-3

আপনি যখন ম্যানিফেস্টে ক্রিয়াকলাপটি ঘোষণা করেন তখন আপনার অ্যান্ড্রয়েড দরকার: কনফিগারেশন = "ওরিয়েন্টেশন"

উদাহরণ:

<activity android:theme="@android:style/Theme.Light.NoTitleBar" android:configChanges="orientation"  android:label="traducción" android:name=".PantallaTraductorAppActivity"></activity>

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