Crash when rotating Activity using ViewFlipper

懵懂的女人 提交于 2019-12-22 01:31:31

问题


I originally had two ListActivity classes.

I'm experimenting with having 1 Activity and, using a ViewFlipper, flipping between the two lists.

It seems to be working great except for one problem. If I rotate the emulator, I'll randomly get a crash. It doesn't happen every time and I can't figure out a specific workflow to trigger it. This is the error:

01-12 16:28:58.292: WARN/dalvikvm(877): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
01-12 16:28:58.292: ERROR/AndroidRuntime(877): Uncaught handler: thread main exiting due to uncaught exception
01-12 16:28:58.312: ERROR/AndroidRuntime(877): java.lang.IllegalArgumentException: Receiver not registered: android.widget.ViewFlipper$1@43d44458
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread$PackageInfo.forgetReceiverDispatcher(ActivityThread.java:667)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ApplicationContext.unregisterReceiver(ApplicationContext.java:747)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:321)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.widget.ViewFlipper.onDetachedFromWindow(ViewFlipper.java:104)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.View.dispatchDetachedFromWindow(View.java:5835)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1076)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1074)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1074)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewRoot.dispatchDetachedFromWindow(ViewRoot.java:1570)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewRoot.doDie(ViewRoot.java:2556)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.ViewRoot.die(ViewRoot.java:2526)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:218)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.view.Window$LocalWindowManager.removeViewImmediate(Window.java:436)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3498)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3599)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread.access$2300(ActivityThread.java:119)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1867)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.os.Handler.dispatchMessage(Handler.java:99)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.os.Looper.loop(Looper.java:123)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at android.app.ActivityThread.main(ActivityThread.java:4363)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at java.lang.reflect.Method.invokeNative(Native Method)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at java.lang.reflect.Method.invoke(Method.java:521)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
01-12 16:28:58.312: ERROR/AndroidRuntime(877):     at dalvik.system.NativeStart.main(Native Method)

Does anyone have any ideas as to what might be the problem?

Here is a basic skeleton of my Activity:

public class ActivityFlipper extends Activity implements OnItemClickListener, OnClickListener {

    ViewFlipper flipper;

    // query tokens
    final int LIST1_MY_QUERY_TOKEN = 42;
    final int LIST2_MY_QUERY_TOKEN = 43;

    // vars for list1 screen
    private List1Adapter mList1Adapter = null;
    private Cursor mList1Cursor = null;
    List1QueryHandler mList1QueryHandler;

    // vars for list2 screen
    private List2Adapter mList2Adapter = null;
    private Cursor mList2Cursor = null;
    List2QueryHandler mList2QueryHandler;


    // ui controls for list1 screen
    private ListView mList1;
    private Button mAdd;
    private TextView mList1Header;

    // ui controls for list2 screen
    private ListView mList2;
    private TextView mList2Header;
    private Button mSelector;

