Android Java JSON解析器/插入数据库优化

时间:2012-02-16 14:26:44

标签: android json sqlite optimization

我不确定这个问题是否在这里,但我想问你们所有人,他们真的可以给我一些如何优化这段代码的建议,以正确的方式运行得更好快点。我正在做的事情是我通过互联网下载数据作为JSON,解析它并将其插入sqlite数据库。如果json字符串不大,对我来说没有什么大问题,但是当我的json在某些情况下包含很多数组和对象时,我等待10-13分钟来下载/解析/插入数据库中的所有数据,这是太多的时间。

我展示的代码是某种测试代码,因为我试图实现InsertHelper以查看速度是否会有一点差异,但结果现在是相同的。这是代码:

    UserDatabaseHelper userDbHelper = RPCCommunicator.rpcUserDbHelper;

    SQLiteDatabase db = userDbHelper.getWritableDatabase();
    InsertHelper ih = new InsertHelper(db, "cards");

    ih.prepareForInsert();
    //ContentValues values = new ContentValues();
    ContentValues valuess = new ContentValues();
    try {
        int objectid = ih.getColumnIndex("objectId");
        ih.bind(objectid, objectId);
        //values.put("objectId", objectId);
        Log.d("", "ObjectId: " + objectId);
        int objectoid = ih.getColumnIndex("objectOid");
        ih.bind(objectoid, objectOid);
        //values.put("objectOid", objectOid);

        String jsonData = new String(cardBuffer, "UTF-8");
        Log.d("JSONDATA", "JSONDATA VALID OR NOT : " + jsonData);
        json = new JSONObject(jsonData);
        JSONObject jsonObj = (JSONObject) new JSONTokener(jsonData).nextValue();

        int collectionID = ih.getColumnIndex("collectionId");
        int collectionId = Integer.parseInt(jsonObj.optString("collection_id","0"));
        Log.d("Collection Id ", "Show Collection Id : " + collectionId);
        if(collectionId!=0)
            ih.bind(collectionID, collectionId);

        //values.put("collectionId", collectionId);

        int categoryID = ih.getColumnIndex("categoryId");
        int categoryId = Integer.parseInt(jsonObj.optString("category_id", "0"));
        Log.d("Category Id ", "Show Category Id : " + categoryId);
        if(categoryId!=0)
            ih.bind(categoryID, categoryId);
        //values.put("categoryId", categoryId);

        int dateCreated = ih.getColumnIndex("dateCreated");
        String date = jsonObj.optString("date_created");
        if(date!=null)
            ih.bind(dateCreated, date);
        //values.put("dateCreated", date);

        int titlee = ih.getColumnIndex("title");
        String title = jsonObj.optString("title");
        Log.d("Title", "Show Title : " + title);
        if(title!=null)
            ih.bind(titlee, title);
        //values.put("title", title);

        // ... some other variables to get from JSON

        JSONObject stats = jsonObj.optJSONObject("statistics");

        if (jsonObj.has("statistics")) {
            ContentValues values2 = new ContentValues();
            InsertHelper ihr = new InsertHelper(db, "cardstats");


            Iterator<Object> keys = stats.keys();
            while (keys.hasNext()) {

                ihr.prepareForInsert();
                String key = (String) keys.next();
                JSONObject obj = new JSONObject();
                obj = stats.getJSONObject(key);

                int paramId = Integer.parseInt(obj.optString("param_id"));

                int cardIdTable = ihr.getColumnIndex("cardId");
                ihr.bind(cardIdTable, objectId);

                values2.put("cardId", objectId);

                int statKey = ihr.getColumnIndex("statKeyId");
                ihr.bind(statKey, paramId);

                values2.put("statKeyId", paramId);

                int catIdTable = ihr.getColumnIndex("catId");
                int catId = Integer.parseInt(obj.optString("cat_id"));
                ihr.bind(catIdTable, catId);

                values2.put("catId", catId);

                int paramtitle = ihr.getColumnIndex("title");
                String paramTitle = obj.optString("param_title");
                ihr.bind(paramtitle, paramTitle);

                values2.put("title", paramTitle);

                String cardstats = "SELECT cardId , statKeyId FROM cardstats WHERE cardId="+objectId+" AND statKeyId="+catId;
                Cursor cardStats = userDbHelper.executeSQLQuery(cardstats);
                if(cardStats.getCount()==0){
                    //userDbHelper.executeQuery("cardstats", values2);
                    ihr.execute();
                } else {
                    for(cardStats.moveToFirst(); cardStats.moveToNext(); cardStats.isAfterLast()){
                        //int card = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("cardId")));
                        int statId = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("statKeyId")));

                        if(paramId != statId){
                            ihr.execute();
                            //userDbHelper.executeQuery("cardstats", values2);
                        } else {
                            userDbHelper.updateSQL("cardstats", values2, "cardId=?", new String[]{Integer.toString(objectId)});
                        }
                    }
                }
                cardStats.close();

                //userDbHelper.executeQuery("cardstats", values2);
            }
        }// end if

        String sql = "SELECT objectId FROM cards WHERE objectId = " + objectId;
        Cursor cursor = userDbHelper.executeSQLQuery(sql);
        if (cursor.getCount() == 0) {
            ih.execute();
            //userDbHelper.executeQuery("cards", values);
        } else {
            for (cursor.move(0); cursor.moveToNext(); cursor.isAfterLast()) {
                int objectID = Integer.parseInt(cursor.getString(cursor.getColumnIndex("objectId")));
                Log.d("","objectId : objectID - "+objectId+"    "+objectID );
                if (objectId != objectID) {
                    ih.execute();
                    //userDbHelper.executeQuery("cards", values);
                } else if(objectId == objectID){
                    userDbHelper.updateSQL("cards", valuess, "objectId=?", new String[] {Integer.toString(objectId)});
                }
            }
        }
        cursor.close();

    } catch (Exception e) {
        e.printStackTrace();
        Log.d("Error",  ": " + e);
    }
    db.close();
    return true;
}

