android: 操作多媒体文件之图片文件

有时候,我们想在程序内打开图库,从中挑选图片,并复制图片(或移动图片)到本程序关联目录下。在android 4.4版本中的Uri是经过封装的,所以调用起来需要解析路径,比较麻烦。下面是我实践过的调取图片的方法:

一、打开图库

    在打开图库之前,需要动态申请存储空间的访问权限(我的测试手机没有插SD卡)。申请权限之前,一定要先在AndroidManifest.xml中加入这样一条语句(不然无法获得存储空间的访问权限):

放得位置是这样的:

xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.lenovo.testapp">
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
    application>
manifest>

然后,点击按钮动态申请申请存储空间访问权限,如果已经获取权限,可直接打开图库:

@Override
public void onClick(View v){
    switch (v.getId()) {
        case R.id.openalbum:
            /*动态申请访问存储空间的权限*/
            if(ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
            }else{
                openAlbum();
            }
            break;
    }
}
/*
*@description 开启系统相册
*/
private void openAlbum(){
    Intent intent=new Intent("android.intent.action.GET_CONTENT");
    intent.setType("image/*");
    startActivityForResult(intent,1);
}

实现效果如图1所示:

android: 操作多媒体文件之图片文件_第1张图片

                                                              图 1 打开相册

二、获取图片路径

        刚才只是打开了图库,并没有对选择的图片进行任何处理,所以你会发现点击任意一张图片后又回到了前一个界面。现在我们来获取图片的路径。

考虑最后一行代码:startActivityForResult(intent,1);

你可能会好奇startActivityForResult的第二个参数1是干嘛用的,其实1是一个代号,是为了后面处理图片而设的代码。当从相册中选择完图片回到startActivityForResult( )方法时,就会进入onActivityResult( )方法中的1 的case来处理图片。

 
  
@Override
protected void onActivityResult(int requestCode, int resultCode,Intent data) {
    switch (requestCode) {
        case 1:
            if (resultCode == RESULT_OK) {
                //判断手机系统版本号
                if (Build.VERSION.SDK_INT >= 19) {
                    //4.4以上版本使用这个方法处理图片
                    handleMediaOnKitKat(data, CHOOSE_PHOTO);
                } else {
                    //4.4以下系统使用这个方法处理图片
                    handleImageBeforeKitKat(data, CHOOSE_PHOTO);
                }
            }
            break;
    }
}
 
  
/*
*@description 4.4以下版本媒体文件路径的获取
*/
private void handleImageBeforeKitKat(Intent data,int choice){
    Uri uri=data.getData();
    String mediaPath=getMediaPath(uri,null,choice);

}
/*
*@description 4.4版本及以上媒体文件路径的获取
*
*/
@TargetApi(19)
private void handleMediaOnKitKat(Intent data,int choice){
    String mediaPath=null;
    Uri uri=data.getData();
    if(DocumentsContract.isDocumentUri(this,uri)){
        //如果是document类型的Uri,则通过document id处理
        String docId=DocumentsContract.getDocumentId(uri);
        if("com.android.providers.media.documents".equals(uri.getAuthority())){
            String id=docId.split(":")[1];//解析出数字格式的id
            String selection;
            if(choice==CHOOSE_PHOTO){
                selection= MediaStore.Images.Media._ID+"="+id;
                mediaPath=getMediaPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection,choice);
            }
        }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
            Uri contentUri= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
            mediaPath=getMediaPath(contentUri,null,choice);
        }
    }else if("content".equalsIgnoreCase(uri.getScheme())){
        //如果是content类型的Uri,则用普通方式处理
        mediaPath=getMediaPath(uri,null,choice);
    }else if("file".equalsIgnoreCase(uri.getScheme())){
        //如果是file类型的Uri,直接获取文件路径即可
        mediaPath=uri.getPath();
    }

}

/*获取多媒体文件的路径*/
private String getMediaPath(Uri uri,String selection,int choice){
    String path=null;
    Cursor cursor;
    cursor=getContentResolver().query(uri,null,selection,null,null);
    if(cursor!=null){
        if(cursor.moveToFirst()){
            path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        }
        cursor.close();
    }
    String splitarr[]=path.split("/");
    if(choice==CHOOSE_PHOTO);
        image_name=path.split("/")[splitarr.length-1];
    //将text的值设为路径。这里要先将text变量设为全局的,以便在不同的方法中调用。
    text.setText(path);
    return path;
}
 
  

