Giter VIP home page Giter VIP logo

androidbox's Introduction

AndroidBox

Java、Android开发知识、经验、资料等总结,作为个人的Android开发知识体系。

About Me

Android开发实战经验总结

为什么我写的程序有Bug

  • 为什么我写的程序有Bug(一):概述篇
  • 为什么我写的程序有Bug(二):系统篇
  • 为什么我写的程序有Bug(三):网络篇
  • 为什么我写的程序有Bug(四):逻辑篇
  • 为什么我写的程序有Bug(五):性能篇
  • 为什么我写的程序有Bug(六):工具篇
  • 为什么我写的程序有Bug(七):技巧篇

App开发知识必备

浅析Android系统

解密im推送sdk开发

  • 解密im推送sdk开发(一):架构篇
  • 解密im推送sdk开发(二):协议篇
  • 解密im推送sdk开发(三):保活篇
  • 解密im推送sdk开发(四):心跳篇
  • 解密im推送sdk开发(五):宿主篇
  • 解密im推送sdk开发(六):测试篇
  • 解密im推送sdk开发(七):经验篇

秒懂设计模式

略懂Java编程

简述JVM基础

AndroidStudio

更新日志

  • 知识结构初版完成 2016-10-16
  • 调整结构 2017-08-19

androidbox's People

Contributors

zengjingfang avatar opendevteam avatar

Stargazers

 avatar Wakeyoo avatar  avatar  avatar  avatar  avatar  avatar Noah avatar sonaive avatar  avatar  avatar Yoo Zhou avatar XingjieZheng avatar Yumeng0628 avatar  avatar  avatar

Watchers

James Cloos avatar  avatar  avatar  avatar

androidbox's Issues

SQLite异常整理

android.database.sqlite.SQLiteDiskIOException: disk I/O error - SQLITE_IOERR_WRITE (Sqlite code 778), (OS error - 9:Bad file descriptor)
at android.database.sqlite.SQLiteConnection.nativeExecute(Native Method)
at android.database.sqlite.SQLiteConnection.execute(SQLiteConnection.java:563)
at android.database.sqlite.SQLiteSession.endTransactionUnchecked(SQLiteSession.java:437)
at android.database.sqlite.SQLiteSession.endTransaction(SQLiteSession.java:401)
at android.database.sqlite.SQLiteDatabase.endTransaction(SQLiteDatabase.java:541)
at com.xtc.im.core.push.store.dao.ServerConfigDao.update(Unknown Source)
at com.xtc.im.core.push.domain.DomainManager.updateOnConnectSuccess(Unknown Source)
at com.xtc.im.core.push.PushService$1$1.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:743)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:150)
at android.os.HandlerThread.run(HandlerThread.java:61)

Neither user 10421 nor current process has android.permission.ACCESS_COARSE_LOCATION.

 Process: com.xxx.xxx.xxx:push, PID: 5783
 java.lang.SecurityException: Neither user 10421 nor current process has android.permission.ACCESS_COARSE_LOCATION.
     at android.os.Parcel.readException(Parcel.java:1546)
     at android.os.Parcel.readException(Parcel.java:1499)
     at com.android.internal.telephony.ITelephony$Stub$Proxy.getAllCellInfoUsingSubId(ITelephony.java:2923)
     at android.telephony.TelephonyManager.getAllCellInfo(TelephonyManager.java:2729)
     at android.telephony.TelephonyManager.getAllCellInfo(TelephonyManager.java:2723)
     at com.xxx.im.core.common.utils.SIMUtil.getMobileDbm(Unknown Source)
     at com.xxx.im.core.common.utils.SIMUtil.isSignalStrong(Unknown Source)
/**
     * 获取手机信号强度,需添加权限 android.permission.ACCESS_COARSE_LOCATION <br>
     * API要求不低于17 <br>
     *
     * @return 当前手机主卡信号强度, 单位 dBm(-1是默认值,表示获取失败)
     */
    private static int getMobileDbm(Context context) {

        int dbm = -1;
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        List<CellInfo> cellInfoList;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            cellInfoList = tm.getAllCellInfo();
            if (null != cellInfoList) {
                for (CellInfo cellInfo : cellInfoList) {
                    if (cellInfo instanceof CellInfoGsm) {//移动
                        CellSignalStrengthGsm cellSignalStrengthGsm = ((CellInfoGsm) cellInfo).getCellSignalStrength();
                        dbm = cellSignalStrengthGsm.getDbm();
                    } else if (cellInfo instanceof CellInfoCdma) {//电信
                        CellSignalStrengthCdma cellSignalStrengthCdma = ((CellInfoCdma) cellInfo).getCellSignalStrength();
                        dbm = cellSignalStrengthCdma.getDbm();
                    } else if (cellInfo instanceof CellInfoWcdma) {//联通
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                            CellSignalStrengthWcdma cellSignalStrengthWcdma = ((CellInfoWcdma) cellInfo).getCellSignalStrength();
                            dbm = cellSignalStrengthWcdma.getDbm();
                        }
                    } else if (cellInfo instanceof CellInfoLte) {//移动
                        CellSignalStrengthLte cellSignalStrengthLte = ((CellInfoLte) cellInfo).getCellSignalStrength();
                        dbm = cellSignalStrengthLte.getDbm();
                    }
                }
            }
        }
        LogUtil.d(TAG,"mobile dbm: "+dbm);
        return dbm;
    }

增加了权限,还是报权限问题。为什么???

java.lang.IllegalStateException: The specified child already has a parent.

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xtc.watch/com.xtc.watch.view.home.activity.XtcHomeActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2200)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2249)
	at android.app.ActivityThread.access$800(ActivityThread.java:141)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1212)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loop(Looper.java:136)
	at android.app.ActivityThread.main(ActivityThread.java:5113)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:515)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612)
	at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
	at android.view.ViewGroup.addViewInner(ViewGroup.java:3564)
	at android.view.ViewGroup.addView(ViewGroup.java:3417)
	at android.view.ViewGroup.addView(ViewGroup.java:3362)
	at android.view.ViewGroup.addView(ViewGroup.java:3338)
	at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1434)
	at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
	at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
	at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
	at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:3200)
	at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:195)
	at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:597)
	at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
	at android.app.Activity.performStart(Activity.java:5252)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2173)
	... 11 more

IM即时通讯SDK网络问题集合

1、 java.net.SocketException: sendto failed: EBADF (Bad file descriptor)

java.net.SocketException: sendto failed: EBADF (Bad file descriptor)
	at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:542)
	at libcore.io.IoBridge.sendto(IoBridge.java:511)
	at java.net.PlainSocketImpl.write(PlainSocketImpl.java:500)

Native闪退

