2014-03-04 68 views
5

我搜索並搜索到,但尚未找到解決方案。希望這裏有人能幫忙。嘗試插入時拋出SQLiteConstraintException

我試圖插入MediaStore.Audio.Media.EXTERNAL_CONTENT_URI自定義鈴聲。 大多數情況下,它的工作效果很好,但偶爾會在調用getContentResolver()。insert()時引發SQLiteConstraintException。拋出異常是因爲具有唯一列(_data)的記錄已經存在於該表中的特定值。 但是,當我然後嘗試使用_data作爲where子句獲取該記錄時,返回null。

因此,在我看來,有多個表在這裏被檢查,現有的相同_data列的記錄是某種關聯的表格,當我使用MediaStore.Audio.Media.EXTERNAL_CONTENT_URI 。

所以,我的問題是,如果是這樣,有沒有辦法清除這些孤兒記錄? 或者有沒有辦法確定這個重複值在哪個表中,以便我可以手動刪除它? 也許某種類型的文件表?

另外,也許我完全錯誤的假設。 任何幫助真的很感激。

這裏有保存鈴聲

ContentValues mediaValues = new ContentValues(); 
mediaValues.put(MediaStore.MediaColumns.DATA, filename.toString()); 
mediaValues.put(MediaStore.MediaColumns.TITLE, speakTextTxt); 
mediaValues.put(MediaStore.MediaColumns.DISPLAY_NAME, speakTextTxt); 
mediaValues.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg3"); 
mediaValues.put(MediaStore.MediaColumns.SIZE, filename.length()); 
mediaValues.put(MediaStore.Audio.Media.ARTIST, appName); 
mediaValues.put(MediaStore.Audio.Media.IS_RINGTONE, true); 
mediaValues.put(MediaStore.Audio.Media.IS_NOTIFICATION, true); 
mediaValues.put(MediaStore.Audio.Media.IS_ALARM, true); 
mediaValues.put(MediaStore.Audio.Media.IS_MUSIC, false); 

ringtoneUri = getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mediaValues); 

在上面ringtoneUri的代碼發生此問題時爲空。

這裏被拋出

03-04 13:18:16.522 24774-23075/? E/SQLiteDatabase﹕ Error inserting bucket_id=1420360973 media_type=2 storage_id=65537 date_modified=1393450056 is_alarm=true is_ringtone=true parent=22388 format=12297 artist_id=90 is_music=false bucket_display_name=Ringtones album_id=161 title=German gorilla is_notification=true title_key= 3 / I ? ' A  3 C I 7 = = ' mime_type=audio/mpeg3 date_added=1393967896 _display_name=German_gorilladeuDEUcomgoogleandroidtts-75868.mp3 _size=32044 _data=/storage/emulated/0/Android/data/com.twoclaw.typeyourringtonepro/files/Ringtones/German_gorilladeuDEUcomgoogleandroidtts-75868.mp3 
android.database.sqlite.SQLiteConstraintException: column _data is not unique (code 19) 
     at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method) 
     at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:782) 
     at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788) 
     at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86) 
     at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1469) 
     at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1339) 
     at com.android.providers.media.MediaProvider.insertFile(MediaProvider.java:3199) 
     at com.android.providers.media.MediaProvider.insertInternal(MediaProvider.java:3439) 
     at com.android.providers.media.MediaProvider.insert(MediaProvider.java:2851) 
     at android.content.ContentProvider$Transport.insert(ContentProvider.java:220) 
     at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:156) 
     at android.os.Binder.execTransact(Binder.java:404) 
     at dalvik.system.NativeStart.run(Native Method) 

我看不到任何與失敗的有所不同,但也許他們已經部分地在某一點插入異常。

試圖讓這個紀錄再回來空

String[] projection = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns._ID}; 
String[] selectionArgs = {filename.toString()}; 
Cursor existingTone = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, MediaStore.MediaColumns.DATA+"=?", selectionArgs, null); 

if (existingTone.getCount() > 0)...

文件並在_data列

希望這解釋了事情所示的位置存在是假的。 在此先感謝!

+0

