activity中的onPause()和onSaveInstanceState()解析

当用户在开启一个新activity时,当前的activity可能在内存中处于停止状态也可能由于新activity需要更多内存而被系统杀掉了,但不论怎样,当用户在新activity上按返回键时,他希望看到的是原先的activity的界面。原先的activity如果是被重新创建,那么它要恢复到用户最后看到它的样子。那么我们怎么做呢?其实也不难,跟据上一节所述,在onPause()或onStop()或onDestyroy()中保存必要的数据就行了。但是现在google又冒出一个新的东西:onSaveInstanceState(),观其名可知其意:它是专门用来保存实例状态的,这个“实例”不是指的activity对象,而是它所在的进程,因为activity的销毁是因为它所在的进程被杀而造成的。onSaveInstanceState()是在系统感觉需要杀死activity时调用的,它被传入一个参数:Bundle,这个Bundle可以被认为是个map,字典之类的东西,用”键-值”来保存数据。

    现在又叫人蛋疼了:不是可以在onPause()中保存数据吗?为什么又搞出这样一个家伙来?它们之间是省木关系呢?原来onSaveInstanceState()的主要目的是保存activity的状态有关的数据,当系统在杀死activity时,如果它希望activity下次出现的样子跟现在完全一样,那么它就调用这个onSaveInstanceState(),否则就不调用。所以要明白这一点:onSaveInstanceState()并不是永远都会调用。比如,当用户在一个activity上按返回时,就不会调用,因为用户此时明确知道这个activity是要被销毁的,并不期望下次它的样子跟现在一样(当然开发者可以使它保持临死时的表情,你非要这样做,系统也没办法),所以就不用调用onSaveInstanceState()。现在应该明白了:在onPause(),onStop()以及onDestroy()中需要保存的是那些需要永久化是数据,而不是保存用于恢复状态的数据,状态数据有专门的方法:onSaveInstanceState()。数据保存在一个Bundle中,Bundle被系统永久化。当再调用activity的onCreate()时,原先保存的bundle就被传入,以恢复上一次临死时的模样,如果上次死时没有保存Bundle,则为null。

      还没完呢,如果你没有实现自己的onSaveInstanceState(),但是activity上控件的样子可能依然能被保存并恢复。原来activity类已实现了onSaveInstanceState(),在onSaveInstanceState()的默认实现中,会调用所有控件的相关方法,把控件们的状态都保存下来,比如EditText中输入的文字,CheckBox是否被选中等等。然而不是所有的控件都能被保存,这取决于你是否在layout文件中为控件赋了一个名字(android:id)。有名的就存,无名的不管。


      既然有现成的可用,那么我们到底还要不要自己实现onSaveInstanceState()?这得看情况了,如果你自己的派生类中有变量影响到UI,或你程序的行为,当然就要把这个变量也保存了,那么就需要自己实现,否则就不需要,但大多数情况肯定需要自己实现一下下了。对了,别忘了在你的实现中调用父类的onSaveInstanceState()。

注:由于onSaveInstanceState()并不是每次销毁时都会调用,所以不要在其中保存那些需要永久化的数据,执行保存那些数据的最好地方是:onPause()中。

    测试你程序的状态恢复能力的最好方法是:旋转屏幕,每当屏幕的方向改变时,当前的activity就会被系统销毁,然后重新创建(应该是进程被关闭!――不会吧?效率不高哦)。


事件检验真理

setttings 改变字体大小后,焦点保留在原来位置不变,代码

/**
 * Copyright (C) 2012 Togic Corporation. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.togic.settings.fragment;

import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.provider.Settings.System.SOUND_EFFECTS_ENABLED;
import static android.provider.Settings.System.TEXT_SHOW_PASSWORD;

import java.io.IOException;

import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.Fragment;
import android.app.WallpaperManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.togic.settings.App;
import com.togic.settings.R;
import com.togic.settings.util.LogUtil;
import com.togic.settings.view.MultiValueItem;
import com.togic.settings.view.OnValueChangeListener;
import com.togic.settings.view.ToggleItem;

/**
 * @author mountains.liu@togic.com @date 2012-11-17
 */
public class DesktopSettings extends Fragment implements OnValueChangeListener {

    private static final long DEFAULT_SCREEN_TIMEOUT = 300;
    private static final int DEFAULT_TOUCH_SOUND = 1;
    private static final int DEFAULT_PWD_VISIBLE = 1;
    private static final int NO_INTEM_FOCUS = 0;

    private static final int TASK_DELAY = 2000;

    private static final int GET_WALLPAPER = 0x0001;
    private static final int CHANGE_WALLPAPER = 0x0002;
    private static final String FOCUS_ITEM = "focusItem";