06-21 10:36:51.901 18665-18945/com.xtc.watch A/libc: heap corruption detected by dlmalloc_real
06-21 10:36:51.901 18665-18945/com.xtc.watch A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 18945 (Thread-3956)
06-21 10:36:53.581 1241-18958/? E/test: key length=16
06-21 10:36:53.591 1241-18958/? E/test: decodePrivate 22
06-21 10:36:54.051 875-1143/? E/NativeCrashListener: Exception dealing with report
                                                     android.system.ErrnoException: read failed: EAGAIN (Try again)
                                                         at libcore.io.Posix.readBytes(Native Method)
                                                         at libcore.io.Posix.read(Posix.java:165)
                                                         at libcore.io.BlockGuardOs.read(BlockGuardOs.java:230)
                                                         at android.system.Os.read(Os.java:350)
                                                         at com.android.server.am.NativeCrashListener.consumeNativeCrashData(NativeCrashListener.java:240)
                                                         at com.android.server.am.NativeCrashListener.run(NativeCrashListener.java:138)

Android8.0系统:.RemoteServiceException: Bad notification for startForeground

问题:启动push进程失败

启动的时候发现push进程起来了,但是立即弹出“停止运行”,查看Log有如下异常:

Process: com.xtc.watch:push, PID: 12789
android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=null pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 vis=PRIVATE)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

点击确认,发现Push进程已挂,随后Log出现如下异常:

java.lang.IllegalStateException: Not allowed to start service Intent { act=com.xtc.im.core.push.PushService flg=0x20 pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.push.PushService (has extras) }:
app is in background uid UidRecord{1922d78 u0a169 SVC idle change:idle|uncached procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
at android.app.ContextImpl.startService(ContextImpl.java:1477)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at com.xtc.im.core.app.bridge.PushServiceManager.init(PushServiceManager.java:104)
at com.xtc.im.core.app.IMCore$16.run(IMCore.java:903)
at java.lang.Thread.run(Thread.java:764)

Android 8.0:Not allowed to start service Intent

问题:Android 8.0 系统启动service失败

java.lang.IllegalStateException: Not allowed to start service Intent { act=com.xtc.im.core.push.PushService flg=0x20 pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.push.PushService (has extras) }:
app is in background uid UidRecord{1922d78 u0a169 SVC idle change:idle|uncached procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1521)
at android.app.ContextImpl.startService(ContextImpl.java:1477)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at com.xtc.im.core.app.bridge.PushServiceManager.init(PushServiceManager.java:104)
at com.xtc.im.core.app.IMCore$16.run(IMCore.java:903)
at java.lang.Thread.run(Thread.java:764)

.EventBus.register异常: Didn't find class "android.os.PersistableBundle"

java.lang.NoClassDefFoundError: android/os/PersistableBundle
	at java.lang.Class.getDeclaredMethods(Native Method)
	at java.lang.Class.getPublicMethodsRecursive(Class.java:894)
	at java.lang.Class.getMethods(Class.java:877)
	at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingReflectionInSingleClass(SubscriberMethodFinder.java:157)
	at org.greenrobot.eventbus.SubscriberMethodFinder.findUsingInfo(SubscriberMethodFinder.java:88)
	at org.greenrobot.eventbus.SubscriberMethodFinder.findSubscriberMethods(SubscriberMethodFinder.java:64)
	at org.greenrobot.eventbus.EventBus.register(EventBus.java:136)
	at com.xtc.watch.view.location.view.impl.LocationMainActivity.onCreate(LocationMainActivity.java:300)
	at android.app.Activity.performCreate(Activity.java:5355)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1089)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2171)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2257)
	at android.app.ActivityThread.access$800(ActivityThread.java:140)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1202)
	at android.os.Handler.dispatchMessage(Handler.java:102)
	at android.os.Looper.loop(Looper.java:136)
	at android.app.ActivityThread.main(ActivityThread.java:5113)
	at java.lang.reflect.Method.invokeNative(Native Method)
	at java.lang.reflect.Method.invoke(Method.java:515)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:780)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:596)
	at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.os.PersistableBundle" on path: DexPathList[[zip file "/data/app/com.xtc.watch-1.apk", zip file "/data/data/com.xtc.watch/code_cache/secondary-dexes/com.xtc.watch-1.apk.classes2.zip", zip file "/data/data/com.xtc.watch/code_cache/secondary-dexes/com.xtc.watch-1.apk.classes3.zip", zip file "/data/data/com.xtc.watch/code_cache/secondary-dexes/com.xtc.watch-1.apk.classes4.zip"],nativeLibraryDirectories=[/data/app-lib/com.xtc.watch-1, /vendor/lib, /system/lib]]
	at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
	... 22 more

代码

  @override
  public void onSaveInstanceState(Bundle outState) {
       super.onSaveInstanceState(outState);
      EventBus.getDefault().register(MainActivity.this);
  }
    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        LogUtil.i(TAG, "xxx onSaveInstanceState...");
    }

SQLite查询操作源码分析:从 IllegalArgumentException:the bind value at index 2 is null 说起

一、问题现象以及结论

1、问题现象

做数据库查询操作时,报了异常 IllegalArgumentException:the bind value at index 2 is null。

2、异常代码片段

cursor = db.query("table_account", null,“account_name” + "=? and "+"account_tel"+ "=? and "+"account_sex"+"=?",new String[]{entity.getName(),entity.getTel(),String.valueOf(entity.getSex())}, null, null, null);

3、问题原因

传入的entity.getTel() 为null了,SQLite内部抛出 IllegalArgumentException ,查询任务终止。

二、详细分析

1、异常出处代码片段

发现直接从db.query方法往下追有点麻烦,分支比较多,所以直接找到异常出处的代码,然后倒追回来。如果不习惯,也可以从后往前看。
IllegalArgumentException("the bind value at index " + index + " is null")。

SQLiteProgram.java[1.1]

    /**
     * Bind a String value to this statement. The value remains bound until
     * {@link #clearBindings} is called.
     *
     * @param index The 1-based index to the parameter to bind
     * @param value The value to bind, must not be null
     */
    public void bindString(int index, String value) {
        if (value == null) {
            throw new IllegalArgumentException("the bind value at index " + index + " is null");
        }
        bind(index, value);
    }

2、代码追踪

### SQLiteProgram.java[1.2]

    /**
     * Given an array of String bindArgs, this method binds all of them in one single call.
     *
     * @param bindArgs the String array of bind args, none of which must be null.
     */
    public void bindAllArgsAsStrings(String[] bindArgs) {
        if (bindArgs != null) {
            for (int i = bindArgs.length; i != 0; i--) {
			bindString(i, bindArgs[i - 1]);//调用[1.1]
            }
        }
    }

SQLiteDirectCursorDriver.java[2.1]