效果如下图所示:

android: 操作多媒体文件之图片文件_第2张图片

当然,如果你想把图片显示出来的话,需要用到Bitmap:

我们在private String getMediaPath(Uri uri,String selection,int choice)方法下的text.setText(mediaPath);语句后再添加一条语句,用来显示图片:

displayImage(mediaPath);

displayImage(mediaPath)方法的实现如下所示:

private void displayImage(String mediaPath){
    if(mediaPath!=null){
        Bitmap bitmap= BitmapFactory.decodeFile(mediaPath);
        imageView.setImageBitmap(bitmap);
    }else{
        Toast.makeText(this,"获取图片失败",Toast.LENGTH_SHORT).show();
    }
}

最后的效果是这样的:

android: 操作多媒体文件之图片文件_第3张图片

附上各个按钮图标的定义和声明:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    public static final int CHOOSE_PHOTO=1;
    public TextView text;
    public ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button image_btn=(Button)findViewById(R.id.openalbum);
        imageView=(ImageView)findViewById(R.id.image);
        text=(TextView)findViewById(R.id.text);
        image_btn.setOnClickListener(this);
    }
}

三、将图片文件移动到程序关联目录下

        在上述操作中,虽然我们已经将图片显示在程序中了,但图片文件依旧是存储在原来的位置下。我们可能会想要将图片文件复制到与应用程序关联的目录中来。我们在private String getMediaPath(Uri uri,String selection,int choice)方法下的

displayImage(String mediaPath);

语句后再添加一条语句,

fileCopy(String fromFile,int choice);

用来复制图片文件。其中,getFilesDir()获取路径,将文件从系统目录下复制到/data/data/< package name >/files/…,

fileCopy(String fromFile,int choice)方法的实现如下:

/*
*@description 将指定路径下的文件复制成关联目录下的指定类型文件
*@param fromFile 被复制文件路径
*@param choice 文件类型
*@return
*/
 public int fileCopy(String fromFile,int choice)
 {
     try
     {
         InputStream fosfrom = new FileInputStream(fromFile);
         OutputStream fosto= new FileOutputStream(getFilesDir().toString()+"/"+image_name);
         byte bt[] = new byte[1024];
         int c;
         while ((c = fosfrom.read(bt)) > 0)
         {
             fosto.write(bt, 0, c);
         }
         fosfrom.close();
         fosto.close();
         return 0;

     } catch (Exception ex)
     {
         return -1;
     }
 }

四、删除原图片文件

        如果你想要将图片文件移到程序关联的目录下,并删除原系统目录下的图片文件的话,请继续往下看。

        上一节在private String getMediaPath(Uri uri,String selection,int choice)下调用fileCopy(path)实现图片文件的复制,现在我们想升级我们的方法,实现复制并删除原路径下的图片。新建一个方法:copyAndDeletImage(path),该方法的实现如下:

    

public void copyAndDeleteImage(String path){
    if(path!=null){
        fileCopy(path);
        try{
            //resolver.delete 能够在删除图库文件后并清空其缓存
            ContentResolver resolver = this.getContentResolver();
            resolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    MediaStore.Images.Media.DATA+"=\""+path+"\"",null);
            Toast.makeText(MainActivity.this,"已删除原位置文件", Toast.LENGTH_SHORT).show();
        }catch (Exception e){
            e.printStackTrace();
            Toast.makeText(this,"删除原位置文件出错",Toast.LENGTH_SHORT).show();
        }
    }
}

在getImagePath()方法中,将fileCopy(path)换成copyAndDeleteImage(path);即可。

五、完整代码如下:

布局文件:

xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.lenovo.testapp.MainActivity">

   <Button
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/openalbum"
       android:text="选择照片"/>

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/text"/>
   
   <ImageView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/image"/>


LinearLayout>
代码:

package com.example.lenovo.testapp;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    public static final int CHOOSE_PHOTO=1;
    public TextView text;
    public ImageView imageView;
    public String image_name;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button image_btn=(Button)findViewById(R.id.openalbum);
        imageView=(ImageView)findViewById(R.id.image);
        text=(TextView)findViewById(R.id.text);
        image_btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v){
        switch (v.getId()) {
            case R.id.openalbum:
                /*动态申请访问存储空间的权限*/
                if(ContextCompat.checkSelfPermission(MainActivity.this,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                    ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
                }else{
                    openAlbum();
                }
                break;

        }
    }
    /*
    *@description 开启系统相册
    */
    private void openAlbum(){
        Intent intent=new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO);
    }

    /*响应相册点击事件*/
    @Override
    protected void onActivityResult(int requestCode, int resultCode,Intent data) {
        switch (requestCode) {
            case 1:
                if (resultCode == RESULT_OK) {
                    //判断手机系统版本号
                    if (Build.VERSION.SDK_INT >= 19) {
                        //4.4以上版本使用这个方法处理图片
                        handleMediaOnKitKat(data, CHOOSE_PHOTO);
                    } else {
                        //4.4以下系统使用这个方法处理图片
                        handleImageBeforeKitKat(data, CHOOSE_PHOTO);
                    }
                }
                break;
        }
    }

    /*
    *@description 4.4版本及以上媒体文件路径的获取
    *
    */
    @TargetApi(19)
    private void handleMediaOnKitKat(Intent data,int choice){
        String mediaPath=null;
        Uri uri=data.getData();
        if(DocumentsContract.isDocumentUri(this,uri)){
            //如果是document类型的Uri,则通过document id处理
            String docId=DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id=docId.split(":")[1];//解析出数字格式的id
                String selection;
                if(choice==CHOOSE_PHOTO){
                    selection= MediaStore.Images.Media._ID+"="+id;
                    mediaPath=getMediaPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection,choice);
                }
            }else if("com.android.providers.downloads.documents".equals(uri.getAuthority())){
                Uri contentUri= ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),Long.valueOf(docId));
                mediaPath=getMediaPath(contentUri,null,choice);
            }
        }else if("content".equalsIgnoreCase(uri.getScheme())){
            //如果是content类型的Uri,则用普通方式处理
            mediaPath=getMediaPath(uri,null,choice);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
            //如果是file类型的Uri,直接获取文件路径即可
            mediaPath=uri.getPath();
        }

    }

    /*获取多媒体文件的路径*/
    private String getMediaPath(Uri uri,String selection,int choice){
        String path=null;
        Cursor cursor;
        cursor=getContentResolver().query(uri,null,selection,null,null);
        if(cursor!=null){
            if(cursor.moveToFirst()){
                path=cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
            }
            cursor.close();
        }
        String splitarr[]=path.split("/");
        if(choice==CHOOSE_PHOTO);
            image_name=path.split("/")[splitarr.length-1];
        //将text的值设为路径。这里要先将text变量设为全局的,以便在不同的方法中调用。
        text.setText(path);
        displayImage(path);
        copyAndDeleteImage(path);
        return path;
    }


    /*
    *@description 4.4以下版本媒体文件路径的获取
    */
    private void handleImageBeforeKitKat(Intent data,int choice){
        Uri uri=data.getData();
        String mediaPath=getMediaPath(uri,null,choice);

    }

    private void displayImage(String mediaPath){
        if(mediaPath!=null){
            Bitmap bitmap= BitmapFactory.decodeFile(mediaPath);
            imageView.setImageBitmap(bitmap);
        }else{
            Toast.makeText(this,"获取图片失败",Toast.LENGTH_SHORT).show();
        }
    }

    /*
   *@description 将指定路径下的文件复制成关联目录下的指定类型文件
   *@param fromFile 被复制文件路径
   *@param choice 文件类型
   *@return
   */
    public int fileCopy(String fromFile)
    {
        try
        {
            InputStream fosfrom = new FileInputStream(fromFile);
            OutputStream fosto= new FileOutputStream(getFilesDir().toString()+"/"+image_name);
            byte bt[] = new byte[1024];
            int c;
            while ((c = fosfrom.read(bt)) > 0)
            {
                fosto.write(bt, 0, c);
            }
            fosfrom.close();
            fosto.close();
            return 0;

        } catch (Exception ex)
        {
            return -1;
        }
    }

    public void copyAndDeleteImage(String path){
        if(path!=null){
            fileCopy(path);
            try{
                //resolver.delete 能够在删除图库文件后并清空其缓存
                ContentResolver resolver = this.getContentResolver();
                resolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        MediaStore.Images.Media.DATA+"=\""+path+"\"",null);
                Toast.makeText(MainActivity.this,"已删除原位置文件", Toast.LENGTH_SHORT).show();
            }catch (Exception e){
                e.printStackTrace();
                Toast.makeText(this,"删除原位置文件出错",Toast.LENGTH_SHORT).show();
            }
        }
    }

}

 
  
 
  


你可能感兴趣的:(android)