1

私は数ヶ月前にこの問題を抱えていましたが、今はそれに戻る時が来ました.

電話の通話履歴をデータベースに照会しますが、テーブルにデータを入力するのに約 30 秒かかります。クエリには約 1 秒かかるように見えますが、電話機には最後の 500 コールのみが保存されますが、データの取り込みには永遠にかかります。なぜそんなに遅いのですか?私は何か間違ったことをしていますか?

エミュレータのコールログには 8 つの項目しかないため、電話でのみテストします。

  final String[] projection = null;

            HotOrNot infoA = new HotOrNot(Charts.this);
            infoA.open();
            infoA.createtable_Calls();
            infoA.deleteAllEntries_Calls();
            infoA.close();

            final Context context = getApplicationContext();
            final String selection = null;
            final String sortOrder = android.provider.CallLog.Calls.DATE + " DESC";

            Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, projection, selection, null, sortOrder);
            while (c.moveToNext()) { 
                String callLogID = c.getString(c.getColumnIndex(android.provider.CallLog.Calls._ID));

                int numberColumn = c.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
                int dateColumn = c.getColumnIndex(android.provider.CallLog.Calls.DATE);
                int typeColumn = c.getColumnIndex(android.provider.CallLog.Calls.TYPE);
                int durationColumn = c.getColumnIndex(android.provider.CallLog.Calls.DURATION);
                int person = c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);



                String number = c.getString(numberColumn);
                int duration = c.getInt(durationColumn);
                String personname = c.getString(person);
                long callDate = c.getLong(dateColumn);
                int callType = c.getInt(typeColumn);

                if (duration >= 0)
                {
                    switch (callType) {
                    case 1:
                        duration_in = duration;
                        duration_out = 0;
                        break;
                    case 2:
                        duration_out = duration;
                        duration_in = 0;
                        break;
                    case 3:
                        duration_in = 0;
                        duration_out = 0;
                        break;


                    }
                    }

    //Here comes the slow part

                    HotOrNot info = new HotOrNot(Charts.this);
                    info.open();
                    info.pop   
ulate_Calls(personname, number, String.valueOf(callType), Integer.toString(duration), Long.toString(callDate), callLogID);
                info.close();   
             }

これは入力関数です。

public long populate_Calls(String name, String phone, String type, String duration, String date, String contactid) {
        ContentValues cv = new ContentValues();
        cv.put(KEY_NAME, name);
        cv.put(KEY_PHONE, phone);
        cv.put(KEY_TYPE, type);
        cv.put(KEY_DURATION, duration);
        cv.put(KEY_DATE, date);
        cv.put(KEY_CONTACTID, contactid);
        return ourDatabase.insert(DATABASE_TABLE, null, cv);        
    }

編集

Andreas Ka と twaddington の回答に対して、SQLiteOpenHelper クラスの人口メソッドを変更しましたが、残念ながら違いはありませんでした。

public long populate_Calls(String name, String phone, String type, String duration, String date, String contactid) {
    ContentValues cv = new ContentValues();
     try {
         ourDatabase.beginTransaction();

         cv.put(KEY_NAME, name);
         cv.put(KEY_PHONE, phone);
         cv.put(KEY_TYPE, type);
         cv.put(KEY_DURATION, duration);
         cv.put(KEY_DATE, date);
         cv.put(KEY_CONTACTID, contactid);

         ourDatabase.yieldIfContendedSafely();

         ourDatabase.setTransactionSuccessful();
     } finally {
         ourDatabase.endTransaction();
     }

    return ourDatabase.insert(DATABASE_TABLE, null, cv);        
}

