程序员人生 网站导航

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

栏目:综合技术时间:2016-03-30 12:18:42

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



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






前言

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

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

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




实现思路


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


自定义Dialog

dialog_progressbar.xml

<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 WeakReferencemActivity; 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第1个参数 * 异步操作,不在主UI线程中,不能对控件进行修改 * 可以调用publishProgress方法中转到onProgressUpdate(这里完成了1个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第3个参数 (接受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第2个参数 * 在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线程中,此时是预履行状态,下1步是doInBackground * * @see #onPostExecute * @see #doInBackground */ @Override protected void onPreExecute() { super.onPreExecute(); } /** *

Applications should preferably override {@link #onCancelled(Object)}. * This method is invoked by the default implementation of * {@link #onCancelled(Object)}.

*

*

Runs on the UI thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.

* * @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 WeakReferencemActivity; 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第1个参数 * 异步操作,不在主UI线程中,不能对控件进行修改 * 可以调用publishProgress方法中转到onProgressUpdate(这里完成了1个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第3个参数 (接受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第2个参数 * 在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线程中,此时是预履行状态,下1步是doInBackground * * @see #onPostExecute * @see #doInBackground */ @Override protected void onPreExecute() { super.onPreExecute(); } /** *

Applications should preferably override {@link #onCancelled(Object)}. * This method is invoked by the default implementation of * {@link #onCancelled(Object)}.

*

*

Runs on the UI thread after {@link #cancel(boolean)} is invoked and * {@link #doInBackground(Object[])} has finished.

* * @see #onCancelled(Object) * @see #cancel(boolean) * @see #isCancelled() */ @Override protected void onCancelled() { /** * 设置按钮可用 */ DownloadImageToGalleryActivity.this.saveBT.setEnabled(true); super.onCancelled(); } } 


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