Android Studio - 线程完成后从 SQLite 获取数据

Posted

技术标签:

【中文标题】Android Studio - 线程完成后从 SQLite 获取数据【英文标题】:Android Studio - get data from SQLite after thread done 【发布时间】:2021-12-01 18:56:18 【问题描述】:

在启动应用程序时,我首先需要同步数据库中的数据,以便用户可以离线查看数据。因此,我创建了一个特殊的同步类,用于比较来自网络的数据,并在必要时将其写入本地 SQLite 数据库。

从 SQLite 数据库中检索数据以将更改与来自 Internet 的数据进行比较时会出现问题。

我尝试使用通常在其他类中使用的 AsyncTask,但这会导致应用程序一遍又一遍地重新启动。

当使用“public class GetDbData implements Runnable ...”时,会出现以下错误,我不清楚是什么原因造成的。

感谢您的回复。

错误信息:

2021-10-13 11:01:36.682 18498-18590/com.commonsware.android E/AndroidRuntime: FATAL EXCEPTION: Thread-10
    Process: com.commonsware.android, PID: 18498
    java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
        at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:136)
        at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:116)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:151)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:409)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:298)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:96)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:54)
        at androidx.room.RoomDatabase.query(RoomDatabase.java:238)
        at com.commonsware.android.database.DbDao_Impl.getAllNews(DbDao_Impl.java:190)
        at com.commonsware.android.synchronize_data.SyncNews$GetDbData.run(SyncNews.java:178)
        at java.lang.Thread.run(Thread.java:764)


2021-10-13 11:01:36.869 18498-18498/com.commonsware.android E/WindowManager: android.view.WindowLeaked: Activity com.commonsware.android.SyncActivity has leaked window DecorView@30e5ecf[SyncActivity] that was originally added here
        at android.view.ViewRootImpl.<init>(ViewRootImpl.java:529)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:346)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
        at android.app.Dialog.show(Dialog.java:329)
        at com.commonsware.android.SyncActivity.onCreate(SyncActivity.java:24)
        at android.app.Activity.performCreate(Activity.java:7148)
        at android.app.Activity.performCreate(Activity.java:7139)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2924)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3079)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1836)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6702)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:911)

我的班级:


    public class SyncNews 
    
        private Context context;
    
        private DbRoomDatabase db;
        private DbDao dbDao;
    
        private String JSON_URL_NEWS = "URL for data";
        private Boolean webDataError = false;
        private JSONObject webData;
    
        private List<News> newsDB = null;
        private List<News> newsListAdd = new ArrayList<>();
        private List insertData;
    
        public SyncNews(Context ct) 
    
            context = ct;
            db = DbRoomDatabase.getDatabase(context);
            dbDao = db.dbDao();
    
            GetWebData getWebData = new GetWebData();
            Thread getWebDataThread = new Thread(getWebData);
            getWebDataThread.start();
            while(webDataError == false && getWebDataThread.isAlive()) ;
    
            if(webDataError == false) 
    
                GetDbData getDbData = new GetDbData();
                Thread getDbDataThread = new Thread(getDbData);
                getDbDataThread.start();
                while(getDbDataThread.isAlive()) 
    
                Log.d("TEST", String.valueOf(newsDB));
    
            
        
    
        public void syncWithDb() 
            //synchronize
        
    
        public void InsertData () 
            if (insertData.size() > 0)
                dbDao.insertMultipleNews(insertData);
        
    
        public class GetWebData implements Runnable 
    
            @Override
            public void run() 
                if(!this.getWebData()) 
                    Looper.prepare();
                    webDataError = true;
                    Toast.makeText(context, context.getString(R.string.mess_data_has_not_been_synchronized), Toast.LENGTH_LONG).show();
                    Looper.loop();
                
            
    
            public Boolean getWebData() 
    
                RequestQueue requestQueue = Volley.newRequestQueue(context);
    
                RequestFuture<JSONObject> future = RequestFuture.newFuture();
                JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, JSON_URL_NEWS, new JSONObject(), future, future);
                requestQueue.add(request);
    
                try 
                    webData = future.get();
                    Log.e("getWebData", String.valueOf(request));
                 catch (InterruptedException | ExecutionException e) 
                    if (VolleyError.class.isAssignableFrom(e.getCause().getClass())) 
                        VolleyError ve = (VolleyError) e.getCause();
                        Log.i("getWebData", String.valueOf(ve));
                        if (ve.networkResponse != null) 
                            Log.i("getWebData", String.valueOf(ve.networkResponse));
                            Log.i("getWebData",   String.valueOf(ve.networkResponse.statusCode));
                            Log.i("getWebData", String.valueOf(ve.networkResponse.data));
                        
                    
                    return false;
                
                return true;
            
        
        
    
        public class GetDbData implements Runnable 
    
            @Override
            public void run() 
                newsDB = dbDao.getAllNews();
            
        
    

【问题讨论】:

【参考方案1】:

每次更改数据库的架构/实体类时,您可能需要升级数据库版本

在这种情况下,您似乎需要升级您的数据库版本,您可以在您的数据库类中的@Database(version = xx) 中找到

【讨论】:

感谢您的回复,一般都是通过卸载重装app来解决的。我更担心第二条消息,我只是不知道它是否相关,所以我把它写下来。有趣的是,它在模拟器中运行没有任何问题,但是当我在手机上尝试它时,它会出现 FATAL ERROR。 似乎不能依靠重新安装解决方案。关于第二个日志,您似乎需要检查代码实现是否意外将主上下文(活动/片段)传递给您的 DB 类,您应该使用应用程序上下文而不是 DB 类 在活动中我只将这个类称为线程,但有可能你是对的。 new Thread() @Override public void run() try new SyncNews(getApplicationContext()); catch (Exception e) finally dialog.dismiss(); .start(); 我终于找到了解决方案。只需将 fallbackToDestructiveMigration() 与 Room.databaseBuilder 一起使用。 fallbackToDestructiveMigration() 不适合在生产代码中使用,一旦您更改数据库架构,它将删除整个数据库。当您更改生产代码的架构时,您应该添加迁移。

以上是关于Android Studio - 线程完成后从 SQLite 获取数据的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio 内存泄漏活动未在线程中完成

ubuntu安装Android Studio开发环境

Android Studio 线程调试

android studio 2018.4.17 进程和线程

如何创建一个新线程,Android Studio?

Android Studio学习随笔-UI线程阻塞以及优化