我想我難倒大家:)我已經把周圍的工作現在,但我仍然試圖找出這一個。 – Trees

回答

1

「也許某種類型的文件表?」

你太親近了! MediaStore.Files正是你要找的。你會發現Android已經在SD卡上索引了的所有內容(即使.nomedia目錄,這是完全不直觀的)。試圖重新插入記錄將導致SQLiteContraintException(我認爲僅在API級別19上,因爲並不總是需要唯一性_data)。還要注意的是MediaStore.Files是在API層面新11

注:有一個簡單的選擇,那就是MediaScannerConnection,但我沒有用它,所以我不知道應該如何表現比較直接添加它到MediaStore。

無論如何,我要支持到API第7級一路,所以這是我如何解決它:

Uri findAudioFileUri(File filename) { 
    // SDK 11+ has the Files store, which already indexed... everything 
    // We need the file's URI though, so we'll be forced to query 
    if (Build.VERSION.SDK_INT >= 11) { 
     Uri uri = null; 

     Uri filesUri = MediaStore.Files.getContentUri("external"); 
     String[] projection = {MediaStore.MediaColumns._ID, MediaStore.MediaColumns.TITLE}; 
     String selection = MediaStore.MediaColumns.DATA + " = ?"; 
     String[] args = {filename.getAbsolutePath()}; 
     Cursor c = ctx.getContentResolver().query(filesUri, projection, selection, args, null); 

     // We expect a single unique record to be returned, since _data is unique 
     if (c.getCount() == 1) { 
      c.moveToFirst(); 
      long rowId = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID)); 
      String title = c.getString(c.getColumnIndex(MediaStore.MediaColumns.TITLE)); 
      c.close(); 
      uri = MediaStore.Files.getContentUri("external", rowId); 

      // Since all this stuff was added automatically, it might not have the metadata you want, 
      // like Title, or Artist, or IsRingtone 
      if (!title.equals(DESIRED_TITLE)) { 
       ContentValues values = new ContentValues(); 
       values.put(MediaStore.MediaColumns.TITLE, DESIRED_TITLE); 

       if (ctx.getContentResolver().update(toneUri, values, null, null) != 1) { 
        throw new UnsupportedOperationException(); // update failed 
       } 

       // Apparently this is best practice, although I have no idea what the Media Scanner 
       // does with the new data 
       ctx.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, toneUri)); 
      } 
     } 
     else if (c.getCount() == 0) { 
      // I suppose the MediaScanner hasn't run yet, we'll insert it 
      ... ommitted 
     } 
     else { 
      throw new UnsupportedOperationException(); // it's expected to be unique! 
     } 

     return uri; 
    } 
    // For the legacy way, I'm assuming that the file we're working with is in a .nomedia 
    // folder, so we are the ones who created it in the MediaStore. If this isn't the case, 
    // consider querying for it and updating the existing record. You should store the URIs 
    // you create in case you need to delete them from the MediaStore, otherwise you're a 
    // litter bug :P 
    else { 
     ContentValues values = new ContentValues(); 
     values.put(MediaStore.MediaColumns.DATA, path.getAbsolutePath()); 
     values.put(MediaStore.MediaColumns.SIZE, path.length()); 
     values.put(MediaStore.MediaColumns.DISPLAY_NAME, path.getName()); 
     values.put(MediaStore.MediaColumns.TITLE, DESIRED_TITLE); 
     values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mpeg3"); 
     values.put(MediaStore.Audio.Media.ARTIST, appName); 
     values.put(MediaStore.Audio.Media.IS_RINGTONE, true); 
     values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true); 
     values.put(MediaStore.Audio.Media.IS_ALARM, true); 
     values.put(MediaStore.Audio.Media.IS_MUSIC, false); 

     Uri newToneUri = ctx.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values); 

     // Apparently this is best practice, although I have no idea what the Media Scanner 
     // does with the new data 
     ctx.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newToneUri)); 

     return newToneUri; 
    } 
} 
+0

這部分代碼ctx.sendBroadcast(新意圖(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,toneUri));如果該文件不是外部sdcard,則不起作用。如果它位於內部sdcard上,則工作。 – Ahmed

0