public Cursor query(CursorFactory factory, String[] selectionArgs) {
        final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
        final Cursor cursor;
        try {
            query.bindAllArgsAsStrings(selectionArgs);//调用[1.2]

            if (factory == null) {
                cursor = new SQLiteCursor(this, mEditTable, query);// 这里应该是用了 default factory 
            } else {
                cursor = factory.newCursor(mDatabase, this, mEditTable, query);
            }
        } catch (RuntimeException ex) {
            query.close();
            throw ex;
        }

        mQuery = query;
        return cursor;
    }

SQLiteDatabase.java[3.1]

    /**
     * Runs the provided SQL and returns a cursor over the result set.
     *
     * @param cursorFactory the cursor factory to use, or null for the default factory
     */
    public Cursor rawQueryWithFactory(
            CursorFactory cursorFactory, String sql, String[] selectionArgs,
            String editTable, CancellationSignal cancellationSignal) {
        acquireReference();
        try {
            SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
                    cancellationSignal);
					//cursorFactory传入为null则用mCursorFactory
            return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
                    selectionArgs);//调用[2.1]
        } finally {
            releaseReference();
        }
    }

SQLiteDatabase.java[3.2]

 /**
     * Query the given URL, returning a {@link Cursor} over the result set.
     *
     * @param cursorFactory the cursor factory to use, or null for the default factory
     * @param distinct true if you want each row to be unique, false otherwise.
     */
    public Cursor queryWithFactory(CursorFactory cursorFactory,
            boolean distinct, String table, String[] columns,
            String selection, String[] selectionArgs, String groupBy,
            String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
        acquireReference();
        try {
            String sql = SQLiteQueryBuilder.buildQueryString(
                    distinct, table, columns, selection, groupBy, having, orderBy, limit);//调用[6.1]

            return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
                    findEditTable(table), cancellationSignal);//调用[3.1]
        } finally {
            releaseReference();
        }
    }

SQLiteDatabase.java[3.3]

 /**
     * Query the given URL, returning a {@link Cursor} over the result set.
     *
     * @param distinct true if you want each row to be unique, false otherwise.
     */
    public Cursor query(boolean distinct, String table, String[] columns,
            String selection, String[] selectionArgs, String groupBy,
            String having, String orderBy, String limit) {
        return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
                groupBy, having, orderBy, limit, null);//调用[3.2]
    }

SQLiteDatabase.java[3.4]

  /**
     * Query the given table, returning a {@link Cursor} over the result set.
     *
     * @return A {@link Cursor} object, which is positioned before the first entry. Note that
     * {@link Cursor}s are not synchronized, see the documentation for more details.
     * @see Cursor
     */
    public Cursor query(String table, String[] columns, String selection,
            String[] selectionArgs, String groupBy, String having,
            String orderBy) {

        return query(false, table, columns, selection, selectionArgs, groupBy,
                having, orderBy, null /* limit */);//调用[3.3]
    }

三、扩展问题

1、distinct 这个布尔参数在控制什么

看到上述代码块中的[3.4]调用[3.3]中直接给 distinct 传了false,看代码注释:distinct true if you want each row to be unique, false otherwise.大致意思是我true的时候有一个唯一性的要求。搜索代码如下:

BordeauxSessionStorage[4.1]

    BordeauxSessionManager.Session getSession(String key) {
		//调用[3.3]
        Cursor cursor = mDbSessions.query(true, SESSION_TABLE,
                new String[]{COLUMN_KEY, COLUMN_CLASS, COLUMN_MODEL, COLUMN_TIME},
                COLUMN_KEY + "=\"" + key + "\"", null, null, null, null, null);
        if ((cursor == null) | (cursor.getCount() == 0)) {
            cursor.close();
            return null;
        }
        if (cursor.getCount() > 1) {
            cursor.close();
            throw new RuntimeException("Unexpected duplication in session table for key:" + key);
        }
        cursor.moveToFirst();
        BordeauxSessionManager.Session s = getSessionFromCursor(cursor);
        cursor.close();
        return s;
    }

BordeauxSessionManager[5.1]

这里,我可以看到这个BordeauxSessionManager的类注释:

// This class manages the learning sessions from multiple applications.
// The learning sessions are automatically backed up to the storage.

这里应该是和Application的管理有关。

public IBinder getSessionBinder(Class learnerClass, SessionKey key) {
        if (mSessions.containsKey(key.value)) {
            return mSessions.get(key.value).learner.getBinder();
        }
        // not in memory cache
        try {
            // try to find it in the database
            Session stored = mSessionStorage.getSession(key.value);//调用[4.1]
            if (stored != null) {
                // set the callback, so that we can save the state
                stored.learner.setModelChangeCallback(new LearningUpdateCallback(key.value));
                // found session in the storage, put in the cache
                mSessions.put(key.value, stored);
                return stored.learner.getBinder();
            }

            // if session is not already stored, create a new one.
            Log.i(TAG, "create a new learning session: " + key.value);
            IBordeauxLearner learner =
                    (IBordeauxLearner) learnerClass.getConstructor().newInstance();
            // set the callback, so that we can save the state
            learner.setModelChangeCallback(new LearningUpdateCallback(key.value));
            Session session = new Session();
            session.learnerClass = learnerClass;
            session.learner = learner;
            mSessions.put(key.value, session);
            return learner.getBinder();
        } catch (Exception e) {
            throw new RuntimeException("Can't instantiate class: " +
                                       learnerClass.getName());
        }
    }

但是不懂是干什么的,接着看到这里。

BordeauxSessionManager[5.2]

    // internal unique key that identifies the learning instance.
    // Composed by the package id of the calling process, learning class name
    // and user specified name.
    public SessionKey getSessionKey(String callingUid, Class learnerClass, String name) {
        SessionKey key = new SessionKey();
        key.value = callingUid + "#" + "_" + name + "_" + learnerClass.getName();
        return key;
    }

还是不懂,先放弃了。//TODO
还是回头去去看下这个参的true或者false实现上有啥区别。

SQLiteQueryBuilder.java[6.1]

 // SQLiteDatabase.java[3.2]调用了该方法。
 public static String buildQueryString(
            boolean distinct, String tables, String[] columns, String where,
            String groupBy, String having, String orderBy, String limit) {
	    //这里做的不错,当两个参数为一对都存在才可用的时候要进行校验。
        if (TextUtils.isEmpty(groupBy) && !TextUtils.isEmpty(having)) {
            throw new IllegalArgumentException(
                    "HAVING clauses are only permitted when using a groupBy clause");
        }
        if (!TextUtils.isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
            throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
        }

        StringBuilder query = new StringBuilder(120);

        query.append("SELECT ");
        if (distinct) {
            query.append("DISTINCT ");//区别就是在这里,拼接SQL语句的时候,加了个 DISTINCT
        }
        if (columns != null && columns.length != 0) {
            appendColumns(query, columns);
        } else {
            query.append("* ");
        }
        query.append("FROM ");
        query.append(tables);
        appendClause(query, " WHERE ", where);
        appendClause(query, " GROUP BY ", groupBy);
        appendClause(query, " HAVING ", having);
        appendClause(query, " ORDER BY ", orderBy);
        appendClause(query, " LIMIT ", limit);

        return query.toString();
    }

