26.Android 下载图片保存到相册

26.Android 下载图片保存到相册

  • Android 下载图片保存到相册
    • 前言
    • 实现思路
    • 自定义Dialog
    • 自定义Handler
    • 自定义AsyncTask
    • AndroidManifest配置权限
    • DownloadImageToGalleryActivity
    • 效果图
    • 源码传送门

前言

有遇到没有这样的一种需求:浏览的大图后,点击保存下载高清原图到相册的需求。

现在的图片缓存大多都是Universal-Imager-Loader为多。但是我们在公司的某些离谱的需求(圈子系的需求,要求每条动态展示的图片不止6张,有一条30多张,直接报了Universal-Imager-Loader的OOM,怎么改配置都不能解决)上,后来调研了GlideFresco,发现Glide基本是完虐的节奏。

这里给大家提一个Glide小问题:Glide自带能把图片加载成圆角,Glide加载本地图片不能实现圆角。

实现思路

  • 1.自定义一个AsyncTask下载图片
  • 2.自定义一个Dialog显示下载进度
  • 3.自定义一个Handler刷新Dialog的进度
  • 4.下载完成后,保存图片到相册里

自定义Dialog

dialog_progressbar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal">

    <ProgressBar  android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:padding="10dip" />

    <TextView  android:id="@+id/load_info_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dip" android:text="正在提交..." android:textColor="#000000" />

</LinearLayout>

CustomProgressBarDialog

    /** * 自定义进度条Dialog */
    public class CustomProgressBarDialog extends Dialog {

        private LayoutInflater mInflater;
        private Context mContext;
        private WindowManager.LayoutParams params;
        private View mView;
        private TextView promptTV;

        public CustomProgressBarDialog(Context context) {
            super(context);
            this.init(context);
        }

        public CustomProgressBarDialog(Context context, int themeResId) {
            super(context, themeResId);
            this.init(context);
        }

        protected CustomProgressBarDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
            super(context, cancelable, cancelListener);
            this.init(context);
        }

        private void init(Context context) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            this.mContext = context;
            this.mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            this.mView = this.mInflater.inflate(R.layout.dialog_progressbar, null);
            setContentView(this.mView);

            // 设置window属性
            this.params = getWindow().getAttributes();
            this.params.gravity = Gravity.CENTER;
            // 去背景遮盖
            this.params.dimAmount = 0;
            this.params.alpha = 1.0f;
            // 不能关掉
            this.setCancelable(false);
            this.getWindow().setAttributes(this.params);
            this.promptTV = (TextView) findViewById(R.id.load_info_text);
        }

        /** * 设置内容 * * @param prompt */
        public void setLoadPrompt(String prompt) {
            this.promptTV.setText(prompt);
        }

    }

自定义Handler

