Оптимизация парсера / вставки базы данных Android Java JSON - PullRequest
0 голосов
/ 16 февраля 2012

Я не совсем уверен, если этот вопрос здесь, но я хочу спросить всех вас, ребята, которые действительно могут дать мне несколько советов о том, как лучше оптимизировать этот кусок кода, чтобы лучше работать должным образом и Быстрее. Дело в том, что я загружаю данные через Интернет в формате 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 ]

2 голосов
/ 16 февраля 2012

Даже если у вас много 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 (вы можете запустить его на Gingerbread, если вместо злоупотребления AsyncTask.SERIAL_EXECUTOR запускаете поток или пул потоков), версия без транзакции занимает почти 4 минуты (229484 мс), в то время как версия, запущенная в транзакции, занимает около 3 секунд (2975 мс).

Короче говоря, делайте много обновлений - делайте это в транзакции.

Чтобы оптимизировать HTTP, вы должны убедиться, что вы поддерживаете соединение HTTP (keep-alive) и загружаете более крупные фрагменты. Гораздо больше, чем те, которые вы делаете сейчас - если возможно, переключитесь на анализатор JSON, который поддерживает чтение из потока, вместо загрузки всей вещи в String перед ее анализом.

1 голос
/ 16 февраля 2012

В вашем деле задействовано два длительных действия.

а. Загрузка данных в пакетах (предполагается, что это HTTP). Для одного пакета это займет у вас около 1-3 секунд в зависимости от задержки сети. Для 200 = 2X100 = 200 секунд ~ 3 минуты Вы можете сэкономить много секунд, если загружаете все данные, скажем, не более 3-5 вызовов в оба конца.

б. Вставка базы данных Вам нужно сделать файловую операцию, а именно записать файловую операцию, которая требует времени. Честно говоря, вы не можете много оптимизации здесь

Проверьте мой другой ответ здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...