最后发现 distinct 为 true 的时候,给查询的 SQL 语句拼接了一个参数 DISTINCT。搜索下来段英文的解释装个逼。

The SELECT DISTINCT statement is used to return only distinct (different) values.

Inside a table, a column often contains many duplicate values; and sometimes you only want to list the different (distinct) values.

The SELECT DISTINCT statement is used to return only distinct (different) values.

2、cursorFactory 传null了,注释说用 default factory 怎么玩的

首先观察SQLiteDatabase.java[3.2]这个类rawQueryWithFactory方法中cursorFactory传入为null则用 mCursorFactory,这样说明这个mCursorFactory,也就是所说的 default factory。

SQLiteDatabase.java[3.5]

    private SQLiteDatabase(String path, int openFlags, CursorFactory cursorFactory,
            DatabaseErrorHandler errorHandler) {
        mCursorFactory = cursorFactory;//mCursorFactory
        mErrorHandler = errorHandler != null ? errorHandler : new DefaultDatabaseErrorHandler();
        mConfigurationLocked = new SQLiteDatabaseConfiguration(path, openFlags);
    }

发现mCursorFactory是构造中继续传入。

SQLiteDatabase.java[3.6]

    /**
     * Open the database according to the flags {@link #OPEN_READWRITE}
     * @param factory an optional factory class that is called to instantiate a
     *            cursor when query is called, or null for default
     * @param flags to control database access mode
     * @param errorHandler the {@link DatabaseErrorHandler} obj to be used to handle corruption
     * when sqlite reports database corruption
     * @return the newly opened database
     * @throws SQLiteException if the database cannot be opened
     */
    public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
            DatabaseErrorHandler errorHandler) {
        SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
        db.open();
        return db;
    }

SQLiteOpenHelper.java[7.1]

private SQLiteDatabase getDatabaseLocked(boolean writable) {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // Darn!  The user closed the database by calling mDatabase.close().
                mDatabase = null;
            } else if (!writable || !mDatabase.isReadOnly()) {
                // The database is already open for business.
                return mDatabase;
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getDatabase called recursively");
        }

        SQLiteDatabase db = mDatabase;
        try {
            mIsInitializing = true;

            if (db != null) {
                if (writable && db.isReadOnly()) {
                    db.reopenReadWrite();
                }
            } else if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                try {
                    if (DEBUG_STRICT_READONLY && !writable) {
                        final String path = mContext.getDatabasePath(mName).getPath();
						//调用了[3.6]
                        db = SQLiteDatabase.openDatabase(path, mFactory,
                                SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                    } else {
                        db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
                                Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
                                mFactory, mErrorHandler);
                    }
                } catch (SQLiteException ex) {
                    if (writable) {
                        throw ex;
                    }
                    Log.e(TAG, "Couldn't open " + mName
                            + " for writing (will try read-only):", ex);
                    final String path = mContext.getDatabasePath(mName).getPath();
					//调用了[3.6]
                    db = SQLiteDatabase.openDatabase(path, mFactory,
                            SQLiteDatabase.OPEN_READONLY, mErrorHandler);
                }
            }

            onConfigure(db);

            final int version = db.getVersion();
            if (version != mNewVersion) {
                if (db.isReadOnly()) {
                    throw new SQLiteException("Can't upgrade read-only database from version " +
                            db.getVersion() + " to " + mNewVersion + ": " + mName);
                }

                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);

            if (db.isReadOnly()) {
                Log.w(TAG, "Opened " + mName + " in read-only mode");
            }

            mDatabase = db;
            return db;
        } finally {
            mIsInitializing = false;
            if (db != null && db != mDatabase) {
                db.close();
            }
        }
    }

SQLiteOpenHelper.java[7.2]

    public SQLiteDatabase getReadableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(false);
        }
    }

SQLiteOpenHelper.java[7.3]

    public SQLiteDatabase getWritableDatabase() {
        synchronized (this) {
            return getDatabaseLocked(true);
        }
    }

SQLiteOpenHelper.java[7.4]

    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
        this(context, name, factory, version, null);
    }

最后追踪到这里,又回到开头了。我们通常要继承SQLiteOpenHelper,但是发现我们一般在这里传入的就是null,那这个并没有任何实现。

   MyDBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

DatabaseCursorTest[8.1]

  @MediumTest
    public void testRequeryWithAlteredSelectionArgs() throws Exception {
        /**
         * Test the ability of a subclass of SQLiteCursor to change its query arguments.
         */
        populateDefaultTable();

        SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() {
            public Cursor newCursor(
                    SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable,
                    SQLiteQuery query) {
                return new SQLiteCursor(db, masterQuery, editTable, query) {
                    @Override
                    public boolean requery() {
                        setSelectionArguments(new String[]{"2"});
                        return super.requery();
                    }
                };
            }
        };
	  // 省略  xxx
  }
}

根据SQLiteDirectCursorDriver.java[2.1] ,看到一个测试代码里边有这么个写法,这时候应该大概明白了这个CursorFactory的作用了,实际可以在外部自定义newCursor的实现。
观察到SQLiteDirectCursorDriver.java[2.1] 的代码,发现传入的CursorFactory,new的方式不一样。

SQLiteCursor[9.1]

    /**
     * Execute a query and provide access to its result set through a Cursor
     * interface. For a query such as: {@code SELECT name, birth, phone FROM
     * myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
     * phone) would be in the projection argument and everything from
     * {@code FROM} onward would be in the params argument.
     *
     * @param editTable the name of the table used for this query
     * @param query the {@link SQLiteQuery} object associated with this cursor object.
     */
    public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) {
        if (query == null) {
            throw new IllegalArgumentException("query object cannot be null");
        }
        if (StrictMode.vmSqliteObjectLeaksEnabled()) {
            mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
        } else {
            mStackTrace = null;
        }
        mDriver = driver;
        mEditTable = editTable;
        mColumnNameMap = null;
        mQuery = query;

        mColumns = query.getColumnNames();
        mRowIdColumnIndex = DatabaseUtils.findRowIdColumnIndex(mColumns);
    }