我已經找到解決方案適合我。它適用於我測試過的所有設備,甚至是android 4.3(API 19)。 爲了避免「列_數據不唯一(代碼19)」問題,更好地執行刪除行並再次插入它。它分別用於視頻和音頻文件。這裏是我的代碼:

   if(gd.getContentType() == ContentType.Video){ 
        ContentValues content = new ContentValues(4); 
         content.put(MediaStore.Video.VideoColumns.TITLE, filename); 
         content.put(MediaStore.Video.VideoColumns.DATE_ADDED, 
           System.currentTimeMillis()/1000); 
         content.put(MediaStore.Video.Media.MIME_TYPE, "video/"+fileext); 
         content.put(MediaStore.Video.Media.DATA, gd.url); 
         Uri uri2 = context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, content); 


         Log.i(TAG, "=refresh scan new file inserted video uri="+uri2); 
         if(uri2 != null){ 
          uri_video = uri2; 
          //context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri_video)); 
         }else{ 

          Uri filesUri = MediaStore.Files.getContentUri("external"); 
          String[] projection = {MediaStore.MediaColumns._ID, MediaStore.MediaColumns.TITLE}; 
          String selection = MediaStore.MediaColumns.DATA + " = ?"; 
          String[] args = {gd.url}; 
          Cursor c = context.getContentResolver().query(filesUri, projection, selection, args, null); 

          // We expect a single unique record to be returned, since _data is unique 
          if (c.getCount() == 1) { 
           c.moveToFirst(); 
           long rowId = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID)); 
           String title = c.getString(c.getColumnIndex(MediaStore.MediaColumns.TITLE)); 
           c.close(); 
           uri2 = MediaStore.Files.getContentUri("external", rowId); 
           Log.i(TAG, "=refresh scan force uri2="+uri2); 

           if(uri2 != null){ 
            //context.getContentResolver().update(uri2, content, null, null); 
            context.getContentResolver().delete(uri2, null, null); 
            uri2 = context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, content); 
            if(uri2 != null){ 
             uri_video = uri2; 
            } 
           } 
          } 

         } 
       }else{ 
        ContentValues content = new ContentValues(4); 
         content.put(MediaStore.Audio.AudioColumns.TITLE, "audio"+filename); 
         content.put(MediaStore.Audio.AudioColumns.DATE_ADDED, 
           System.currentTimeMillis()/1000); 
         content.put(MediaStore.Audio.Media.MIME_TYPE, "audio/"+fileext); 
         content.put(MediaStore.Audio.Media.DATA, gd.url); 
         Uri uri2 = context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, content); 


         Log.i(TAG, "=refresh scan new file inserted audio uri="+uri2); 
         if(uri2 != null){ 
          uri_audio = uri2; 
          //context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri_audio)); 
         }else{ 

          Uri filesUri = MediaStore.Files.getContentUri("external"); 
          String[] projection = {MediaStore.MediaColumns._ID, MediaStore.MediaColumns.TITLE}; 
          String selection = MediaStore.MediaColumns.DATA + " = ?"; 
          String[] args = {gd.url}; 
          Cursor c = context.getContentResolver().query(filesUri, projection, selection, args, null); 

          // We expect a single unique record to be returned, since _data is unique 
          if (c.getCount() == 1) { 
           c.moveToFirst(); 
           long rowId = c.getLong(c.getColumnIndex(MediaStore.MediaColumns._ID)); 
           String title = c.getString(c.getColumnIndex(MediaStore.MediaColumns.TITLE)); 
           c.close(); 
           uri2 = MediaStore.Files.getContentUri("external", rowId); 
           Log.i(TAG, "=refresh scan force audio uri2="+uri2); 

           if(uri2 != null){ 
            //context.getContentResolver().update(uri2, content, null, null); 
            context.getContentResolver().delete(uri2, null, null); 
            uri2 = context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, content); 
            if(uri2 != null){ 
             uri_audio = uri2; 
            } 
           } 
          } 


         } 
       } 
     if(uri_video != null) 
      context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri_video)); 
     if(uri_audio != null) 
      context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri_audio)); 
相關問題