最近几天开学,所以没有更新博客。今天开始更新。最近我打算每天抽出一些事件看点Thinkin Java这本书,仔细研究下java,当然也会出这个博客关于Think in java系列的博客,大家可以一起研究下。
不多说,正式进入主题。这篇主要叙述的是关于保存图片的具体功能实现。
我们先来看看UC的
图10.2.13 UC保存图片对话框
图10.2.14 UC文件管理
我们可以看到UC在点击“保存图片”选项后,弹出了一个保存图片的对话框
既然有了参照物,那么我们就首先来进行界面的实现。
为了简单起见,对话框的编写仍旧采用AlertDialog的构建,只需要替换其中的布 局文件就可以了。我们可以简单的将内容的View采用LinearLayout,其中包含两个 LinearLayout,具体的看下面的xml布局配置文件:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:id="@+id/dialog_fileName"
android:layout_width="match_parent"
android:layout_height="30dp"
android:orientation="horizontal"
android:layout_marginTop="30dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/dialog_back"
>
<TextView
android:id="@+id/dialog_fileName_title"
android:layout_width="80dp"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="15sp"
android:text="@string/fileName"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
/>
<EditText
android:id="@+id/dialog_fileName_input"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/blank"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@null"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/dialog_savePath"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="30dp"
android:background="@drawable/dialog_back"
>
<TextView
android:id="@+id/dialog_savePath_title"
android:layout_width="80dp"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="15sp"
android:text="@string/savePath"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
/>
<TextView
android:id="@+id/dialog_savePath_enter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/defaultPath"
android:text="@string/defaultPath"
android:layout_marginRight="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@null"
/>
</LinearLayout>
</LinearLayout>
代码片段10.2.36 保存图片对话框的xml布局文件
具体的预览效果如下:
图10.2.15 对话框内容预览图
因为我们没有权限在手机内存中进行相关操作,所以为了方便起见,我们所有的路 径基础都是以sdcad的路径为基础的。
现在有了保存的界面,我们就可以编写关于文件管理的界面了。不过为了管理方便, 我们将所有的文件操作都放到file包下。现在我们只需要两种操作即可,分别为文件 列表展示与图片下载操作。图片下载先不管他,我们先进行文件展示方面的编写。
文件展示因为需要耗费一定的时间,Android建议我们将所有的耗时操作都放到子 线程中进行。所以,我通过继承了AsynTask类来进行文件展示的操作。
这里需要注意的是所有的耗时操作都是放在doInBackground这个方法当中的, 并且不能将UI线程中的操作放在这个类中,否则会报错。
现在我将这个文件展示类的具体代码放上来:
package com.example.file;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import com.example.androidstudy_web.R;
import com.example.util.SortComparator;
/**
* 文件管理类
* @version 1.0
* @author 本人dddd牛仔
* <hr/>
* */
public class FileShowManager extends AsyncTask<String, String,List<HashMap<String, Object>>>{
private static final String DEG_TAG ="webbrowser_FileManager";
public static final String SDCARD_HOME = Environment.getExternalStorageDirectory().toString();
public static final String DEFAULT_PATH =SDCARD_HOME + "/webbrowserX/download/";
public enum SORTTYPE {
LETTER, DATE,CHILDNUMS
}
private Activityactivity;
private ListViewfileList;
private DialogwaitDialog;
public FileShowManager(Activity activity, ListViewfileListView){
this.activity = activity;
this.fileList = fileListView;
}
@Override
protected void onPreExecute() {
//初始化控件
this.waitDialog =new AlertDialog.Builder(this.activity)
.setMessage("正在加载中...")
.create();
this.waitDialog.setCancelable(false);
this.waitDialog.setCanceledOnTouchOutside(false);
this.waitDialog.show();
super.onPreExecute();
}
@Override
protected List<HashMap<String, Object>>doInBackground(String... params) {
List<HashMap<String, Object>> fileLists =buildListForAdapter(params[0]);
//默认以首字母排序
this.sortByKey(fileLists, SORTTYPE.LETTER);
return fileLists;
}
@Override
protected void onPostExecute(List<HashMap<String, Object>>result) {
//初始化数据
this.initData(result);
fileList.invalidate();
this.waitDialog.dismiss();
super.onPostExecute(result);
}
/**
* 初始化数据
* */
public void initData(List<HashMap<String, Object>>fileLists){
SimpleAdapter adapter = new
SimpleAdapter(this.activity.getApplicationContext(),fileLists,
R.layout.filemanager_list_item,
new String[]{"name","path","childnums","date","img"},
new int[]{R.id.filemanager_item_info_name,R.id.filemanager_item_filePath,
R.id.filemanager_item_info_numsAndDate_nums,R.id.filemanager_item_info_numsAndDate_date,
R.id.filemanager_item_icon});
this.fileList.setAdapter(adapter);
}
/**
* 构建文件List的适配器
* @param path 文件路径
* */
public List<HashMap<String, Object>>buildListForAdapter(String path){
List<HashMap<String, Object>> list = newArrayList<HashMap<String,Object>>();
File rootFile = new File(path);
if(!rootFile.exists()){
//以默认位置打开
rootFile = new File(DEFAULT_PATH);
if(!rootFile.exists()){
//默认位置不存在,进行创建
rootFile.mkdirs();
}
}
File[] currentPathFiles = rootFile.listFiles();
Log.d(DEG_TAG,DEFAULT_PATH+":"+currentPathFiles);
if(!path.equals(SDCARD_HOME)){
HashMap<String, Object> root = new HashMap<String,Object>();
root.put("name", "/");
root.put("img", R.drawable.floder_home_back);
root.put("path", SDCARD_HOME);
root.put("childnums","返回根目录");
root.put("date", "");
list.add(root);
HashMap<String, Object> pmap = new HashMap<String,
Object>();
pmap.put("name", "..");
pmap.put("img", R.drawable.floder_up_back);
pmap.put("path", rootFile.getParent());
pmap.put("childnums","返回上一级");
pmap.put("date", "");
list.add(pmap);
}
if(currentPathFiles!=null){
//如果存在子文件则进行遍历
for (File file : currentPathFiles){
//根据是否为文件夹选择不同的图标
if(file.isDirectory()){
HashMap<String, Object> item = new HashMap<String,Object>();
item.put("img", R.drawable.floder_back);
item.put("name", file.getName());
item.put("path", file.getPath());
item.put("childnums","共有"+this.getDirectoryNums(file)+"项");
item.put("date",new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.CHINA).format(file.lastModified()));
list.add(item);
}
}
}
return list;
}
/**
* 统计文件夹中的文件夹数量
* @param directory文件夹
* */
public int getDirectoryNums(File directory){
if(directory.isDirectory()){
File[] files = directory.listFiles();
return this.getDirectoryNums(files);
}
return -1;
}
/**
* 统计文件夹中的文件夹数量
* @param files 文件夹下的所有文件
* */
public int getDirectoryNums(File[] files){
int nums = 0;
if(files!=null){
for(File file : files){
if(file.isDirectory()){
nums++;
}
}
}
return nums;
}
/**
* List排序
* @param lists 待排序的数组
* @param sortType排列种类
* */
public List<HashMap<String, Object>>sortByKey(List<HashMap<String, Object>> lists, SORTTYPE sortType){
Collections.sort(lists, new SortComparator(sortType));
Log.d(DEG_TAG,"list.sort:["+lists+"]");
return lists;
}
}
代码片段10.2.37 文件列表展示具体代码实现
这里最主要的一个函数就是buildListForAdapter。我通过传入当前的文件 路径来列出当前的所有文件夹以及通过getDirectoryNums这个函数得到每个 子文件夹的具体文件数量。至于为什么只选择显示文件夹,列出的子项数量也为子 文件夹的数量。这是因为UC的功能就是这么实现的,不过UC在删除文件夹的时 候会显示出其他文件,这个不知道是不是UC的一个BUG。
现在这样的文件显示效果是没有顺序可言的。我通过sortByKey的函数,将文 件列表以字母的数序来进行排列,为了以后的扩展性需要,我这里并没有将它写死, 而是传入了枚举变量,通过这个变量类分辨以何种顺序排列。
文件的排列我是通过Collections.sort来实现的,不过这个函数的实现需 要构建一个自定义的Comparator比较器。
具体的比较器实现方法如下:
package com.example.util;
import java.util.Comparator;
import java.util.HashMap;
import com.example.file.FileShowManager;
public class SortComparator implementsComparator<HashMap<String, Object>> {
private FileShowManager.SORTTYPEsortType;
public SortComparator(FileShowManager.SORTTYPE sortType){
this.sortType = sortType;
}
@Override
public int compare(HashMap<String, Object> lhs,HashMap<String, Object> rhs) {
switch(sortType){
case LETTER:
//字母排序
return String.valueOf(lhs.get("name")).compareTo(String.valueOf(rhs.get("name")));
case DATE:
//日期排序
return String.valueOf(lhs.get("date")).compareTo(String.valueOf(rhs.get("date")));
case CHILDNUMS:
//含文件夹数排序
return String.valueOf(lhs.get("childnums")).compareTo(String.valueOf(rhs.get("childnums")));
}
return 0;
}
}
代码片段10.2.38 比较器代码实现
我们根据传入的枚举值,来进行比较,如果为字母排序,则通过传入的单项为 HashMap的实现取得name值来比较,后面的日期与文件数排序也是相同的实现。至于 为什么日期也可以这样实现,那是因为日期的传入是一个字符串的形式。
现在我们可以看下文件列表展示的效果:
图10.2.16 文件列表的展示
如何实现这个界面呢?还是老样子,显示定义xml文件布局,再是根据布局编写相 应的Activity和其功能。
现在放上代码:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
>
<FrameLayout
android:id="@+id/fileManager_title"
android:layout_width="fill_parent"
android:layout_height="46dp"
android:background="@android:color/holo_blue_light"
>
<TextView
android:id="@+id/fileManager_title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/filemanagerTitle"
android:textSize="18sp"
android:textColor="@android:color/white"
android:textStyle="bold"
android:layout_gravity="center"
/>
<Button
android:id="@+id/fileManager_title_newDirectory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/filemanagerNewDirectory"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="3dp"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
/>
</FrameLayout>
<ListView
android:id="@+id/fileManager_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/fileManager_title"
android:layout_above="@+id/fileManager_toolbar"
>
</ListView>
<RelativeLayout
android:id="@+id/fileManager_toolbar"
android:layout_width="fill_parent"
android:layout_height="35dp"
android:layout_alignParentBottom="true"
android:background="@drawable/tools_back"
>
<TextView
android:id="@+id/fileManager_toolbar_sure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sure"
android:textSize="17sp"
android:textColor="@android:color/black"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_marginLeft="20dp"
/>
<TextView
android:id="@+id/fileManager_toolbar_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:textSize="17sp"
android:textColor="@android:color/black"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
/>
</RelativeLayout>
</RelativeLayout>
代码片段10.2.39 文件列表展示xml布局页面
我们可以来看看这个布局文件的预览效果:
图10.2.17 文件列表展示预览
文件列表的点击功能可以这样分析,我们在每个列表中加入一个向上的项和返回 根目录的项。这个功能已经在上述的文件展示类中实现了的。在我们点击确定按钮后, 返回当前的url,按取消则是不做任何处理。
因此,我们在activity中需要设置一个全局变量currentPath记录当前的相对路 径。
package com.example.androidstudy_web;
import java.io.File;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.file.FileShowManager;
import com.example.other.ItemLongClickedPopWindow;
public class FileActivity extends Activity{
private static final String DEG_TAG ="webbrowser_FileManager";
public static final int RESULT_FILEMANAGER = 1;
//文件列表
private ListViewfileList;
//确定取消按钮
private TextViewsure;
private TextViewcancel;
//新建目录按钮
private ButtoncreateNewFloder;
//监听器
private FileManagerOnItemListenerfileManagerOnItemListener;
private FileManagerOnClickListenerfileManagerOnClickListener;
private FileManagerOnItemLongListenerfileManagerOnItemLongListener;
private FileListPopWindowMenufileListPopWindowMenu;
//长按文件列表单项弹出菜单
private ItemLongClickedPopWindowfileListItemLongClickedPopWindow;
//文件管理线程类
private FileShowManagerfileManager;
//当前的路径
private StringcurrentPath;
/**
* 文件管理Actvity
* @param savedInstanceState父Activity信息
* */
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_filemanager);
//初始化控件
this.fileList = (ListView)this.findViewById(R.id.fileManager_list);
this.sure = (TextView)this.findViewById(R.id.fileManager_toolbar_sure);
this.cancel = (TextView)this.findViewById(R.id.fileManager_toolbar_cancel);
this.createNewFloder = (Button)this.findViewById(R.id.fileManager_title_newDirectory);
this.fileManager =new FileShowManager(this,this.fileList);
this.fileManagerOnItemListener =new FileManagerOnItemListener();
this.fileManagerOnClickListener =new FileManagerOnClickListener();
this.fileManagerOnItemLongListener =new FileManagerOnItemLongListener();
//注册监听
this.fileList.setOnItemClickListener(this.fileManagerOnItemListener);
this.fileList.setOnItemLongClickListener(this.fileManagerOnItemLongListener);
this.sure.setOnClickListener(this.fileManagerOnClickListener);
this.cancel.setOnClickListener(this.fileManagerOnClickListener);
this.createNewFloder.setOnClickListener(this.fileManagerOnClickListener);
//启动文件查询线程
currentPath = getIntent().getStringExtra("savePath");
this.fileManager.execute(currentPath);
}
/**
* OnItemClickListener自定义继承类
* 覆盖如下方法:
* 1. onItemClick
* */
private class FileManagerOnItemListener implements OnItemClickListener{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
TextView path = (TextView) view.findViewById(R.id.filemanager_item_filePath);
currentPath = path.getText().toString();
Log.d(DEG_TAG,"path:"+currentPath);
fileManager = new FileShowManager(FileActivity.this,fileList);
fileManager.execute(currentPath);
}
}
/**
* OnItemLongClickListener自定义继承类
* 覆盖如下方法:
* 1. onItemLongClick
* */
private class FileManagerOnItemLongListener implementsOnItemLongClickListener{
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position,long id) {
TextView date = (TextView) view.findViewById(R.id.filemanager_item_info_numsAndDate_date);
if(date.getText().toString().equals("")){
return false;
}
fileListItemLongClickedPopWindow =new ItemLongClickedPopWindow(FileActivity.this,ItemLongClickedPopWindow.FILEMANAGER_ITEM_POPUPWINDOW, 200, 200);
fileListItemLongClickedPopWindow.showAsDropDown(view, view.getWidth()/2,-view.getHeight()/2);
TextView deleteFloder = (TextView) fileListItemLongClickedPopWindow.getView(R.id.item_longclicked_deleteFloder);
TextViewnewNameForFloder = (TextView) fileListItemLongClickedPopWindow.getView(R.id.item_longclicked_newNameForFloder);
fileListPopWindowMenu =new FileListPopWindowMenu(view);
deleteFloder.setOnClickListener(fileListPopWindowMenu);
newNameForFloder.setOnClickListener(fileListPopWindowMenu);
return true;
}
}
/**
* OnClickListener自定义继承类
* */
private class FileListPopWindowMenu implements OnClickListener{
private ViewbeLongClickedView;
public FileListPopWindowMenu(View beLongClickedView){
this.beLongClickedView = beLongClickedView;
}
@Override
public void onClick(View v) {
fileListItemLongClickedPopWindow.dismiss();
TextView floderPath = (TextView) beLongClickedView.findViewById(R.id.filemanager_item_filePath);
TextView oldFloderName = (TextView) beLongClickedView.findViewById(R.id.filemanager_item_info_name);
final String floderPathStr = floderPath.getText().toString();
if(v.getId()==R.id.item_longclicked_deleteFloder){
//删除文件夹的实现
new AlertDialog.Builder(FileActivity.this)
.setTitle("删除目录")
.setMessage("是否删除""+floderPathStr+""目录")
.setPositiveButton("删除",new DialogInterface.OnClickListener() {
@Override
publicvoid onClick(DialogInterface dialog, int which) {
File deleteDirectory = newFile(floderPathStr);
if(deleteDirectory.exists()){
deleteDirectory.delete();
fileManager =new FileShowManager(FileActivity.this,fileList);
fileManager.execute(currentPath);
}
}
})
.setNegativeButton("取消",null)
.create()
.show();
}else if(v.getId()==R.id.item_longclicked_newNameForFloder){
//重命名文件夹的实现
View newNameForFloderView = LayoutInflater.from(FileActivity.this).inflate(R.layout.dialog_newnameforfloder,null);
final TextView floderName = (TextView) newNameForFloderView.findViewById(R.id.dialog_newNameForFloder
_floderName);
floderName.setText(oldFloderName.getText().toString());
new AlertDialog.Builder(FileActivity.this)
.setTitle("重命名")
.setView(newNameForFloderView)
.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
publicvoid onClick(DialogInterface dialog, int which) {
String newFloderName =floderName.getText().toString();
File newNameFloder = new File(floderPathStr);
newNameFloder.renameTo(new File(currentPath +"/" + newFloderName));
fileManager =new FileShowManager(FileActivity.this,fileList);
fileManager.execute(currentPath);
}
})
.setNegativeButton("取消",null)
.create()
.show();
}
}
}
/**
* OnClickListener自定义继承类
* 覆盖如下方法
* 1. onClick
* */
private class FileManagerOnClickListener implements OnClickListener{
@Override
public void onClick(View v) {
if(v.getId()==R.id.fileManager_toolbar_sure){
//确定操作,返回确定的url
Intent intentExtraUrl = new Intent();
intentExtraUrl.putExtra("savePath",currentPath);
setResult(RESULT_FILEMANAGER, intentExtraUrl);
finish();
}else if(v.getId()==R.id.fileManager_toolbar_cancel){
//取消操作,不更改url
setResult(MainActivity.REQUEST_DEFAULT);
finish();
}else if(v.getId()==R.id.fileManager_title_newDirectory){
//新建目录操作
View createNewFolderView = LayoutInflater.from(FileActivity.this).inflate(R.layout.dialog_createnewfloder,null);
final EditText newFloderName = (EditText)createNewFolderView.findViewById(R.id.dialog_createNewFloder_floderName);
new AlertDialog.Builder(FileActivity.this)
.setTitle("创建新目录")
.setView(createNewFolderView)
.setPositiveButton("确定",new DialogInterface.OnClickListener() {
@Override
publicvoid onClick(DialogInterface dialog, int which) {
StringcreateNewpath = currentPath + "/" + newFloderName.getText().toString();
Log.d(DEG_TAG,"createNewpath:"+createNewpath);
File file = new File(createNewpath);
if(!file.exists()){
file.mkdir();
fileManager =new FileShowManager(FileActivity.this,fileList);
fileManager.execute(currentPath);
}else{
//目录已存在,提示无法创建
Toast.makeText(FileActivity.this,"目录已存在", Toast.LENGTH_SHORT).show();
}
}
})
.setNegativeButton("取消",null)
.create()
.show();
}
}
}
@Override
public void onBackPressed() {
setResult(MainActivity.REQUEST_DEFAULT);
super.onBackPressed();
}
}
代码片段10.2.40 文件展示列表的具体实现
注意:这里在默认打开界面的时候就需要加载文件列表,而默认的位置就是保存图 片对话框所显示出来的保存路径。我们每次进行加载的时候都需要重新实例化一个文 件列表展示类,因为继承自AsynTask,只能执行一次execute方法。
因为我们要实现列表单项长按弹出菜单的实现,所以这就需要监听长按的事件。而 对于弹出菜单实现单击事件。上述代码中都有所提及。
至于在弹出保存对话框中的具体代码实现如下:
else if(v.getId()==R.id.item_longclicked_saveImage){
//图片菜单-保存图片
View dialogSaveImg = LayoutInflater.from(MainActivity.this).inflate(R.layout.dialog_saveimg,null);
choosePath = (TextView) dialogSaveImg.findViewById(R.id.dialog_savePath_enter);
imgSaveName = (TextView) dialogSaveImg.findViewById(R.id.dialog_fileName_input);
final String imgName =value.substring(value.lastIndexOf("/") + 1);
imgSaveName.setText(imgName);
choosePath.setOnClickListener(buttonClickedListener);
saveImageToChoosePath =new AlertDialog.Builder(MainActivity.this)
.setTitle("选择保存路径")
.setView(dialogSaveImg)
.setPositiveButton("确定",new
DialogInterface.OnClickListener(){
@Override
publicvoid onClick(DialogInterface dialog, int which) {
Log.d(DEG_TAG,"fileName:"+imgName+",filePath:"+choosePath.getText().toString());
new ImageDownloadManager(MainActivity.this).execute(imgName,value, choosePath.getText().toString());
}
})
.setNegativeButton("取消",null)
.create();
saveImageToChoosePath.show();
}
代码片段10.2.41 弹出保存对话框的具体实现
这里的ImageDownloadManager就是管理下载图片的类,因为耗时的缘故,我们这里仍旧使用AsynTask类。
package com.example.file;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
public class ImageDownloadManager extends AsyncTask<String, String,String>{
private static final String DEG_TAG ="webbrowser_FileDownloadManager";
private Filefile;
private Contextcontext;
public ImageDownloadManager(Context context){
this.context = context;
}
@SuppressLint("SdCardPath")
@Override
protected String doInBackground(String... params) {
Log.d(DEG_TAG,"fileName:"+params[0]+",filePath:"+params[2]);
if(params[2].startsWith("/sdcard/")){
//如果是以/sdcard/为开头的,则应保存为sdcard中
params[2] = Environment.getExternalStorageDirectory()+params[2].substring(8);
Log.d(DEG_TAG,"saveImagePath:"+params[2]);
}
try{
URL url = new URL(params[1]);
HttpURLConnectionconn =(HttpURLConnection)url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStreaminputStream=conn.getInputStream();
Bitmap imgSave =BitmapFactory.decodeStream(inputStream);
this.writeFile(params[0],params[2], imgSave);
inputStream.close();
}catch(IOException e){
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
Toast.makeText(context,"成功下载", Toast.LENGTH_SHORT).show();
super.onPostExecute(result);
}
/**
* 将图片写入
* @param fileName图片名
* @param dirPath 图片路径
* @param Bitmap 图片内容
* */
public void writeFile(String fileName, String dirPath, BitmapimgSave){
try{
File directory = new File(dirPath);
if((directory.exists())&&(directory.isFile())){
directory.delete();
}else{
directory.mkdirs();
}
this.file =new File(dirPath, fileName);
if(this.file.exists()){
this.file.delete();
}
this.file.createNewFile();
FileOutputStream fo = new FileOutputStream(this.file);
imgSave.compress(Bitmap.CompressFormat.PNG, 100, fo);
fo.flush();
fo.close();
}catch(FileNotFoundException e1){
Log.d(DEG_TAG,"文件未找到:"+e1.getMessage());
}catch(IOException e2){
Log.d(DEG_TAG,"文件创建错误:"+e2.getMessage());
e2.printStackTrace();
}
}
}
代码片段10.2.41 下载文件管理类
至此我们的保存图片功能已经完成。
案例: