android - 在新线程中将值插入数据库会导致进度对话框关闭

标签 android multithreading sqlite android-asynctask progressdialog

在我的应用程序中,我从服务器下载了大量数据(大约 3000-4000 条记录),然后将其插入数据库。这个过程需要很长时间,所以我想在整个过程运行时显示进度对话框。我在 AsyncTask 类中实现了进度对话框,我在其中下载数据并将其插入数据库。这是 AsyncTask 的代码:

    @Override
        protected void onPreExecute() {
            super.onPreExecute();
            a.runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    pd.setTitle("Загрузка необходимых данных");
                    pd.setMessage("Пожалуйста подождите");
                    pd.setIndeterminate(true);
                    pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                    pd.setProgress(0);
                    pd.setCancelable(false);
                    pd.show();
                }
            });

        }

        protected Map<String, String> doInBackground(String... strs) {
                    return getMaterials();
        }

        @Override
        protected void onPostExecute (Map<String, String> map) {
            a.runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    pd.dismiss();
                }
            }); 
        }

public Map<String,String> getMaterials() {
        int maxNum = getMaxIndex("materials");
        Map<String,String> materials = null;
        DBConnection db = new DBConnection(context);
        Date end = new Date(System.currentTimeMillis());
        String exml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" +
                "<REQUEST format=\"json\" client=\"exstroy\" action=\"get\" enddate=\""+ end.toString() + "\" " +
                "startdate=\"2000-01-28\" POINT_ID=\"3\" session=\"" + session_id + "\" catalogname=\"nomenclature\" type=\"cataloglist\">" +
                "<LIST firstmrid = \"0\" lastmrid=\""+ maxNum + "\"></LIST>"  +
                "</REQUEST>";
        try{
            PrintWriter writer = new PrintWriter(Environment.getExternalStorageDirectory().getPath() + "/data.xml", "UTF-8");
            writer.println(exml);
            writer.close();
        } catch (IOException e) {
        }

        String charset = "UTF-8";
        File uploadFile1 = new File(Environment.getExternalStorageDirectory().getPath() + "/data.xml");
        String requestURL = "blahblah.com";

        try {
            MultipartUtility multipart = new MultipartUtility(requestURL, charset);

            multipart.addFilePart("datafile", uploadFile1);

            List<String> response = multipart.finish();


            materials = new HashMap<String, String>();
            String s = "{ " + response.get(1) + "}";
            JSONObject json = new JSONObject(s);
            JSONObject cataloglist = json.getJSONObject("cataloglist");

            JSONArray array = cataloglist.names();
            //db.clearNomenclature();
            ArrayList<Map<String, Object>> data = new ArrayList<Map<String, Object>>(5000);
            int max = 0;
            for(int n = 0; n < array.length(); n++)
            {
                if (n > max)
                    max = n;
                JSONObject object = cataloglist.getJSONObject(array.getString(n));
                Map<String, Object> map;
                map = new HashMap<String, Object>();
                if (object.has("version"))
                    map.put("version", object.getInt("version"));
                else
                    map.put("version", 0);
                if (object.has("name"))
                    map.put("name", object.getString("name"));
                else
                    map.put("name", "");
                if (object.has("uuid"))
                    map.put("uuid", object.getString("uuid"));
                else
                    map.put("uuid", "");
                if (object.has("uuid"))
                    map.put("measure", object.getString("measure"));
                else
                    map.put("measure", "");

                data.add(map);

                }
          db.insertNom(data);
        } catch (IOException ex) {
            System.err.println(ex);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        ArrayList<Map<String, String>> measures = getMeasures();
        db.measures(measures);
        return materials;
    }

在执行下载数据时会显示进度对话框,但当它到达数据库插入进度对话框时会被关闭。下面是数据库插入的部分代码:

public void insertNom(final ArrayList<Map<String, Object>> data) {
        dbOpen();
        database.execSQL("CREATE TABLE IF NOT EXISTS "+"nomenclature"+
                " ("+"ID"+" INTEGER PRIMARY KEY AUTOINCREMENT, "+
                "name TEXT, version INTEGER, measure UUID, uuid UUID)");
        dbClose();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < data.size(); i++) {
                    dbOpen();
                    Map<String, Object> map = data.get(i);
                    ContentValues cv = new ContentValues();
                    cv.put("name", (String) map.get("name"));
                    cv.put("version", (int) map.get("version"));
                    cv.put("uuid", (String) map.get("uuid"));
                    cv.put("measure", (String) map.get("measure"));
                    database.insert("nomenclature", null, cv);
                    dbClose();
                }
            }
        };
        new Thread(runnable).start();

    }

我尝试在单独的线程中执行此操作,如您在上面的代码中所见,我也尝试仅在 AsyncTask 的 doInBackgroung 方法中执行此操作。两种方式都关闭了进度对话框。另外还有一个问题,虽然从服务器下载数据比较快:3-4秒,插入数据库大约需要20秒,甚至更多。有什么办法可以更快吗?如果不是,是什么导致进度对话框关闭?

最佳答案

需要将大约 3000-4000 条记录插入表中。执行以下更改以加快插入速度:

1. 如果数据直接从 JSON 插入到表中,则无需在 HashMap 中保存 JSONObject。只需使用 JsonReader 即可读取 JSON 编码值作为标记流。并为每个对象调用插入方法。 (可选,但如果您在当前代码中这样做,那么它也会减少读取和打包集合中数据的时间)

2. 仅使用 doInBackground 并从 insertNom 方法中删除 Thread。

3.doInBackground 中使用 Android 数据库事务进行批量插入。喜欢:

   protected Map<String, String> doInBackground(String... strs) {
        // 1. Open DB
        // 2. Create Table 

         Map<String, String> materials=getMaterials();

        // 3.
        // START Transaction
           database.beginTransaction();

         //call insertNom method
           insertNom(materials);

         // set Successful
         database.setTransactionSuccessful();

          // END Transaction 
         database.endTransaction();

         return materials;
    }

关于android - 在新线程中将值插入数据库会导致进度对话框关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41297076/

相关文章:

iphone - 简单的 iOS 应用程序的数据存储方法是什么?

Android getParent() 为 null 但已设置 parentActivityName

java - 如何在 Java 中查找 CPU 密集型类?

c++:通过 promise 打包任务

c++ - 使用 4 个线程获取/释放语义

android - 浏览 Android SQLite 数据库中的数据

Android SQLiteDatabase空指针异常

Android:每次单击抽屉导航项时创建一个新 fragment 更好还是加载以前创建的 fragment ?

java - Android studio - 努力从应用程序 Assets 共享图像/音频/视频文件

android - 使用游标适配器和加载器时动态编辑 ListView 项