Activity嵌套Fragment应用放置后台很久,被系统回收,出现crash

 由于使用了主界面的 东西比较多  占用内存比较大,在程序进入后台后,长时间不操作被系统回收 ,再次 进入程序后导致程序崩溃。错误日志:
Parcel android.os.Parcel@42209460: Unmarshalling unknown type code
 2131165303 at offset 3748
         at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2080)
         at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2105)
         at android.app.ActivityThread.access$600(ActivityThread.java:136)
         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1201)
         at android.os.Handler.dispatchMessage(Handler.java:99)
         at android.os.Looper.loop(Looper.java:137)
         at android.app.ActivityThread.main(ActivityThread.java:4876)
         at java.lang.reflect.Method.invokeNative(Native Method)
         at java.lang.reflect.Method.invoke(Method.java:511)
         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:804)
         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:571)
         at com.kdgdev.xtension.core.XtensionMain.main(XtensionMain.java:91)
         at dalvik.system.NativeStart.main(Native Method)
看日志是应用程序崩溃恢复解打包的偏移导致异常。

定位至报错位置
FragmentActivity的super.onCreate(savedInstanceState);恢复现场时报错
我们查看报错的FragmentActivity的源码:
FragmentActivity
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
Parcelable p = this.mFragments.saveAllState();
if (p != null)
outState.putParcelable("android:support:fragments", p);
}
static final String FRAGMENTS_TAG = "android:support:fragments";
/**
     * Perform initialization of all fragments and loaders.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mFragments.attachActivity(this, mContainer, null);
        // Old versions of the platform didn't do this!
        if (getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }
        
        super.onCreate(savedInstanceState);
        
        NonConfigurationInstances nc = (NonConfigurationInstances)
                getLastNonConfigurationInstance();
        if (nc != null) {
            mAllLoaderManagers = nc.loaders;
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        mFragments.dispatchCreate();
    }

崩溃时做了保存View状态的处理,崩溃恢复后解包getParcelable(FRAGMENTS_TAG) 恢复View状态发生移位错误(某种异常情况下,如对象不是Parcelable、 writeToParcel和createFromParcel无对应等 )

多方定位发现是AutoScrollTextView 的实现由问题,导致崩溃时View状态保存有误:
查看报错位置:

public class AutoScrollTextView extends TextView implements OnClickListener {
    public final static String TAG = AutoScrollTextView.class.getSimpleName();
   
    private float textLength = 0f;//文本长度
    private float viewWidth = 0f;
    private float step = 0f;//文字的横坐标
    private float y = 0f;//文字的纵坐标
    private float temp_view_plus_text_length = 0.0f;//用于计算的临时变量
    private float temp_view_plus_two_text_length = 0.0f;//用于计算的临时变量
    public boolean isStarting = false;//是否开始滚动
    private Paint paint = null;//绘图样式
    private String text = "";//文本内容
   
    public AutoScrollTextView(Context context) {
        super(context);
        initView();
    }
    public AutoScrollTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }
    public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }
   
   
    private void initView()
    {
        setOnClickListener(this);
    }
   
   
    public void init(WindowManager windowManager)
    {
        paint = getPaint();
        text = getText().toString();
        textLength = paint.measureText(text);
        viewWidth = getWidth();
        if(viewWidth == 0)
        {
            if(windowManager != null)
            {
                Display display = windowManager.getDefaultDisplay();
                viewWidth = display.getWidth();
            }
        }
        step = textLength;
        temp_view_plus_text_length = viewWidth + textLength;
        temp_view_plus_two_text_length = viewWidth + textLength * 2;
        y = getTextSize() + getPaddingTop();
    }
   
    @Override
    public Parcelable onSaveInstanceState()
    {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
       
        ss.step = step;
        ss.isStarting = isStarting;
       
        return ss;
       
    }
   
    @Override
    public void onRestoreInstanceState(Parcelable state)
    {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }
        SavedState ss = (SavedState)state;
        super.onRestoreInstanceState(ss.getSuperState());
       
        step = ss.step;
        isStarting = ss.isStarting;
    }
   
    public static class SavedState extends BaseSavedState {
        public boolean isStarting = false;
        public float step = 0.0f;
        SavedState(Parcelable superState) {
            super(superState);
        }
        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeBooleanArray(new boolean[]{isStarting});
            out.writeFloat(step);
        }

        public static final Parcelable.Creator CREATOR
                = new Parcelable.Creator() {
           
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }
        };
        private SavedState(Parcel in) {
            super(in);
            boolean[] b = null;
            in.readBooleanArray(b);
            if(b != null && b.length > 0)
                isStarting = b[0];
            step = in.readFloat();
        }
    }
   
    public void startScroll()
    {
        isStarting = true;
        invalidate();
    }
   
   
    public void stopScroll()
    {
        isStarting = false;
        invalidate();
    }
   
    @Override
    public void onDraw(Canvas canvas) {
        canvas.drawText(text, temp_view_plus_text_length - step, y, paint);
        if(!isStarting)
        {
            return;
        }
        step += 0.5;//0.5为文字滚动速度。
        if(step > temp_view_plus_two_text_length)
            step = textLength;
        invalidate();
    }
    @Override
    public void onClick(View v) {
        if(isStarting)
            stopScroll();
        else
            startScroll();
       
    }
}

跑马灯中重写TextView中自定义实现SavedState导致的解包异常,注释掉SavedState的实现即恢复正常。大部分应用都是这样,销毁了进来重新create了,所以你要把报错的地方判断一下就好了,因此另一种解决办法就是在FragmentActivity的onCreate做判断:

if (savedInstanceState != null) {
     savedInstanceState.putParcelable("android:support:fragments", null);
}
super.onCreate(savedInstanceState);
 
   如果是Activity,则改成如下: 
  
if (savedInstanceState != null) {
     savedInstanceState.putParcelable("android:fragments", null);
}
super.onCreate(savedInstanceState);



你可能感兴趣的:(Android之问题集)