    private Handler mTaskHandler = new Handler(App.sTaskRunner.getLooper()) {
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case GET_WALLPAPER:
                getWallpaper();
                return;
            case CHANGE_WALLPAPER:
                changeWallpaper(msg.arg1);
                return;
            }
        }
    };
    private Handler mMainHandler = new Handler();

    private Activity mActivity;
    private WallpaperManager mWpMgr;
    private ContentResolver mResolver;
    private Bitmap mSystemWp;
    private boolean mNeedSystemWallpaper = true;
    private AudioManager mAudioMgr;

    private ImageView mPicture;
    private MultiValueItem mWallpaper;
    private MultiValueItem mFontSize;
    private MultiValueItem mSleep;
    private ToggleItem mTouchSound;
    private ToggleItem mPwdVisible;
    private int mFocusItem;
    private View view = null;

    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mActivity = activity;
        mResolver = activity.getContentResolver();
        mWpMgr = WallpaperManager.getInstance(activity);
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle data) {
        view = inflater.inflate(R.layout.frag_desktop, null, false);
        initView(view);
        return view;
    }

    public void onActivityCreated(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mFocusItem = savedInstanceState.getInt(FOCUS_ITEM);
        }
        super.onActivityCreated(savedInstanceState);
    }

    public void onDestroyView() {
        super.onDestroyView();
        recycle();
    }

    public void onResume() {
        if (mFocusItem != NO_INTEM_FOCUS) {
            View v = (View) view.findViewById(mFocusItem);
            v.requestFocus();
        }
        super.onResume();
    }

    public void onDetach() {
        super.onDetach();
        System.gc();
    }

    public void onSaveInstanceState(Bundle outState) {
        mFocusItem = getFocusItem();
        if (mFocusItem != NO_INTEM_FOCUS) {
            outState.putInt(FOCUS_ITEM, mFocusItem);
        }
        super.onSaveInstanceState(outState);
    }

    private int getFocusItem() {
        View v = view.findFocus();
        if (v == null) {
            return NO_INTEM_FOCUS;
        }
        if (mWallpaper.isMyChild(v)) {
            return R.id.desktop_wallpaper;
        } else if (mFontSize.isMyChild(v)) {
            return R.id.desktop_fontsize;
        } else if (mSleep.isMyChild(v)) {
            return R.id.desktop_sleep;
        } else if (mTouchSound.isMyChild(v)) {
            return R.id.desktop_sound;
        } else if (mPwdVisible.isMyChild(v)) {
            return R.id.desktop_password;
        }
        return NO_INTEM_FOCUS;
    }

    private void initView(View view) {
        mPicture = (ImageView) view.findViewById(R.id.desktop_picture);
        mWallpaper = (MultiValueItem) view.findViewById(R.id.desktop_wallpaper);
        mFontSize = (MultiValueItem) view.findViewById(R.id.desktop_fontsize);
        mSleep = (MultiValueItem) view.findViewById(R.id.desktop_sleep);
        mTouchSound = (ToggleItem) view.findViewById(R.id.desktop_sound);
        mPwdVisible = (ToggleItem) view.findViewById(R.id.desktop_password);

        mTaskHandler.sendEmptyMessageDelayed(GET_WALLPAPER, 0);

        final Configuration c = getResources().getConfiguration();
        mFontSize.setCurrentValue(String.valueOf(c.fontScale));

        final long timeOut = Settings.System.getLong(mResolver,
                SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_TIMEOUT);
        mSleep.setCurrentValue(Long.toString(timeOut));

        final int touchSound = Settings.System.getInt(mResolver,
                SOUND_EFFECTS_ENABLED, DEFAULT_TOUCH_SOUND);
        mTouchSound.setCurrentValue(touchSound != 0);

        final int pwdVisible = Settings.System.getInt(mResolver,
                TEXT_SHOW_PASSWORD, DEFAULT_PWD_VISIBLE);
        mPwdVisible.setCurrentValue(pwdVisible != 0);

        mWallpaper.setOnValueChangeListener(this);
        mFontSize.setOnValueChangeListener(this);
        mSleep.setOnValueChangeListener(this);
        mTouchSound.setOnValueChangeListener(this);
        mPwdVisible.setOnValueChangeListener(this);
    }

    private void recycle() {
        mNeedSystemWallpaper = false;
        if (mSystemWp != null) {
            mSystemWp.recycle();
            mSystemWp = null;
        }
    }

    public void onValueChange(View parent, View child, String oldVal,
            String newVal) {
        if (parent == mWallpaper) {
            LogUtil.v("wallpaper changed: " + newVal);
            changeWallpaper(newVal);
        } else if (parent == mFontSize) {
            LogUtil.v("font size changed: " + newVal);
            changeFontSize(newVal);
        } else if (parent == mSleep) {
            LogUtil.v("sleep changed: " + newVal);
            changeScreenTimeout(newVal);
        } else if (parent == mTouchSound) {
            LogUtil.v("touch sound changed: " + newVal);
            changeTouchSound(newVal);
        } else if (parent == mPwdVisible) {
            LogUtil.v("password visible changed: " + newVal);
            changePwdVisible(newVal);
        }
    }

    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LogUtil.v("********** new config: " + newConfig);
        mFontSize.setCurrentValue(String.valueOf(newConfig.fontScale));
    }

    private void changeWallpaper(String newVal) {
        final int id = getWallpaperResourceId(newVal);
        mPicture.setImageResource(id);
        recycle();

        mTaskHandler.removeMessages(CHANGE_WALLPAPER);
        final Message msg = mTaskHandler.obtainMessage(CHANGE_WALLPAPER, id, 0);
        mTaskHandler.sendMessageDelayed(msg, TASK_DELAY);
    }

    private void changeFontSize(String fontSize) {
        try {
            changeFontSize(Float.parseFloat(fontSize));
        } catch (NumberFormatException e) {
            LogUtil.e("could not persist font size setting");
        }
    }

    private void changeFontSize(final float f) {
        mTaskHandler.postDelayed(new Runnable() {
            public void run() {
                try {
                    final Configuration c = getResources().getConfiguration();
                    c.fontScale = f;
                    ActivityManagerNative.getDefault()
                            .updatePersistentConfiguration(c);
                } catch (RemoteException e) {
                    LogUtil.w("Can not save font size changed: " + f);
                } catch (IllegalStateException e) {
                    LogUtil.w("Can not save font size changed: " + f);
                }
            }
        }, 0);
    }

    private void changeScreenTimeout(String timeOut) {
        try {
            changeScreenTimeout(Integer.parseInt(timeOut));
        } catch (NumberFormatException e) {
            LogUtil.e("could not persist screen timeout setting");
        }
    }

    private void changeScreenTimeout(final int val) {
        mTaskHandler.postDelayed(new Runnable() {
            public void run() {
                Settings.System.putLong(mResolver, SCREEN_OFF_TIMEOUT, val);
            }
        }, 0);
    }

    private void changeTouchSound(String touchSound) {
        if (mAudioMgr == null) {
            mAudioMgr = (AudioManager) getActivity().getSystemService(
                    Context.AUDIO_SERVICE);
        }

        if ("0".equals(touchSound)) {
            changeTouchSound(0);
        } else {
            changeTouchSound(1);
        }
    }

    private void changeTouchSound(final int val) {
        mTaskHandler.postDelayed(new Runnable() {
            public void run() {
                if (val == 0) {
                    mAudioMgr.unloadSoundEffects();
                } else {
                    mAudioMgr.loadSoundEffects();
                }
                Settings.System.putInt(mResolver, SOUND_EFFECTS_ENABLED, val);
            }
        }, 0);
    }

    private void changePwdVisible(String pwdVisible) {
        if ("0".equals(pwdVisible)) {
            changePwdVisible(0);
        } else {
            changePwdVisible(1);
        }
    }

    private void changePwdVisible(final int val) {
        mTaskHandler.postDelayed(new Runnable() {
            public void run() {
                Settings.System.putInt(mResolver, TEXT_SHOW_PASSWORD, val);
            }
        }, 0);
    }

    private void getWallpaper() {
        final Bitmap src = mWpMgr.getBitmap();
        if (src == null) {
            return;
        }

        // NOTE: scale src bitmap.
        final Bitmap b = Bitmap.createScaledBitmap(src, 150, 100, true);
        mMainHandler.postDelayed(new Runnable() {
            public void run() {
                if (b == null) {
                    return;
                } else if (mNeedSystemWallpaper) {
                    mSystemWp = b;
                    mPicture.setImageBitmap(b);
                } else {
                    b.recycle();
                }

                // FIXME: why can't recycle src bitmap immediately after
                // create scaled bitmap.
                // if (src != null) {
                // src.recycle();
                // }
                System.gc();
            }
        }, 0);
    }

    private int getWallpaperResourceId(String newVal) {
        if ("wallpaper_1".equals(newVal)) {
            return R.drawable.bg_main;
        } else {
            return R.drawable.bg_main2;
        }
    }

    private void changeWallpaper(int id) {
        try {
            mWpMgr.setResource(id);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值