Java 应为BEGIN_对象,但在第1行第14列路径$with OBJECT和SQLite处为数字

Java 应为BEGIN_对象,但在第1行第14列路径$with OBJECT和SQLite处为数字,java,android,json,notifications,gson,Java,Android,Json,Notifications,Gson,我试图在SQLite数据库中存储一个Android通知对象,但遇到了一个错误 首先,在我解释错误之前,让我解释一下什么是有效的。我有一个NotificationListenerService类,它侦听通知并阻止它们显示。你可以在下面的课堂上看到这一点。当通知被阻止时,我想将它们存储在SQLite数据库中。然而,我的问题是如何在数据库中存储通知对象,所以我选择了GSON到JSON的路由。因此,无论何时销毁通知,它都会将通知对象转换为Json并将其存储在数据库中(以及其他一些内容) 通知监听器服务:

我试图在SQLite数据库中存储一个Android通知对象,但遇到了一个错误

首先,在我解释错误之前,让我解释一下什么是有效的。我有一个NotificationListenerService类,它侦听通知并阻止它们显示。你可以在下面的课堂上看到这一点。当通知被阻止时,我想将它们存储在SQLite数据库中。然而,我的问题是如何在数据库中存储通知对象,所以我选择了GSON到JSON的路由。因此,无论何时销毁通知,它都会将通知对象转换为Json并将其存储在数据库中(以及其他一些内容)

通知监听器服务:

public class NotificationListenerServiceUsage extends NotificationListenerService {
    private static final String TAG = "NotificationListenerSer";


    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn){
        cancelAllNotifications();
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn){
        // 1. Getting DB Context and initializing SQLiteDatabase
        Context context = getApplicationContext();
        SQLiteDatabase sqLiteDatabase = context.openOrCreateDatabase("notifications", Context.MODE_PRIVATE,null);

        // 2. Initialize the DBHelper class.
        DBHelper dbHelper = new DBHelper(sqLiteDatabase);

        // 3. Getting the content for the DB
        String notificationKey = sbn.getKey();
        Integer notificationID = sbn.getId();
        long postTime = sbn.getPostTime();
        Notification notificationContent = sbn.getNotification();

        // 3.1 Converting the Notification Object into a String
        Gson gson = new Gson();
        String notificationInput = gson.toJson(notificationContent);


        // 4. Saving into the DB
        dbHelper.saveNotifications(notificationKey, notificationID, postTime, notificationInput);

        // FOR TESTING PURPOSES
        Notification finalNotificationObj = gson.fromJson(notificationInput, Notification.class);

        // FOR TESTING PURPOSES
        Log.d(TAG, "onNotificationRemoved: " + "INPUT: " + notificationContent);
        Log.d(TAG, "onNotificationRemoved: " + "JSON: " + notificationInput);
        Log.d(TAG, "onNotificationRemoved: " + "OUTPUT: " + finalNotificationObj );
    }

}
public class DBHelper {
    SQLiteDatabase sqLiteDatabase;
    private static final String TAG = "DBHelper";

    public DBHelper(SQLiteDatabase sqLiteDatabase) {
        this.sqLiteDatabase = sqLiteDatabase;
    }

    public void createTable (){
        sqLiteDatabase.execSQL("CREATE TABLE  IF NOT EXISTS notifications" + "(notificationKey TEXT, notificationID INTEGER, postTime BIGINT, notificatoinContent TEXT)");
    }

    public ArrayList<NotificationObject> readNotifications(){
        // 1. Checking the table and creating a NotificationObject instance
        createTable();
        ArrayList<NotificationObject> notificationObjects = new ArrayList<>();

        // 2. Starting the cursor at the top of the notification Table
        Cursor c = sqLiteDatabase.rawQuery(("SELECT * from notifications"), null);

        // 3. Gets the index of all of the columns so that the cursor can reference it from the row
        int keyIndex = c.getColumnIndex("notificationKey");
        int notificationIDIndex = c.getColumnIndex("notificationID");
        int postTimeIndex = c.getColumnIndex("postTime");
        int notificationContentIndex = c.getColumnIndex("postTime");

        // 4. Moves the cursor to the top
        c.moveToFirst();

        // 5. While loop to loop through all the rows
        while (!c.isAfterLast()){

            // 5.1 Getting all of the values from row of the cursor
            String notificationKey = c.getString(keyIndex);
            Integer notificationID = c.getInt(notificationIDIndex);
            long postTime = c.getLong(postTimeIndex);
            String notificationContent = c.getString(notificationContentIndex);

            // 5.2 Converting Notification content back to Notification Object
            Gson gson = new Gson();
            Notification finalNotificationObj = gson.fromJson(notificationContent, Notification.class);

            // 5.3 Adds all of the content to the NotificationObject Object
            NotificationObject notificationObject = new NotificationObject(notificationKey, notificationID, postTime, finalNotificationObj);

            // 5.4 Adds the notificationObject to the arraylist
            notificationObjects.add(notificationObject);
            c.moveToNext();
        }
        c.close();
        sqLiteDatabase.close();
        return notificationObjects;
    }