* 修改:*

以下是我如何保存从互联网上获取的二进制数据(图像):

public static void saveToExternalStorage(String servername, int userId, String  filename, byte[] buffer){
    try {
        File myDir=new File("/sdcard/.Stampii/Users/"+servername+"/"+userId+"/Storage");
        myDir.mkdirs();

        File file = new File(myDir, filename);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(buffer);
        fos.flush();
        fos.close();

    } catch (FileNotFoundException e){
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

所以欢迎任何类型的建议/建议,这将有助于我改进这段代码并使其运行得更快。

提前致谢!

2 个答案:

答案 0 :(得分:2)

即使您拥有大量HTTP流量(您似乎拥有),您仍然可以优化数据库的使用。

这个做出10000次插入的天真例子将向您展示我们在这里谈论的改进规模:

public class BombasticActivity extends Activity {
    DBHelper mHelper;
    SQLiteDatabase mDb;
    InsertHelper mInsertHelper;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mHelper = new DBHelper(this);
        mDb = mHelper.getWritableDatabase();
        mInsertHelper = new InsertHelper(mDb, "table1");
    }
    @Override
    protected void onStart() {
        super.onStart();
        AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new Insert(10000, mInsertHelper)));
        AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new DoInTransaction(mDb, new Insert(10000, mInsertHelper))));
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mInsertHelper.close();
        mDb.close();
        mHelper.close();
    }
    static class MeasureTime implements Runnable {
        final Runnable mAction;
        MeasureTime(Runnable action) {
            mAction = action;
        }
        public void run() {
            final String name = mAction.getClass().getSimpleName();
            System.out.println("Starting action (" + name + ")");
            long t0 = System.currentTimeMillis();
            try {
                mAction.run();
            } finally {
                t0 = System.currentTimeMillis() - t0;
                System.out.println("Time to complete action (" + name + "): " + t0 + "ms");
            }
        }
    }
    static class DoInTransaction implements Runnable {
        final Runnable mAction;
        final SQLiteDatabase mDb;
        DoInTransaction(SQLiteDatabase db, Runnable action) {
            mAction = action;
            mDb = db;
        }
        public void run() {
            mDb.beginTransaction();
            try {
                mAction.run();
                mDb.setTransactionSuccessful();
            } finally {
                mDb.endTransaction();
            }
        }
    }
    static class Insert implements Runnable {
        final int mNumberOfInserts;
        final InsertHelper mInsertHelper;
        Insert(int numberOfInserts, InsertHelper insertHelper) {
            mNumberOfInserts = numberOfInserts;
            mInsertHelper = insertHelper;
        }
        public void run() {
            Random rnd = new Random(0xDEADBEEF);
            ContentValues values = new ContentValues();
            for (int i = 0; i < mNumberOfInserts; i++) {
                values.put("text1", String.valueOf(rnd.nextDouble()));
                values.put("text2", String.valueOf(rnd.nextFloat()));
                values.put("text3", String.valueOf(rnd.nextLong()));
                values.put("int1", rnd.nextInt());
                mInsertHelper.insert(values);
                if (i % 200 == 0) {
                    System.out.println("Done " + i + " inserts");
                }
            }
        }
    }
}

class DBHelper extends SQLiteOpenHelper {
    DBHelper(Context context) {
        super(context.getApplicationContext(), "bombastic", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE table1 (_id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT, text3 TEXT, int1 INTEGER)");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}

在ICS设备上(如果启动线程或线程池而不是滥用AsyncTask.SERIAL_EXECUTOR,可以在Gingerbread上运行)非事务版本需要将近4分钟才能完成(229484ms) )在事务中运行的版本只需要大约3秒(2975毫秒)。

所以很快就把它做,做很多更新 - 在交易中做。

要优化HTTP,您应该确保保持HTTP连接处于活动状态(保持活动状态)并下载更大的块。比您现在正在做的要大得多 - 如果可能的话,切换到支持从流中读取的JSON解析器,而不是在解析之前将整个事物加载到String

答案 1 :(得分:1)

您的案件涉及两项耗时的活动。

一个。下载数据包中的数据(假设它是HTTP)。对于单个数据包,它应该需要大约1-3秒,具体取决于网络延迟。 对于200 = 2X100 = 200秒~3分钟 如果您以不超过3-5次往返呼叫的方式下载整个数据,则可以节省大量秒数。

湾数据库插入 你需要做文件操作专门写文件操作需要时间。老实说,你不能在这里做太多优化

检查我的其他答案here