EDIT2: Babibu と twaddington の回答に基づいてコード全体を投稿します。ちなみに、temp_arrays は LinkedLists になりましたが、時間の違いはありません。

 final String[] projection = null;
        final Context context = getApplicationContext();
        final String selection = null;
        final String sortOrder = android.provider.CallLog.Calls.DATE + " DESC";
        lv1 = (ListView) findViewById(R.id.ListView02); 


        HotOrNot infoA = new HotOrNot(Calllogs.this);
        infoA.open();
        infoA.createtable_Calls();
        infoA.deleteAllEntries_Calls();
        infoA.close();

          pd = ProgressDialog.show(Calllogs.this, "Please wait..", "Loading data, it may take a few" +
                " seconds based on the number of data.", false, true);

        Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, projection, selection, null, sortOrder);
        while (c.moveToNext()) { 
            String callLogID = c.getString(c.getColumnIndex(android.provider.CallLog.Calls._ID));

            int numberColumn = c.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
            int dateColumn = c.getColumnIndex(android.provider.CallLog.Calls.DATE);
            int typeColumn = c.getColumnIndex(android.provider.CallLog.Calls.TYPE);
            int durationColumn = c.getColumnIndex(android.provider.CallLog.Calls.DURATION);
            int person = c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);



            String number = c.getString(numberColumn);
            int duration = c.getInt(durationColumn);
            String personname = c.getString(person);
            long callDate = c.getLong(dateColumn);
            int callType = c.getInt(typeColumn);

            if (duration >= 0)
            {
                switch (callType) {
                case 1:
                    duration_in = duration;
                    duration_out = 0;
                    break;
                case 2:
                    duration_out = duration;
                    duration_in = 0;
                    break;
                case 3:
                    duration_in = 0;
                    duration_out = 0;
                    break;
                }
            }

            temp_name.add(personname);
            temp_num.add(number);
            temp_type.add(String.valueOf(callType));
            temp_dur.add(Integer.toString(duration));
            temp_date.add(String.valueOf(callDate));
            temp_id.add(callLogID);
          } //end of while loop


        HotOrNot infotemp = new HotOrNot(Calllogs.this);
        infotemp.open();


            for (int i=0; i<temp_name.size(); i++)
            {
                infotemp.populate_Calls(temp_name.get(i), temp_num.get(i), temp_type.get(i), temp_dur.get(i), temp_date.get(i), temp_type.get(i));
            }
 infotemp.close();

解決

私は twaddington のソリューションを投稿しています。これにより、時間が 8 秒から 2 秒未満に短縮されました。

 HotOrNot infotemp = new HotOrNot(Calllogs.this);
        infotemp.open();

        // Get our database. You can do this however you wish, but
        // it seems like since the database is contained in your `HotOrNot`
        // object, it would be best to simply add a getter method to
        // the class.
        SQLiteDatabase db = infotemp.getDatabase();

        try {
            // Begin our transaction
            db.beginTransaction();

            // Loop over the array of calls and
            // perform a db insert for each.
            for (int i=0; i<temp_name.size(); i++) {
                // Yield the database lock if requested. This will
                // temporarily suspend our loop, but it should
                // continue when the lock is opened.
                db.yieldIfContendedSafely();

                infotemp.populate_Calls(temp_name.get(i), temp_num.get(i),
                        temp_type.get(i), temp_dur.get(i), temp_date.get(i), temp_type.get(i));
            }

            // Mark our transaction as successful!
            db.setTransactionSuccessful();
        } finally {
            // Always end the transaction!
            db.endTransaction();
        }

        infotemp.close();
4

3 に答える 3

2

SQLite データベースに変更を加えるたびに、エラーが発生した場合に変更をロールバックするためのジャーナル ファイルの作成など、一連の複雑な手順が発生します。一連の更新をデータベース トランザクションにラップして、SQLite に一連の更新全体を 1 つの操作として強制的に処理させることができます。これにより、はるかに効率的になります。

try {
    db.beginTransaction();
    while (c.moveToNext()) {
        // Yield the database lock if requested
        db.yieldIfContendedSafely();

        // Add your code here!
        // ...

        // Perform the database insert
        populate_Calls(...);
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
于 2012-05-28T17:19:16.327 に答える
1

メソッド全体で単一のトランザクションを使用してみてください: http://notes.theorbis.net/2010/02/batch-insert-to-sqlite-on-android.html

于 2012-05-28T17:23:46.360 に答える
1

ブラウジング中に挿入すると、データベースがロックされます。最初にwhileループを終了してから、データベースに挿入する必要があります。同じ一時的なリンクされたリストにデータを保持するだけです(あなたの場合は配列よりも優れています。高速に挿入できます)

于 2012-05-28T17:29:20.480 に答える