    public void saveNotifications (String notificationKey, Integer notificationID, long postTime, String notificationContent){

        createTable();
        sqLiteDatabase.execSQL(String.format("INSERT INTO notifications (notificationKey, notificationID, postTime, notificatoinContent)" +
                " VALUES ('%s', '%s', '%s', '%s')", notificationKey, notificationID, postTime, notificationContent));
    }
}
2020-04-20 13:55:52.881 12060-12060/com.example.finalproject E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.finalproject, PID: 12060
    java.lang.IllegalStateException: Could not execute method for android:onClick
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
        at android.view.View.performClick(View.java:7125)
        at android.view.View.performClickInternal(View.java:7102)
        at android.view.View.access$3500(View.java:801)
        at android.view.View$PerformClick.run(View.java:27336)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 14 path $
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        at com.google.gson.Gson.fromJson(Gson.java:897)
        at com.google.gson.Gson.fromJson(Gson.java:846)
        at com.google.gson.Gson.fromJson(Gson.java:817)
        at com.example.finalproject.BatchNotifications.DBHelper.readNotifications(DBHelper.java:54)
        at com.example.finalproject.BatchNotifications.Batch_Notifications.getHeldNotifications(Batch_Notifications.java:290)
        at java.lang.reflect.Method.invoke(Native Method) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) 
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 14 path $
        at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:386)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215)
        at com.google.gson.Gson.fromJson(Gson.java:932) 
        at com.google.gson.Gson.fromJson(Gson.java:897) 
        at com.google.gson.Gson.fromJson(Gson.java:846) 
        at com.google.gson.Gson.fromJson(Gson.java:817) 
        at com.example.finalproject.BatchNotifications.DBHelper.readNotifications(DBHelper.java:54) 
        at com.example.finalproject.BatchNotifications.Batch_Notifications.getHeldNotifications(Batch_Notifications.java:290) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) 
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
呈现的结果Json如下所示:

{
   "audioAttributes":{
      "mContentType":4,
      "mFlags":2048,
      "mFormattedTags":"",
      "mSource":-1,
      "mUsage":5
   },
   "audioStreamType":-1,
   "color":0,
   "defaults":0,
   "extras":{
      "mParcelledData":{
         "mNativePtr":3569564416
      }
   },
   "flags":0,
   "icon":2131230820,
   "iconLevel":0,
   "ledARGB":0,
   "ledOffMS":0,
   "ledOnMS":0,
   "mChannelId":"channel1",
   "mSmallIcon":{
      "mString1":"com.example.finalproject",
      "mType":2
   },
   "number":0,
   "priority":1,
   "visibility":0,
   "when":1587406911152
}
有什么问题吗?

我能够成功地将字符串Json存储在数据库中,但是当我将其从数据库中拉回来,并尝试将其转换回Notification对象时,我得到了一个IllegalStateException。下面是堆栈跟踪以供参考。我觉得在存储字符串Json并将其取出时会出现问题,因为在上面的Notificaiton侦听器文件中,我只记录了一些事情,并且成功地将其转换为Json并返回,并且完全匹配。下面是我正在使用的数据库帮助器类,它显示了如何存储和提取数据。问题中的错误发生在readNotifications()方法中

有没有想过为什么会发生这种错误

数据库访问类:

public class NotificationListenerServiceUsage extends NotificationListenerService {
    private static final String TAG = "NotificationListenerSer";


    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn){
        cancelAllNotifications();
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn){
        // 1. Getting DB Context and initializing SQLiteDatabase
        Context context = getApplicationContext();
        SQLiteDatabase sqLiteDatabase = context.openOrCreateDatabase("notifications", Context.MODE_PRIVATE,null);

        // 2. Initialize the DBHelper class.
        DBHelper dbHelper = new DBHelper(sqLiteDatabase);

        // 3. Getting the content for the DB
        String notificationKey = sbn.getKey();
        Integer notificationID = sbn.getId();
        long postTime = sbn.getPostTime();
        Notification notificationContent = sbn.getNotification();

        // 3.1 Converting the Notification Object into a String
        Gson gson = new Gson();
        String notificationInput = gson.toJson(notificationContent);


        // 4. Saving into the DB
        dbHelper.saveNotifications(notificationKey, notificationID, postTime, notificationInput);

        // FOR TESTING PURPOSES
        Notification finalNotificationObj = gson.fromJson(notificationInput, Notification.class);

        // FOR TESTING PURPOSES
        Log.d(TAG, "onNotificationRemoved: " + "INPUT: " + notificationContent);
        Log.d(TAG, "onNotificationRemoved: " + "JSON: " + notificationInput);
        Log.d(TAG, "onNotificationRemoved: " + "OUTPUT: " + finalNotificationObj );
    }

}
public class DBHelper {
    SQLiteDatabase sqLiteDatabase;
    private static final String TAG = "DBHelper";

    public DBHelper(SQLiteDatabase sqLiteDatabase) {
        this.sqLiteDatabase = sqLiteDatabase;
    }