SQLiteDirectCursorDriver.java[2.2]

    /**
     * Used to allow returning sub-classes of {@link Cursor} when calling query.
     */
    public interface CursorFactory {
        /**
         * See {@link SQLiteCursor#SQLiteCursor(SQLiteCursorDriver, String, SQLiteQuery)}.
         */
        public Cursor newCursor(SQLiteDatabase db,
                SQLiteCursorDriver masterQuery, String editTable,
                SQLiteQuery query);
    }

根据上述接口,我们是不是考虑在进行查询操作时假如有部分特殊的要求,可以自定义实现自己想要的Cursor。

3、最后如何得到我们想要的返回值Cursor?

根据SQLiteCursor[9.1]实际已经知道看到了Cursor实际是我们new出来的。不过在构造中有几个操作。

        mQuery = query;

        mColumns = query.getColumnNames();
        mRowIdColumnIndex = DatabaseUtils.findRowIdColumnIndex(mColumns);

五、参考资料

SQL SELECT DISTINCT Statement

Json转换问题

使用jackson进行Json解析出现崩溃,奇怪的是在魅族Pro5出现了该问题,其他机器正常

03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   native: #11 pc 003f483f  /system/lib/libart.so (_ZN3art25JniMethodEndWithReferenceEP8_jobjectjPNS_6ThreadE+102)
03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   native: #12 pc 0008ed03  /data/dalvik-cache/arm/system@framework@boot.oat (Java_java_lang_reflect_Constructor_getDeclaredAnnotations__+86)
03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at java.lang.reflect.Constructor.getDeclaredAnnotations!(Native method)
03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.util.ClassUtil$Ctor.getDeclaredAnnotations(ClassUtil.java:1170)
03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.AnnotatedClass._constructNonDefaultConstructor(AnnotatedClass.java:933)
03-15 14:22:39.882 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.AnnotatedClass.resolveCreators(AnnotatedClass.java:440)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.AnnotatedClass.getConstructors(AnnotatedClass.java:306)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:410)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:285)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getJsonValueMethod(POJOPropertiesCollector.java:169)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findJsonValueMethod(BasicBeanDescription.java:222)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BasicSerializerFactory.findSerializerByAnnotations(BasicSerializerFactory.java:349)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:208)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:157)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1215)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   - locked <0x0b90d435> (a com.fasterxml.jackson.databind.ser.SerializerCache)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1167)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:490)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap.findAndAddSecondarySerializer(PropertySerializerMap.java:90)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer._findAndAddDynamic(ObjectArraySerializer.java:394)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serializeContents(ObjectArraySerializer.java:253)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:216)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:26)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serializeContents(ObjectArraySerializer.java:256)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:216)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.ObjectArraySerializer.serialize(ObjectArraySerializer.java:26)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:672)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:678)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3613)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2962)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.xtc.watch.util.JSONUtil.toJSON(JSONUtil.java:62)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.xtc.watch.receiver.im.business.ModelConvert.toImMessageData(ModelConvert.java:96)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.xtc.watch.view.weichat.WeiChatHandler.dealWeiChatInfo(WeiChatHandler.java:732)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.xtc.watch.WatchSystemService.translateImMsg(WatchSystemService.java:221)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.xtc.watch.WatchSystemService.onStartCommand(WatchSystemService.java:184)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3433)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.app.ActivityThread.-wrap21(ActivityThread.java:-1)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1670)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.os.Handler.dispatchMessage(Handler.java:102)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.os.Looper.loop(Looper.java:154)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at android.app.ActivityThread.main(ActivityThread.java:6243)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at java.lang.reflect.Method.invoke!(Native method)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
03-15 14:22:39.883 10510-10510/com.xtc.watch A/art: art/runtime/runtime.cc:403]   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)

调用的方法

public class JSONUtil {

    private static String TAG = JSONUtil.class.getName();

    private static ObjectMapper mapper = new ObjectMapper();

    static {
        //对于为null的字段不进行序列化
        mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
        //对于未知属性不进行反序列化
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //无论对象中的值只有不为null的才进行序列化
        mapper.setSerializationInclusion(Include.NON_NULL);

        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
    }
 /**
     * 把对象转化成json字符串
     *
     * @param obj
     * @return
     */
    public static String toJSON(Object obj) {
        if (obj == null) {
            return null;
        }

        Writer write = new StringWriter();
        try {
            mapper.writeValue(write, obj);
        } catch (JsonGenerationException e) {
            LogUtil.e(TAG, e.toString() + obj);
        } catch (JsonMappingException e) {
            LogUtil.e(TAG, e.toString() + obj);
        } catch (IOException e) {
            LogUtil.e(TAG, e.toString() + obj);
        }
        return write.toString();
    }

    /**
     * JSON字符串转成对象
     *
     * @param jsonStr
     * @param classType
     * @return
     */
    public static <T> T fromJSON(String jsonStr, Class<T> classType) {
        if (TextUtils.isEmpty(jsonStr)) {
            return null;
        }

        T t = null;
        try {
            t = mapper.readValue(jsonStr.getBytes(Constants.CHARSET_UTF_8), classType);
        } catch (JsonParseException e) {
            LogUtil.e(TAG, e.toString() + ", jsonStr:" + jsonStr + ", classType:" + classType.getName());
        } catch (JsonMappingException e) {
            LogUtil.e(TAG, e.toString() + ", jsonStr:" + jsonStr + ", classType:" + classType.getName());
        } catch (IOException e) {
            LogUtil.e(TAG, e.toString() + ", jsonStr:" + jsonStr + ", classType:" + classType.getName());
        }
        return t;
    }
}

换成Gson就OK了

public class GsonUtil {

    public static String toJSON(Object obj) {
        return createGson().toJson(obj);
    }

    public static String toJSON(Object obj, Type type) {
        return createGson().toJson(obj, type);
    }

