Android 保存图片(包括网络图片)到单独的相册

  我们经常会遇到将图片保存到本地的操作,而且有时候我们需要将图片保存到一个单独的相册,比如微信保存的图片是放到微信相册,微博放到了微博相册。

  我们保存的图片可能有很多的类型,比如 Bitmap、网络图片、字节数组、资源 ID 等,根据不同的类型我们需要做不同的处理。

我们先看看怎么把 Bitmap 保存到本地相册:

public static void saveImageToGallery(Context context, Bitmap bitmap) {
        // 先将图片保存到文件
        File imageDir = new File(Environment.getExternalStorageDirectory(), "testGallery");
        if (!imageDir.exists()) {
            imageDir.mkdir();
        }
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(imageDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 再通知图库更新数据库
        Uri uri = Uri.fromFile(file);
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
    }

  这个方法可以将保存的图片在系统图库保存到单独的相册:testGallery,我们还有另一种方法,就直接将图片保存到系统的大图库中:

public static void saveImageToGallery(Context context, Bitmap bitmap) {
        // 先将图片保存到文件
        File imageDir = new File(Environment.getExternalStorageDirectory(), "testGallery");
        if (!imageDir.exists()) {
            imageDir.mkdir();
        }
        String fileName = System.currentTimeMillis() + ".jpg";
        File file = new File(imageDir, fileName);
        try {
            FileOutputStream fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 其次把文件插入到系统图库
        try {
            MediaStore.Images.Media.insertImage(context.getContentResolver(),
                    file.getAbsolutePath(), "Dolfin", "Translation evidence of Dolfin");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最后通知图库更新
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse(file.getAbsolutePath())));
    }

  这个方法是将图片直接存入到系统图库中,没有新建一个独立的相册。而且我们要知道其实我们的图片并不是直接保存到图库中,因为图库是个应用,我们不能直接将图片保存到别的应用中,我们只是将图片保存到了 SD 卡中,然后发了一个广播来通知系统图库更新数据库,间接将图片保存到了图库中。

  我们知道了将 Bitmap 保存到图库中,其实要保存别的形式就可以将别的类型转换为 Bitmap 就行,比如:

// 资源文件保存
    public static void saveImageToGallery(Context context, int resId) {
        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
        if (bitmap != null) {
            saveImageToGallery(context, bitmap);
        }
    }

    // 字节数组保存
    public static void saveImageToGallery(Context context, byte[] bytes) {
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        if (bitmap != null) {
            saveImageToGallery(context, bitmap);
        }
    }

  当然了,如果还需要别的类型,我们完全可以使用 BitmapFactory 来转换就行。

  上面说了这几种类型,但是并没有网络图片类型,因为网络图片类型我们要转换为 Bitmap 需要先把图片下载下来,而网络操作是不能放在 Android 主线程中的,所以我们必须要使用线程工具,Android 原生的就有线程工具,比如 Handler、AsyncTask,全凭自己喜好去选择,我这里使用的是 AsyncTask。

  虽然我们知道这里图片下载完成后是直接保存到图库,但是毕竟是耗时操作,而且也有可能是别的地方会复用,所以我们还是提供一个回调:

public abstract static class OnImageDownloadFinishListener {
        public void start(){}
        public void finish(Bitmap bitmap){}
        public void error(Exception e){}
    }

  这里我没有使用接口,而是使用了抽象类,主要是因为这里图片保存的回调我们可能就在工具类中使用了,如果使用接口会导致复用的使用去重写一些没必要的方法,使用抽象类可以按需重写。

  接下来就是将图片下载下来:

private static Bitmap getBitmap(String imageUrl,OnImageDownloadFinishListener listener) {
        HttpURLConnection connection = null;
        Bitmap bitmap = null;
        try {
            connection = (HttpURLConnection) new URL(imageUrl).openConnection();
            connection.setConnectTimeout(6000);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            bitmap = BitmapFactory.decodeStream(connection.getInputStream());
        } catch (IOException e) {
            if (listener != null){
                // 回调错误
                listener.error(e);
            }
            e.printStackTrace();
        }
        return bitmap;
    }

  这里因为写的 Demo,没有必要去导入各种网络库,大家可以按自己的项目需要使用不同的网络库读出输入流就行。因为这个是耗时操作,所以还是要放入 AsyncTask 中:

private static Bitmap bitmap;
    public static void downImage(Context context,String imageUrl, OnImageDownloadFinishListener listener) {

        class ImageTask extends AsyncTask<Void,Void,Void> {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                if (listener != null){
                    listener.start();
                }
            }

            @Override
            protected Void doInBackground(Void... voids) {
                bitmap = getBitmap(imageUrl,listener);
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                super.onPostExecute(aVoid);
                // 结束
                if (bitmap == null){
                    listener.error(new Exception("下载失败"));
                }else {
                    // 保存到相册
                    saveImageToGallery(context,bitmap);
                    if (listener != null){
                        listener.finish(bitmap);
                    }
                }
            }
        }
        new ImageTask().execute();

    }

  这里我并没有写进度条,大家可以按需重写 AsyncTask 的 onProgressUpdate,不管是在 DoInBackground() 中去调用 publishProgress()还是去添加进度的回调方法都可以。然后我们还是封装一下:

// 网络图片保存
    public static void saveImageToGallery(Context context, String imageUrl,OnImageDownloadFinishListener listener) {
        downImage(context,imageUrl,listener);
    }

  这里关于图片保存到图库就是这些,当然还是不能忘了我们的权限问题:

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

  而这里涉及到了读取文件的敏感权限,所以我们就必须考虑到 Android 6.0 以上的动态权限:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                int check = ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE);
                if (check == PackageManager.PERMISSION_GRANTED) {
                    // 有权限就保存图片
                    ImageUtil.saveImageToGallery(this,R.drawable.hashmap_2_2);
                } else {
                    // 没权限就申请权限
                    requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
                }
            } else {
                ImageUtil.saveImageToGallery(this,R.drawable.hashmap_2_2);
            }

所以我们还要去重写 onRequestPermissionsResult() 方法,去监听权限的变化:

@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            // 根据我们动态请求权限时传入的 requestCode 做处理
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 允许权限,做处理

                } else {
                    // 不允许权限,做处理
                }
                break;
            default:
                break;

        }
    }

接下来就是具体的使用:

// 本地图片
        binding.btnSaveImage.setOnClickListener(view -> {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                int check = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                if (check == PackageManager.PERMISSION_GRANTED) {
                    // 有权限就保存图片
                    ImageUtil.saveImageToGallery(this, R.drawable.hashmap_2_2);
                } else {
                    // 没权限就申请权限
                    requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
                }
            } else {
                ImageUtil.saveImageToGallery(this, R.drawable.hashmap_2_2);
            }

        });

        // 网络图片
        binding.btnSaveImageInternet.setOnClickListener(view ->
                ImageUtil.saveImageToGallery(this, "https://upload-images.jianshu.io/upload_images/2851519-c266af39ef8df081.png?imageMogr2/auto-orient/strip|imageView2/2/w/419/format/webp"
                        , new ImageUtil.OnImageDownloadFinishListener() {
                            @Override
                            public void start() {
                                System.out.println("开始了");
                            }

                            @Override
                            public void finish(Bitmap bitmap) {
                                System.out.println("结束了");
                            }

                            @Override
                            public void error(Exception e) {
                                System.out.println("错误了");
                            }
                        })
        );

好了,关于保存图片到图库就分享到这了,如果喜欢的话欢迎关注我的个人微信公众号,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值