欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-13 12:49:49
...

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

一、打开图库

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

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

放得位置是这样的:

<?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 打开相册

二、获取图片路径

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

考虑最后一行代码: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: 操作多媒体文件之图片文件

当然,如果你想把图片显示出来的话,需要用到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: 操作多媒体文件之图片文件

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

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();
            }
        }
    }

}