2017-05-10 78 views
0

我目前正试图将我保存到我的MySQLite数据库的图像加载到RecyclerView中。从uri载入图像android

用于RecyclerViewAdapter的代码:

public void onBindViewHolder(MyCatchesAdapter.MyViewHolder holder, int position) { 
    MyCatch myCatch = myCatchArrayList.get(position); 
    holder.txtName.setText(myCatch.get_name()); 
    holder.txtLocation.setText(myCatch.get_location()); 
    holder.txtDate.setText(myCatch.get_date()); 

    holder.catchImage.setImageURI(Uri.parse(myCatch.get_catchImage())); 
} 

所有数据加载到除图像回收站视图。我从logcat的以下

Unable to open content: content://com.android.externalstorage.documents/document/primary%3ADownload%2Fsunrise.png 

java.lang.SecurityException: Permission Denial: opening provider com.android.externalstorage.ExternalStorageProvider from ProcessRecord 
{ee1a504 28074:com.example.pavlos.myproject/u0a74} (pid=28074, uid=10074) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS 

我的清单权限是:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/> 

是否有我缺少的东西吗?

编辑: 我如何得到URI:

catchImage.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      Intent intent = new Intent(); 
      intent.setType("image/*"); 
      intent.setAction(Intent.ACTION_GET_CONTENT); 
      startActivityForResult(Intent.createChooser(intent, 
        "Select Picture"), SELECT_PICTURE); 
     } 
    }); 

public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if (resultCode == RESULT_OK) { 
     if (requestCode == SELECT_PICTURE) { 
      Uri selectedImageUri = data.getData(); 
      selectedImagePath = getPath(selectedImageUri); 
      catchImage.setImageURI(selectedImageUri); 
      imagePath = selectedImageUri; 
      Log.d("imagePath","URI "+selectedImageUri); 
     } 
    } 
} 
public String getPath(Uri uri) { 
    // just some safety built in 
    if(uri == null) { 
     // TODO perform some logging or show user feedback 
     return null; 
    } 
    // try to retrieve the image from the media store first 
    // this will only work for images selected from gallery 
    String[] projection = { MediaStore.Images.Media.DATA }; 
    Cursor cursor = managedQuery(uri, projection, null, null, null); 
    if(cursor != null){ 
     int column_index = cursor 
       .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 
     cursor.moveToFirst(); 
     String path = cursor.getString(column_index); 
     cursor.close(); 
     return path; 
    } 
    // this is our fallback here 
    return uri.getPath(); 
} 
+0

的秘密被称作运行时权限https://developer.android.com/training/permissions/requesting.html – Opiatefuchs

+0

@Opiatefuchs:其实,我怀疑,在这种情况下。 – CommonsWare

+0

@pavlos:你究竟是怎么得到原来的'Uri'的? 'ACTION_GET_CONTENT'? 'ACTION_OPEN_DOCUMENT'?还有别的吗? – CommonsWare

回答

2

首先,getPath()是完全错误的。充其量,它将适用于从MediaStore返回的图像的一些子集。完全摆脱它。使用an image-loading library填充您的ImageView

就你的问题而言,你从ACTION_GET_CONTENT得到的Uri可以被你的活动使用,只要该活动实例在附近。当且仅当您包含FLAG_GRANT_READ_URI_PERMISSION时,您才可以将该Uri传递给其他组件(例如,其他活动)。一旦你的程序终止,你将失去访问内容的所有权利。因此,请停止将Uri保留到数据库,或切换到ACTION_OPEN_DOCUMENT并持久保留Uri权限。

+0

我改变将ACTION_GET_CONTENT转换为ACTION_OPEN_DOCUMENT并加载。我应该仍然摆脱'getPath()'功能? – pavlos

+0

@pavlos:是的,因为它不可靠工作。 – CommonsWare

0

看起来像你所得到的图像URI(通常是从画廊),这将被看作一个内容URI(内容://)。这个内容URI带有临时权限,当它丢失当前上下文时会丢失。因此,下次加载URI时,您可能没有权限在当前上下文中加载它。

我建议你存储在数据库中的图像内容,并在需要时加载它。可以应用各种图像优化,如图像压缩。您也可以查看这个Glide图书馆的图片管理,这是Google推荐的。