    public void createTable (){
        sqLiteDatabase.execSQL("CREATE TABLE  IF NOT EXISTS notifications" + "(notificationKey TEXT, notificationID INTEGER, postTime BIGINT, notificatoinContent TEXT)");
    }

    public ArrayList<NotificationObject> readNotifications(){
        // 1. Checking the table and creating a NotificationObject instance
        createTable();
        ArrayList<NotificationObject> notificationObjects = new ArrayList<>();

        // 2. Starting the cursor at the top of the notification Table
        Cursor c = sqLiteDatabase.rawQuery(("SELECT * from notifications"), null);

        // 3. Gets the index of all of the columns so that the cursor can reference it from the row
        int keyIndex = c.getColumnIndex("notificationKey");
        int notificationIDIndex = c.getColumnIndex("notificationID");
        int postTimeIndex = c.getColumnIndex("postTime");
        int notificationContentIndex = c.getColumnIndex("postTime");

        // 4. Moves the cursor to the top
        c.moveToFirst();

        // 5. While loop to loop through all the rows
        while (!c.isAfterLast()){

            // 5.1 Getting all of the values from row of the cursor
            String notificationKey = c.getString(keyIndex);
            Integer notificationID = c.getInt(notificationIDIndex);
            long postTime = c.getLong(postTimeIndex);
            String notificationContent = c.getString(notificationContentIndex);

            // 5.2 Converting Notification content back to Notification Object
            Gson gson = new Gson();
            Notification finalNotificationObj = gson.fromJson(notificationContent, Notification.class);

            // 5.3 Adds all of the content to the NotificationObject Object
            NotificationObject notificationObject = new NotificationObject(notificationKey, notificationID, postTime, finalNotificationObj);

            // 5.4 Adds the notificationObject to the arraylist
            notificationObjects.add(notificationObject);
            c.moveToNext();
        }
        c.close();
        sqLiteDatabase.close();
        return notificationObjects;
    }

    public void saveNotifications (String notificationKey, Integer notificationID, long postTime, String notificationContent){

        createTable();
        sqLiteDatabase.execSQL(String.format("INSERT INTO notifications (notificationKey, notificationID, postTime, notificatoinContent)" +
                " VALUES ('%s', '%s', '%s', '%s')", notificationKey, notificationID, postTime, notificationContent));
    }
}
2020-04-20 13:55:52.881 12060-12060/com.example.finalproject E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.finalproject, PID: 12060
    java.lang.IllegalStateException: Could not execute method for android:onClick
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
        at android.view.View.performClick(View.java:7125)
        at android.view.View.performClickInternal(View.java:7102)
        at android.view.View.access$3500(View.java:801)
        at android.view.View$PerformClick.run(View.java:27336)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 14 path $
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        at com.google.gson.Gson.fromJson(Gson.java:897)
        at com.google.gson.Gson.fromJson(Gson.java:846)
        at com.google.gson.Gson.fromJson(Gson.java:817)
        at com.example.finalproject.BatchNotifications.DBHelper.readNotifications(DBHelper.java:54)
        at com.example.finalproject.BatchNotifications.Batch_Notifications.getHeldNotifications(Batch_Notifications.java:290)
        at java.lang.reflect.Method.invoke(Native Method) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) 
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
     Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was NUMBER at line 1 column 14 path $
        at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:386)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215)
        at com.google.gson.Gson.fromJson(Gson.java:932) 
        at com.google.gson.Gson.fromJson(Gson.java:897) 
        at com.google.gson.Gson.fromJson(Gson.java:846) 
        at com.google.gson.Gson.fromJson(Gson.java:817) 
        at com.example.finalproject.BatchNotifications.DBHelper.readNotifications(DBHelper.java:54) 
        at com.example.finalproject.BatchNotifications.Batch_Notifications.getHeldNotifications(Batch_Notifications.java:290) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) 
        at android.view.View.performClick(View.java:7125) 
        at android.view.View.performClickInternal(View.java:7102) 
        at android.view.View.access$3500(View.java:801) 
        at android.view.View$PerformClick.run(View.java:27336) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 

答案在上面发布的数据库助手类中。在readNotifications方法的步骤3中,行

int notificationContentIndex = c.getColumnIndex("postTime");

指向了不正确的列。它指向postTime列,该列返回的是int值而不是JSON字符串。将该int传递给GSON/JSON转换器会导致上述错误。将其指向正确的列解决了问题。

不要序列化不在您控制下的对象<代码>通知来自Android SDK。它的内部结构(您正试图捕获)可能会在不同的系统版本之间发生变化(您的应用程序在系统更新后会崩溃),可能会在不同的制造商之间发生变化(当我购买新手机并迁移应用程序时,您的应用程序会崩溃),谁知道还会发生什么。为您所要做的事情定制一个自定义的最小信息子集。考虑使用它来禁止您从Android SDK(或<代码> java > */COD>或<代码> KOTLIN > */COD>包)中序列化任何东西。强迫自己养成更好的习惯。@EugenPechanec绝对-创建自定义DTO是最终目标,将用于生产(目前正在开发)。我们目前正努力让概念验证工作,并希望确保类似的事情是可能的。