    public static <T> T fromJSON(String json, Class<T> cls) {
        try {
            return createGson().fromJson(json, cls);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T fromJSON(String json, Type type) {
        try {
            return createGson().fromJson(json, type);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Gson createGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.serializeNulls();
        return gsonBuilder.create();
    }
}

Android8.0兼容问题

Service启动限制

8.0的service启动如果APP处在后台,(x21在APP启动的那一刻也认为在后台)将受限制,并报异常:

51250 java.lang.IllegalStateException: Not allowed to start service Intent { pkg=com.xtc.watch cmp=com.xtc.watch/.AppInitService }: app is in background uid UidRecord{75dee3c u0a196 CEM idle change:cached procs:1 seq(0,0,0)}

141019 [E][2018-05-17 +8.0 10:45:22.597][10832, 684][IM-Core-PushServiceManager][, init, 103][init error: java.lang.IllegalStateException: Not allowed to start service Intent { act=com.xtc.im.core.push.PushService flg=0x20 pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.push.PushService }: app is in background uid UidRecord{433e37b u0a196 CEM idle change:cached procs:1 seq(0,0,0)}

startActivityForResult的坑

在fragment里面用getActivity().startActivityForResult 去启动,那么这个fragment的onActivityResult里面收不到

java.lang.SecurityException: Unable to start service Intent { xxx }: user 0 is restricted

java.lang.SecurityException: Unable to start service Intent { act=com.xtc.im.app.revive.pushinfo cat=[com.xtc.im] flg=0x20 pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.app.bridge.AppReviveService (has extras) }: Unable to launch app com.xtc.watch/10273 for service Intent { act=com.xtc.im.app.revive.pushinfo cat=[com.xtc.im] pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.app.bridge.AppReviveService }: user 0 is restricted
	at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1769)
	at android.app.ContextImpl.startService(ContextImpl.java:1742)
	at android.content.ContextWrapper.startService(ContextWrapper.java:527)

BindService时异常java.lang.NullPointerException: Attempt to read from field 'long android.os.Parcel.mNativePtr' on a null object reference

#Wed Feb 07 13:05:56 GMT+08:00 2018
STACK_TRACE=java.lang.RuntimeException: Unable to bind to service com.xtc.im.core.push.PushService@33d1d88a with Intent { act=com.xtc.im.core.push.PushService flg=0x20 pkg=com.xtc.watch cmp=com.xtc.watch/com.xtc.im.core.push.PushService (has extras) }: java.lang.NullPointerException: Attempt to read from field 'long android.os.Parcel.mNativePtr' on a null object reference
 android.app.ActivityThread.handleBindService(ActivityThread.java:2880)
 android.app.ActivityThread.access$2000(ActivityThread.java:175)
 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1457)
 android.os.Handler.dispatchMessage(Handler.java:102)
 android.os.Looper.loop(Looper.java:135)
 android.app.ActivityThread.main(ActivityThread.java:5418)
 java.lang.reflect.Method.invoke(Native Method)
 java.lang.reflect.Method.invoke(Method.java:372)
 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037)
 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
Caused by: java.lang.NullPointerException: Attempt to read from field 'long android.os.Parcel.mNativePtr' on a null object reference
 android.os.Parcel.appendFrom(Parcel.java:446)
 android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1300)
 android.os.Bundle.writeToParcel(Bundle.java:1034)
 android.os.Parcel.writeBundle(Parcel.java:697)
 android.content.Intent.writeToParcel(Intent.java:7734)
 android.app.ActivityManagerProxy.publishService(ActivityManagerNative.java:3676)
 android.app.ActivityThread.handleBindService(ActivityThread.java:2868)
/r... 9 more
java.lang.NullPointerException: Attempt to read from field 'long android.os.Parcel.mNativePtr' on a null object reference
 android.os.Parcel.appendFrom(Parcel.java:446)
 android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1300)
 android.os.Bundle.writeToParcel(Bundle.java:1034)
 android.os.Parcel.writeBundle(Parcel.java:697)
 android.content.Intent.writeToParcel(Intent.java:7734)
 android.app.ActivityManagerProxy.publishService(ActivityManagerNative.java:3676)
 android.app.ActivityThread.handleBindService(ActivityThread.java:2868)
 android.app.ActivityThread.access$2000(ActivityThread.java:175)
 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1457)
 android.os.Handler.dispatchMessage(Handler.java:102)
 android.os.Looper.loop(Looper.java:135)
 android.app.ActivityThread.main(ActivityThread.java:5418)
 java.lang.reflect.Method.invoke(Native Method)
 java.lang.reflect.Method.invoke(Method.java:372)
 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1037)
 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

java.util.concurrent.RejectedExecutionException

java.util.concurrent.RejectedExecutionException: Task com.xtc.im.core.common.task.RealCall$AsyncCall@f0b58eb rejected from java.util.concurrent.ThreadPoolExecutor@daea648[Shutting down, pool size = 64, active threads = 64, queued tasks = 0, completed tasks = 8]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2049)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:814)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1360)

java.lang.IllegalStateException: Fragment already added

STACK_TRACE=java.lang.IllegalStateException: Fragment already added: LocationMainFragment
at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1891)
at android.support.v4.app.BackStackRecord.executeOps(BackStackRecord.java:760)
at android.support.v4.app.FragmentManagerImpl.executeOps(FragmentManager.java:2596)
at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2383)
at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5401)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:919)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:714)

ANR: "main" prio=5 tid=1 WaitingForGcToComplete

"main" prio=5 tid=1 WaitingForGcToComplete
| group="main" sCount=1 dsCount=0 flags=1 obj=0x747e4600 self=0xf0010000
| sysTid=16849 nice=-10 cgrp=default sched=0/0 handle=0xf39e94a8
| state=S schedstat=( 0 0 0 ) utm=1435 stm=301 core=5 HZ=100
| stack=0xff2b9000-0xff2bb000 stackSize=8MB
| held mutexes=
kernel: (couldn't read /proc/self/task/16849/stack)
native: #00 pc 00019118 /system/lib/libc.so (syscall+28)
native: #1 pc 000b3c05 /system/lib/libart.so (_ZN3art17ConditionVariable16WaitHoldingLocksEPNS_6ThreadE+88)
native: #2 pc 00192c23 /system/lib/libart.so (_ZN3art2gc4Heap25WaitForGcToCompleteLockedENS0_7GcCauseEPNS_6ThreadE+230)
native: #3 pc 0019d63b /system/lib/libart.so (_ZN3art2gc4Heap19WaitForGcToCompleteENS0_7GcCauseEPNS_6ThreadE+190)
native: #4 pc 0019a2f3 /system/lib/libart.so (_ZN3art2gc4Heap22AllocateInternalWithGcEPNS_6ThreadENS0_13AllocatorTypeEbjPjS5_S5_PNS_6ObjPtrINS_6mirror5ClassEEE+78)
native: #5 pc 003b3009 /system/lib/libart.so (artAllocObjectFromCodeInitializedRegionTLAB+228)
native: #6 pc 003e036b /system/lib/libart.so (art_quick_alloc_object_initialized_region_tlab+74)
native: #7 pc 00000e17 /dev/ashmem/dalvik-jit-code-cache (deleted) (Java_com_xtc_log_util_StackUtils_makeStackInfo__IIJ+198)
at com.xtc.log.util.StackUtils.makeStackInfo(StackUtils.java:23)
at com.xtc.log.util.StackUtils.makeAndroidStackInfo(StackUtils.java:59)
at com.xtc.log.xlog.Xlogger.log(Xlogger.java:249)
at com.xtc.log.Log.i(Log.java:33)
at com.xtc.log.LogUtil.i(LogUtil.java:56)
at com.xtc.watch.receiver.SystemReceiver.onReceive(SystemReceiver.java:83)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_51571(LoadedApk.java:1304)
at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.$m$0(unavailable:-1)
at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.run(unavailable:-1)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6665)
at java.lang.reflect.Method.invoke(Native method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:781)