注意:这里可以参考Handler 通用模板。

    private static final int HANDLER_LOADING = 262;

    /** * 刷新Dialog显示的进度Handler */
    private static class LoadingHandler extends Handler {
        private final WeakReference<DownloadImageToGalleryActivity> mActivity;

        public LoadingHandler(DownloadImageToGalleryActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        /** * Subclasses must implement this to receive messages. * * @param msg */
        @Override
        public void handleMessage(Message msg) {
            DownloadImageToGalleryActivity activity = this.mActivity.get();
            if (activity != null) {
                switch (msg.what) {
                    case HANDLER_LOADING: {
                        int progressValue = (int) msg.obj;
                        activity.dialog.setLoadPrompt(progressValue + "%");
                        activity.dialog.show();
                        break;
                    }
                }
            }
        }
    }
    private final LoadingHandler loadingHandler = new LoadingHandler(DownloadImageToGalleryActivity.this);

自定义AsyncTask

注意:这里可以参考AsyncTask 模板。

    /** * 下载图片异步任务 */
    public class DownloadImageAsyncTask extends AsyncTask<String, Integer, String> {

        private Activity activity;
        private String localFilePath;

        public DownloadImageAsyncTask(Activity activity) {
            super();
            this.activity = activity;
        }

        /** * 对应AsyncTask第一个参数 * 异步操作,不在主UI线程中,不能对控件进行修改 * 可以调用publishProgress方法中转到onProgressUpdate(这里完成了一个handler.sendMessage(...)的过程) * * @param params The parameters of the task. * @return A result, defined by the subclass of this task. * @see #onPreExecute() * @see #onPostExecute * @see #publishProgress */
        @Override
        protected String doInBackground(String... params) {
            // TODO 注意这里
            /** * 这里接入你所用的网络框架去下载图片,只要保证this.localFilePath的值有就可以了 */
            URL fileUrl = null;
            try {
                fileUrl = new URL(params[0]);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            if (fileUrl == null) return null;
            try {
                HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
                connection.setRequestMethod("GET");
                connection.setDoInput(true);
                connection.connect();

                //计算文件长度
                int lengthOfFile = connection.getContentLength();
                /** * 不存在SD卡,就放到缓存文件夹内 */
                File cacheDir = this.activity.getCacheDir();
                File downloadFile = new File(cacheDir, UUID.randomUUID().toString() + ".jpg");
                this.localFilePath = downloadFile.getPath();
                if (!downloadFile.exists()) {
                    File parent = downloadFile.getParentFile();
                    if (parent != null) parent.mkdirs();
                }
                FileOutputStream output = new FileOutputStream(downloadFile);
                InputStream input = connection.getInputStream();
                InputStream bitmapInput = connection.getInputStream();
                //下载
                byte[] buffer = new byte[1024];
                int len;
                long total = 0;
                // 计算进度
                while ((len = input.read(buffer)) > 0) {
                    total += len;
                    this.publishProgress((int) ((total * 100) / lengthOfFile));
                    output.write(buffer, 0, len);
                }
                output.close();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        /** * 对应AsyncTask第三个参数 (接受doInBackground的返回值) * 在doInBackground方法执行结束之后在运行,此时已经回来主UI线程当中 能对UI控件进行修改 * * @param string The result of the operation computed by {@link #doInBackground}. * @see #onPreExecute * @see #doInBackground * @see #onCancelled(Object) */
        @Override
        protected void onPostExecute(String string) {
            /** * 设置按钮可用,并隐藏Dialog */
            DownloadImageToGalleryActivity.this.saveBT.setEnabled(true);
            DownloadImageToGalleryActivity.this.dialog.hide();

            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            int screenWidth = metrics.widthPixels;
            int screenHeight = metrics.heightPixels;
            /** * ImageUtil.decodeScaleImage 解析图片 */
            Bitmap bitmap = ImageUtil.decodeScaleImage(this.localFilePath, screenWidth, screenHeight);
            DownloadImageToGalleryActivity.this.saveIV.setImageBitmap(bitmap);
            /** * 保存图片到相册 */
            String imageName = System.currentTimeMillis() + ".jpg";
            MediaStore.Images.Media.insertImage(DownloadImageToGalleryActivity.this.getApplicationContext().getContentResolver(), bitmap, imageName, "牙医助理");
            Toast.makeText(this.activity, "已保存:" + imageName, Toast.LENGTH_LONG).show();
        }

        /** * 对应AsyncTask第二个参数 * 在doInBackground方法当中,每次调用publishProgress方法都会中转(handler.sendMessage(...))到onProgressUpdate * 在主UI线程中,可以对控件进行修改 * * @param values The values indicating progress. * @see #publishProgress * @see #doInBackground */
        @Override
        protected void onProgressUpdate(Integer... values) {
            // 主线程Handler实例消息
            Message message = DownloadImageToGalleryActivity.this.loadingHandler.obtainMessage();
            message.obj = values[0];
            message.what = HANDLER_LOADING;
            // 给主线程Handler发送消息
            DownloadImageToGalleryActivity.this.loadingHandler.handleMessage(message);
        }

        /** * 运行在主UI线程中,此时是预执行状态,下一步是doInBackground * * @see #onPostExecute * @see #doInBackground */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        /** * <p>Applications should preferably override {@link #onCancelled(Object)}. * This method is invoked by the default implementation of * {@link #onCancelled(Object)}.</p> * <p/> * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.</p> * * @see #onCancelled(Object) * @see #cancel(boolean) * @see #isCancelled() */
        @Override
        protected void onCancelled() {
            /** * 设置按钮可用 */
            DownloadImageToGalleryActivity.this.saveBT.setEnabled(true);
            super.onCancelled();
        }

    }

AndroidManifest配置权限

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

DownloadImageToGalleryActivity

activity_download_image_to_grallery.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center_horizontal" tools:context=".DownloadImageToGrallery">

    <TextView  android:id="@+id/save_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="6dp" android:padding="6dp" />

    <Button  android:id="@+id/save_bt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="6dp" android:padding="6dp" android:text="保存" />

    <ImageView  android:id="@+id/save_iv" android:layout_width="360dp" android:layout_height="360dp" android:layout_margin="6dp" />

</LinearLayout>

DownloadImageToGalleryActivity

public class DownloadImageToGalleryActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String OBJECT_IMAGE_URL = "http://img.blog.csdn.net/20150913233900119";

    private Button saveBT;
    private ImageView saveIV;
    private CustomProgressBarDialog dialog;



    /** * Called when a view has been clicked. * * @param v The view that was clicked. */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.save_bt: {
                v.setEnabled(false);
                /** * 设置按钮不可用,开始执行任务 */
                new DownloadImageAsyncTask(this).execute(OBJECT_IMAGE_URL);
                break;
            }
        }
    }

    private static final int HANDLER_LOADING = 262;

    /** * 刷新Dialog显示的进度Handler */
    private static class LoadingHandler extends Handler {
        private final WeakReference<DownloadImageToGalleryActivity> mActivity;

        public LoadingHandler(DownloadImageToGalleryActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        /** * Subclasses must implement this to receive messages. * * @param msg */
        @Override
        public void handleMessage(Message msg) {
            DownloadImageToGalleryActivity activity = this.mActivity.get();
            if (activity != null) {
                switch (msg.what) {
                    case HANDLER_LOADING: {
                        int progressValue = (int) msg.obj;
                        activity.dialog.setLoadPrompt(progressValue + "%");
                        activity.dialog.show();
                        break;
                    }
                }
            }
        }
    }
    private final LoadingHandler loadingHandler = new LoadingHandler(DownloadImageToGalleryActivity.this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_download_image_to_grallery);

        this.saveBT = (Button) this.findViewById(R.id.save_bt);
        this.saveIV = (ImageView) this.findViewById(R.id.save_iv);

        ((TextView) this.findViewById(R.id.save_tv)).setText(OBJECT_IMAGE_URL);
        this.dialog = new CustomProgressBarDialog(this);
        this.saveBT.setOnClickListener(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_download_image_to_grallery, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /** * 自定义进度条Dialog */
    public class CustomProgressBarDialog extends Dialog {

        private LayoutInflater mInflater;
        private Context mContext;
        private WindowManager.LayoutParams params;
        private View mView;
        private TextView promptTV;

        public CustomProgressBarDialog(Context context) {
            super(context);
            this.init(context);
        }

        public CustomProgressBarDialog(Context context, int themeResId) {
            super(context, themeResId);
            this.init(context);
        }

        protected CustomProgressBarDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
            super(context, cancelable, cancelListener);
            this.init(context);
        }

        private void init(Context context) {
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            this.mContext = context;
            this.mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            this.mView = this.mInflater.inflate(R.layout.dialog_progressbar, null);
            setContentView(this.mView);

            // 设置window属性
            this.params = getWindow().getAttributes();
            this.params.gravity = Gravity.CENTER;
            // 去背景遮盖
            this.params.dimAmount = 0;
            this.params.alpha = 1.0f;
            // 不能关掉
            this.setCancelable(false);
            this.getWindow().setAttributes(this.params);
            this.promptTV = (TextView) findViewById(R.id.load_info_text);
        }

        /** * 设置内容 * * @param prompt */
        public void setLoadPrompt(String prompt) {
            this.promptTV.setText(prompt);
        }

    }

    /** * 下载图片异步任务 */
    public class DownloadImageAsyncTask extends AsyncTask<String, Integer, String> {

        private Activity activity;
        private String localFilePath;

        public DownloadImageAsyncTask(Activity activity) {
            super();
            this.activity = activity;
        }

        /** * 对应AsyncTask第一个参数 * 异步操作,不在主UI线程中,不能对控件进行修改 * 可以调用publishProgress方法中转到onProgressUpdate(这里完成了一个handler.sendMessage(...)的过程) * * @param params The parameters of the task. * @return A result, defined by the subclass of this task. * @see #onPreExecute() * @see #onPostExecute * @see #publishProgress */
        @Override
        protected String doInBackground(String... params) {
            // TODO 注意这里
            /** * 这里接入你所用的网络框架去下载图片,只要保证this.localFilePath的值有就可以了 */
            URL fileUrl = null;
            try {
                fileUrl = new URL(params[0]);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            if (fileUrl == null) return null;
            try {
                HttpURLConnection connection = (HttpURLConnection) fileUrl.openConnection();
                connection.setRequestMethod("GET");
                connection.setDoInput(true);
                connection.connect();

                //计算文件长度
                int lengthOfFile = connection.getContentLength();
                /** * 不存在SD卡,就放到缓存文件夹内 */
                File cacheDir = this.activity.getCacheDir();
                File downloadFile = new File(cacheDir, UUID.randomUUID().toString() + ".jpg");
                this.localFilePath = downloadFile.getPath();
                if (!downloadFile.exists()) {
                    File parent = downloadFile.getParentFile();
                    if (parent != null) parent.mkdirs();
                }
                FileOutputStream output = new FileOutputStream(downloadFile);
                InputStream input = connection.getInputStream();
                InputStream bitmapInput = connection.getInputStream();
                //下载
                byte[] buffer = new byte[1024];
                int len;
                long total = 0;
                // 计算进度
                while ((len = input.read(buffer)) > 0) {
                    total += len;
                    this.publishProgress((int) ((total * 100) / lengthOfFile));
                    output.write(buffer, 0, len);
                }
                output.close();
                input.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        /** * 对应AsyncTask第三个参数 (接受doInBackground的返回值) * 在doInBackground方法执行结束之后在运行,此时已经回来主UI线程当中 能对UI控件进行修改 * * @param string The result of the operation computed by {@link #doInBackground}. * @see #onPreExecute * @see #doInBackground * @see #onCancelled(Object) */
        @Override
        protected void onPostExecute(String string) {
            /** * 设置按钮可用,并隐藏Dialog */
            DownloadImageToGalleryActivity.this.saveBT.setEnabled(true);
            DownloadImageToGalleryActivity.this.dialog.hide();

            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            int screenWidth = metrics.widthPixels;
            int screenHeight = metrics.heightPixels;
            /** * ImageUtil.decodeScaleImage 解析图片 */
            Bitmap bitmap = ImageUtil.decodeScaleImage(this.localFilePath, screenWidth, screenHeight);
            DownloadImageToGalleryActivity.this.saveIV.setImageBitmap(bitmap);
            /** * 保存图片到相册 */
            String imageName = System.currentTimeMillis() + ".jpg";
            MediaStore.Images.Media.insertImage(DownloadImageToGalleryActivity.this.getApplicationContext().getContentResolver(), bitmap, imageName, "牙医助理");
            Toast.makeText(this.activity, "已保存:" + imageName, Toast.LENGTH_LONG).show();
        }

        /** * 对应AsyncTask第二个参数 * 在doInBackground方法当中,每次调用publishProgress方法都会中转(handler.sendMessage(...))到onProgressUpdate * 在主UI线程中,可以对控件进行修改 * * @param values The values indicating progress. * @see #publishProgress * @see #doInBackground */
        @Override
        protected void onProgressUpdate(Integer... values) {
            // 主线程Handler实例消息
            Message message = DownloadImageToGalleryActivity.this.loadingHandler.obtainMessage();
            message.obj = values[0];
            message.what = HANDLER_LOADING;
            // 给主线程Handler发送消息
            DownloadImageToGalleryActivity.this.loadingHandler.handleMessage(message);
        }

        /** * 运行在主UI线程中,此时是预执行状态,下一步是doInBackground * * @see #onPostExecute * @see #doInBackground */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        /** * <p>Applications should preferably override {@link #onCancelled(Object)}. * This method is invoked by the default implementation of * {@link #onCancelled(Object)}.</p> * <p/> * <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.</p> * * @see #onCancelled(Object) * @see #cancel(boolean) * @see #isCancelled() */
        @Override
        protected void onCancelled() {
            /** * 设置按钮可用 */
            DownloadImageToGalleryActivity.this.saveBT.setEnabled(true);
            super.onCancelled();
        }

    }

}

效果图

源码传送门

DownLoadImageToGallery

你可能感兴趣的:(android,图片,AsyncTask,下载图片,保存到本地相册)