zoukankan      html  css  js  c++  java
  • StrictMode对SharedPreferences的检查出来的IO操作

    在使用StrictMode时,发现会爆出

    StrictMode policy violation;~duration=1949 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=23 violation=2

     这个提示显示, 在UI线程中有IO操作,请这是尽量避免。

    但是我们真的在UI线程中使用了吗?其实我们也是按照普通大众的方法调用的。 直接在UI线程中调用getSharedPreference方法,该方法可能就会产生IO操作。

    跟着查一下源码吧.

    在2.3版本中有这样的代码:

     @Override
        public SharedPreferences getSharedPreferences(String name, int mode) {
            SharedPreferencesImpl sp;
            File f = getSharedPrefsFile(name);
            synchronized (sSharedPrefs) {
                sp = sSharedPrefs.get(f);
                if (sp != null && !sp.hasFileChanged()) {
                    //Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
                    return sp;
                }
            }
            
            FileInputStream str = null;
            File backup = makeBackupFile(f);
            if (backup.exists()) {
                f.delete();
                backup.renameTo(f);
            }
    
            // Debugging
            if (f.exists() && !f.canRead()) {
                Log.w(TAG, "Attempt to read preferences file " + f + " without permission");
            }
            
            Map map = null;
            if (f.exists() && f.canRead()) {
                try {
                    str = new FileInputStream(f);
                    map = XmlUtils.readMapXml(str);
                    str.close();
                } catch (org.xmlpull.v1.XmlPullParserException e) {
                    Log.w(TAG, "getSharedPreferences", e);
                } catch (FileNotFoundException e) {
                    Log.w(TAG, "getSharedPreferences", e);
                } catch (IOException e) {
                    Log.w(TAG, "getSharedPreferences", e);
                }
            }
    
            synchronized (sSharedPrefs) {
                if (sp != null) {
                    //Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
                    sp.replace(map);
                } else {
                    sp = sSharedPrefs.get(f);
                    if (sp == null) {
                        sp = new SharedPreferencesImpl(f, mode, map);
                        sSharedPrefs.put(f, sp);
                    }
                }
                return sp;
            }
        }

    看发生了xml的读写操作, 怪不得会有IO操作。

    但是再4.0版本此处代码发生了变化。

     @Override
        public SharedPreferences getSharedPreferences(String name, int mode) {
            SharedPreferencesImpl sp;
            synchronized (ContextImpl.class) {
                if (sSharedPrefs == null) {
                    sSharedPrefs = new ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>>();
                }
    
                final String packageName = getPackageName();
                ArrayMap<String, SharedPreferencesImpl> packagePrefs = sSharedPrefs.get(packageName);
                if (packagePrefs == null) {
                    packagePrefs = new ArrayMap<String, SharedPreferencesImpl>();
                    sSharedPrefs.put(packageName, packagePrefs);
                }
    
                // At least one application in the world actually passes in a null
                // name.  This happened to work because when we generated the file name
                // we would stringify it to "null.xml".  Nice.
                if (mPackageInfo.getApplicationInfo().targetSdkVersion <
                        Build.VERSION_CODES.KITKAT) {
                    if (name == null) {
                        name = "null";
                    }
                }
    
                sp = packagePrefs.get(name);
                if (sp == null) {
                    File prefsFile = getSharedPrefsFile(name);
                    sp = new SharedPreferencesImpl(prefsFile, mode);
                    packagePrefs.put(name, sp);
                    return sp;
                }
            }
            if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
                getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
                // If somebody else (some other process) changed the prefs
                // file behind our back, we reload it.  This has been the
                // historical (if undocumented) behavior.
                sp.startReloadIfChangedUnexpectedly();
            }
            return sp;
        }

    看代码,这里没看到XML的IO操作。 那这个IO跑哪里去了呢? 跟踪一下SharedPreferencesImpl的构造方法,

        SharedPreferencesImpl(File file, int mode) {
            mFile = file;
            mBackupFile = makeBackupFile(file);
            mMode = mode;
            mLoaded = false;
            mMap = null;
            startLoadFromDisk();
        }
    
        private void startLoadFromDisk() {
            synchronized (this) {
                mLoaded = false;
            }
            new Thread("SharedPreferencesImpl-load") {
                public void run() {
                    synchronized (SharedPreferencesImpl.this) {
                        loadFromDiskLocked();
                    }
                }
            }.start();
        }

    你看, XML的读取确实启动新线程了,那为什么还要爆出IO操作呢?   重新跟踪堆栈,发现原来不是这段代码发生的IO操作,是在startReloadIfChangedUnexpectedly中发生的, 代码中有些, 处于多进程模式,或者targe版本较低版本都会走该方法。那该方法中就会有IO操作。

    后面, 我又更改了targetAPI的版本,不会走到startReloadIfChangedUnexpectedly中去。 果然StrictMode不会再查出东西来了。

  • 相关阅读:
    HPU 1007: 严格递增连续子段(贪心)
    Codeforces Round #224 (Div. 2) A. Ksenia and Pan Scales
    Codeforces Round #224 (Div. 2) A. Ksenia and Pan Scales
    51Nod 1058: N的阶乘的长度(斯特林公式)
    51Nod 1090: 3个数和为0
    CSU 1112: 机器人的指令
    有关刷题时的多组输入问题
    HDU 1060:Leftmost Digit
    《算法导论》— Chapter 6 堆排序
    《算法导论》— Chapter 9 中位数和顺序统计学
  • 原文地址:https://www.cnblogs.com/xitang/p/3560634.html
Copyright © 2011-2022 走看看