详细

traces(5).txt

image

image

搜索发现:

"FinalizerDaemon" daemon prio=5 tid=5 WaitingPerformingGc
  | group="system" sCount=1 dsCount=0 flags=1 obj=0x12c8a550 self=0xe36fce00
  | sysTid=16856 nice=4 cgrp=default sched=0/0 handle=0xd40dd970
  | state=R schedstat=( 0 0 0 ) utm=1221 stm=58 core=6 HZ=100
  | stack=0xd3fdb000-0xd3fdd000 stackSize=1038KB
  | held mutexes= "mutator lock"(shared held)
  kernel: (couldn't read /proc/self/task/16856/stack)
  native: #00 pc 0017341a  /system/lib/libart.so (_ZN3art2gc9collector17ConcurrentCopying19ProcessMarkStackRefEPNS_6mirror6ObjectE+129)
  native: #01 pc 00172f3b  /system/lib/libart.so (_ZN3art2gc9collector17ConcurrentCopying20ProcessMarkStackOnceEv+402)
  native: #02 pc 00172d9b  /system/lib/libart.so (_ZN3art2gc9collector17ConcurrentCopying16ProcessMarkStackEv+18)
  native: #03 pc 0016e555  /system/lib/libart.so (_ZN3art2gc9collector17ConcurrentCopying12MarkingPhaseEv+456)
  native: #04 pc 0016db35  /system/lib/libart.so (_ZN3art2gc9collector17ConcurrentCopying9RunPhasesEv+540)
  native: #05 pc 0017cbc5  /system/lib/libart.so (_ZN3art2gc9collector16GarbageCollector3RunENS0_7GcCauseEb+268)
  native: #06 pc 001979ef  /system/lib/libart.so (_ZN3art2gc4Heap22CollectGarbageInternalENS0_9collector6GcTypeENS0_7GcCauseEb+2726)
  native: #07 pc 0019b325  /system/lib/libart.so (_ZN3art2gc4Heap22AllocateInternalWithGcEPNS_6ThreadENS0_13AllocatorTypeEbjPjS5_S5_PNS_6ObjPtrINS_6mirror5ClassEEE+4224)
  native: #08 pc 003b3009  /system/lib/libart.so (artAllocObjectFromCodeInitializedRegionTLAB+228)
  native: #09 pc 003e036b  /system/lib/libart.so (art_quick_alloc_object_initialized_region_tlab+74)
  native: #10 pc 014b6921  /system/framework/arm/boot-framework.oat (Java_com_android_internal_os_BinderInternal_00024GcWatcher_finalize__+336)
  at com.android.internal.os.BinderInternal$GcWatcher.finalize(BinderInternal.java:53)
  at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:250)
  at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:237)
  at java.lang.Daemons$Daemon.run(Daemons.java:103)
  at java.lang.Thread.run(Thread.java:764)

Component class com.huawei.hms.support.api.push.PushEventReceiver does not exist in com.xtc.watch

07-25 09:51:01.897 25436-25436/com.xtc.watch E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xtc.watch, PID: 25436
java.lang.RuntimeException: Unable to create application com.xtc.watch.XtcApplication: java.lang.IllegalArgumentException: Component class com.huawei.hms.support.api.push.PushEventReceiver does not exist in com.xtc.watch
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4701)
at android.app.ActivityThread.access$1600(ActivityThread.java:167)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1435)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5401)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:919)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:714)
Caused by: java.lang.IllegalArgumentException: Component class com.huawei.hms.support.api.push.PushEventReceiver does not exist in com.xtc.watch
at android.os.Parcel.readException(Parcel.java:1550)
at android.os.Parcel.readException(Parcel.java:1499)
at android.content.pm.IPackageManager$Stub$Proxy.setComponentEnabledSetting(IPackageManager.java:3394)
at android.app.ApplicationPackageManager.setComponentEnabledSetting(ApplicationPackageManager.java:1492)
at com.xtc.im.phone.thirdpush.a.d(ThirdPushManager.java:242)
at com.xtc.im.phone.thirdpush.a.b(ThirdPushManager.java:132)
at com.xtc.im.phone.IMPhone.startThirdPush(IMPhone.java:154)
at com.xtc.watch.XtcApplication.onCreate(XtcApplication.java:142)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1018)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4698)
at android.app.ActivityThread.access$1600(ActivityThread.java:167) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1435) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5401) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:919) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:714)

Toast Show的时候出现 BadTokenException: Unable to add window -- token

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@8bb205c is not valid; is your activity running?
at android.view.ViewRootImpl.setView(ViewRootImpl.java:812)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:361)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.widget.Toast$TN.handleShow(Toast.java:489)
at android.widget.Toast$TN$2.handleMessage(Toast.java:360)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6455)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1134)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)

Android系统版本兼容ReflectiveOperationException问题

反射获取getTag接口报ReflectiveOperationException

private static String getWakeLockTag(PowerManager.WakeLock wakeLock) {
        String tag = "Default-WakeLock-Tag";
        if (wakeLock == null) {
            return tag;
        }
        try {
            Method getTagMethod = wakeLock.getClass().getDeclaredMethod("getTag");
            getTagMethod.setAccessible(true);
            tag = (String) getTagMethod.invoke(wakeLock, (Object[]) null);
        } catch (ClassNotFoundExceptione) {
            LogUtil.w(TAG,e);
        } 
        return tag;
    }

java.lang.IllegalArgumentException: pointerIndex out of range

java.lang.IllegalArgumentException: pointerIndex out of range
android.view.MotionEvent.nativeGetAxisValue(Native Method)
android.view.MotionEvent.getX(MotionEvent.java:2072)
android.support.v4.view.ViewPager.onTouchEvent(SourceFile:2275)
android.view.View.dispatchTouchEvent(View.java:9432)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2663)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2304)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2669)
android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2318)
com.android.internal.policy.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2447)
com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1766)
android.app.Activity.dispatchTouchEvent(Activity.java:2811)

CursorWindowAllocationException