    // ui controls common
    private ProgressDialog mScannerProgress;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.layout_flipper);

        // set up flipper screen

        flipper = (ViewFlipper) findViewById(R.id.flipper);




        // set up list1 screen

        mList1 = (ListView)findViewById(R.id.list1_list);
        mList1.setOnItemClickListener(this);

        mAdd = (Button)findViewById(R.id.list1_add);
        mAdd.setOnClickListener(this);

        mList1Header = (TextView)findViewById(R.id.list1_header);
        mList1Header.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                flipper.setInAnimation(inFromRightAnimation());
                 flipper.setOutAnimation(outToLeftAnimation());
                 flipper.showNext(); 
            }
        });

        setList1Adapter();

        mList1QueryHandler = new List1QueryHandler(this);

        registerForContextMenu(mList1);
        registerForContextMenu(mAdd);




        // set up list2 screen

        mList2 = (ListView)findViewById(R.id.list2_list);

        mList2Header = (TextView)findViewById(R.id.list2_header);
        mList2Header.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                flipper.setInAnimation(inFromLeftAnimation());
                 flipper.setOutAnimation(outToRightAnimation());
                 flipper.showPrevious(); 
            }
        });

        mSelector = (Button)findViewById(R.id.list2_changestore);
        mSelector.setOnClickListener(this);

        setList2Adapter();

        mList2QueryHandler = new List2pingQueryHandler(this);

        registerForContextMenu(mList2);
    }

    private void setList1Adapter() {
        mList1Adapter = new List1Adapter(ActivityList1.this, null);
        mList1.setAdapter(mList1Adapter);
    }

    private void setList2Adapter() {
        mList2Adapter = new List2Adapter(ActivityList1.this, null);
        mList2.setAdapter(mList2Adapter);
    }

    @Override
    protected void onPause() {
        // remove broadcast listener
        unregisterReceiver(onBroadcast);

        super.onPause();
    }

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

        // add broadcast listener
        registerReceiver(onBroadcast, new IntentFilter("listquery"));

        // get rid of scanner progress if showing
        if (mScannerProgress != null && mScannerProgress.isShowing()) {
            mScannerProgress.dismiss();
        }

        // get data to populate lists
        doList1Query(false);
        doList2Query(false);

    }

    public void onItemClick(AdapterView<?> l, View v, int position, long id) {
        if (v.getId() == mList1.getId()) {
            // do stuff
        }
        else if (v.getId() == mList2.getId()) {
            // do stuff
        }
    }

    public void onClick(View v) {
        if (v.getId() == R.id.list1_add) {
            // do stuff
        }
        else if (v.getId() == R.id.list2_changestore) {
            // do stuff
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // do stuff
    }

    Cursor doList1Query(boolean sync) {
        // Cancel any pending queries
        mList1QueryHandler.cancelOperation(LIST1_MY_QUERY_TOKEN);

        if (sync) {
            try {
                return getContentResolver().query(uri,
                                        columns,
                                        where,
                                        null,
                                        order);
            }
            catch (UnsupportedOperationException ex) {
            }
        }
        else {
            setProgressBarIndeterminateVisibility(true);
            mList1QueryHandler.startQuery(LIST1_MY_QUERY_TOKEN,
                                        null,
                                        uri,
                                        columns,
                                        where,
                                        null,
                                        order);
        }
        return null;
    }

    Cursor doList2Query(boolean sync) {

        mList2QueryHandler.cancelOperation(LIST2_MY_QUERY_TOKEN);

        if (sync) {
            try {
                return getContentResolver().query(uri,
                                        getDisplayColumns(),
                                        where,
                                        null,
                                        order);
            }
            catch (UnsupportedOperationException ex) {
            }
        }
        else {
            setProgressBarIndeterminateVisibility(true);
            mList2QueryHandler.startQuery(LIST2_MY_QUERY_TOKEN,
                                        null,
                                        uri,
                                        columns,
                                        where,
                                        null,
                                        order);
        }
        return null;
    }


    private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctxt, Intent i) {
            doList1Query(false);
            doList2Query(false);
        }
    };




    private Animation inFromRightAnimation() {
        Animation inFromRight = new TranslateAnimation(
                Animation.RELATIVE_TO_PARENT,  +1.0f, Animation.RELATIVE_TO_PARENT,  0.0f,
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,   0.0f
                );

        inFromRight.setDuration(500);
        inFromRight.setInterpolator(new AccelerateInterpolator());

        return inFromRight;
    }

    private Animation outToLeftAnimation() {
        Animation outtoLeft = new TranslateAnimation(
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  -1.0f,
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,   0.0f
                );

        outtoLeft.setDuration(500);
        outtoLeft.setInterpolator(new AccelerateInterpolator());

        return outtoLeft;
    }

    private Animation inFromLeftAnimation() {
        Animation inFromLeft = new TranslateAnimation(
                Animation.RELATIVE_TO_PARENT,  -1.0f, Animation.RELATIVE_TO_PARENT,  0.0f,
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,   0.0f
                );

        inFromLeft.setDuration(500);
        inFromLeft.setInterpolator(new AccelerateInterpolator());

        return inFromLeft;
    }

    private Animation outToRightAnimation() {
        Animation outtoRight = new TranslateAnimation(
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,  +1.0f,
                Animation.RELATIVE_TO_PARENT,  0.0f, Animation.RELATIVE_TO_PARENT,   0.0f
                );

        outtoRight.setDuration(500);
        outtoRight.setInterpolator(new AccelerateInterpolator());

        return outtoRight;
    }
}

回答1:


Indeed this is a bug in the bowels of Android. You can work around it by using a "SafeViewFlipper" instead:

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ViewFlipper;

public class SafeViewFlipper extends ViewFlipper {


    public SafeViewFlipper(Context context) {
        super(context);
    }

    public SafeViewFlipper(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onDetachedFromWindow() {
        try {
            super.onDetachedFromWindow();
        }
        catch (IllegalArgumentException e) {
            // This happens when you're rotating and opening the keyboard that the same time
            // Possibly other rotation related scenarios as well
            stopFlipping();
        }
    }
}


来源:https://stackoverflow.com/questions/4674796/crash-when-rotating-activity-using-viewflipper

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!