android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed.
at android.database.CursorWindow.(CursorWindow.java:104)
at android.database.CursorWindow.(CursorWindow.java:126)
at net.sqlcipher.CursorWindow.(CursorWindow.java:54)
at net.sqlcipher.database.SQLiteCursor.fillWindow(SQLiteCursor.java:288)
at net.sqlcipher.database.SQLiteCursor.getCount(SQLiteCursor.java:280)
at net.sqlcipher.AbstractCursor.moveToPosition(AbstractCursor.java:178)
at net.sqlcipher.AbstractCursor.moveToFirst(AbstractCursor.java:222)
at android.database.CursorWrapper.moveToFirst(CursorWrapper.java:65)
at com.j256.ormlite.sqlcipher.android.AndroidCompiledStatement.getCursor(AndroidCompiledStatement.java:181)
at com.j256.ormlite.sqlcipher.android.AndroidCompiledStatement.runQuery(AndroidCompiledStatement.java:65)
at com.j256.ormlite.stmt.SelectIterator.(SelectIterator.java:55)
at com.j256.ormlite.stmt.StatementExecutor.buildIterator(StatementExecutor.java:247)
at com.j256.ormlite.stmt.StatementExecutor.query(StatementExecutor.java:196)
at com.j256.ormlite.dao.BaseDaoImpl.query(BaseDaoImpl.java:265)
at com.j256.ormlite.stmt.QueryBuilder.query(QueryBuilder.java:361)

使用hanlderThread时出现了NullProintException

     HandlerThread handlerThread = new HandlerThread("timer-scheduler-thread");
    handlerThread.start();// 这里忘记调用就异常了
    mHandler = new Handler(handlerThread.getLooper())

Caused by: java.lang.NullPointerException: Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
at android.os.Handler.(Handler.java:238)
at android.os.Handler.(Handler.java:146)
at com.xtc.watch.scheduler.HandlerScheduler$1.(HandlerScheduler.java:0)
at com.xtc.watch.scheduler.HandlerScheduler.initHandler(HandlerScheduler.java:24)

SharedPreferences多进程的坑

问题背景:

Android 6.0 系统
多进程写同一个SharedPreferences文件
push进程先写数据到data/data/com.xtc.im.phonesample/shared_prefs/com.xtc.im.phonesample.xml,
正常
app主进程再次写数据,这时文件是一样的,会把push进程的数据覆盖掉。

一样的原因是:

    private static SharedPreferences sp;
    private static volatile LocalPreference instance;

    private LocalPreference(Context context) {
        Context application = context.getApplicationContext();
        sp = application.getSharedPreferences(context.getPackageName(), 0);
    }

    public static LocalPreference getInstance(Context context) {
        if (instance == null) {
            synchronized(LocalPreference.class) {
                if (instance == null) {
                    instance = new LocalPreference(context);
                }
            }
        }

        return instance;
    }

    public boolean putString(String key, String value) {
        return this.getEditor().putString(key, value).commit();
    }

``
但是,这里是不同的进程获取这个SP的单列。

ExceptionInInitializerError

java.lang.ExceptionInInitializerError
at com.xtc.im.phone.thirdpush.c$1.onSuccess(Unknown Source)
at com.umeng.message.UmengMessageCallbackHandlerService.onHandleIntent(Unknown Source)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: java.lang.RuntimeException: android.os.DeadObjectException
at android.os.storage.StorageManager.getVolumeList(StorageManager.java:886)
at android.os.Environment$UserEnvironment.getExternalDirs(Environment.java:103)
at android.os.Environment.getExternalStorageDirectory(Environment.java:360)
at com.xtc.im.core.push.store.SDCardFile.(Unknown Source)
... 6 more
Caused by: android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageUid(IPackageManager.java:2235)
at android.os.storage.StorageManager.getVolumeList(StorageManager.java:880)
... 9 more
java.lang.RuntimeException: android.os.DeadObjectException
at android.os.storage.StorageManager.getVolumeList(StorageManager.java:886)
at android.os.Environment$UserEnvironment.getExternalDirs(Environment.java:103)
at android.os.Environment.getExternalStorageDirectory(Environment.java:360)
at com.xtc.im.core.push.store.SDCardFile.(Unknown Source)
at com.xtc.im.phone.thirdpush.c$1.onSuccess(Unknown Source)
at com.umeng.message.UmengMessageCallbackHandlerService.onHandleIntent(Unknown Source)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageUid(IPackageManager.java:2235)
at android.os.storage.StorageManager.getVolumeList(StorageManager.java:880)
... 9 more
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageUid(IPackageManager.java:2235)
at android.os.storage.StorageManager.getVolumeList(StorageManager.java:880)
at android.os.Environment$UserEnvironment.getExternalDirs(Environment.java:103)
at android.os.Environment.getExternalStorageDirectory(Environment.java:360)
at com.xtc.im.core.push.store.SDCardFile.(Unknown Source)
at com.xtc.im.phone.thirdpush.c$1.onSuccess(Unknown Source)
at com.umeng.message.UmengMessageCallbackHandlerService.onHandleIntent(Unknown Source)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:66)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)

image

image

SharedPreferences解析

初始化

SharedPreferencesImpl

  • mFile 实际SharedPreferences数据存储文件,文件后缀名为“.xml”
  • mBackupFile 备份文件,文件后缀名为“.bak”
  • mMap 内存缓存
    SharedPreferencesImpl(File file, int mode) {
        mFile = file;
        mBackupFile = makeBackupFile(file);
        mMode = mode;
        mLoaded = false;
        mMap = null;
        startLoadFromDisk();
    }
  • 如果存在备份文件,则把XML文件删掉,用备份文件来替换
  • 读取xml文件数据赋值给临时的map
  • 如果读到的数据不为null,则赋值给全局的mMap,也就是放到内存缓存中,并把mLoaded置为true
  • 如果map为null,还是给mMap new 一个对象,方便后面使用
    private void loadFromDisk() {
        synchronized (mLock) {
            if (mLoaded) {
                return;
            }
            // 如果存在备份文件,则把XML文件删掉,用备份文件来替换
            if (mBackupFile.exists()) {
                mFile.delete();
                mBackupFile.renameTo(mFile);
            }
        }

        // Debugging
        if (mFile.exists() && !mFile.canRead()) {
            Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission");
        }

        Map map = null;
        StructStat stat = null;
        try {
            stat = Os.stat(mFile.getPath());
            if (mFile.canRead()) {
                BufferedInputStream str = null;
                try {
                    str = new BufferedInputStream(
                            new FileInputStream(mFile), 16*1024);
                    // 将文件里的数据读取赋值给到map内存缓存
                    map = XmlUtils.readMapXml(str);
                } catch (Exception e) {
                    Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e);
                } finally {
                    IoUtils.closeQuietly(str);
                }
            }
        } catch (ErrnoException e) {
            /* ignore */
        }

        synchronized (mLock) {
            mLoaded = true;
            if (map != null) {
                mMap = map;
                mStatTimestamp = stat.st_mtim;
                mStatSize = stat.st_size;
            } else {
                mMap = new HashMap<>();
            }
            mLock.notifyAll();
        }
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.