说明:附件上传,选择上传的附件只做了从图库选择图片或者拍照获取图片,实际也可以上传其他类型的文件,附件分为11中状态,未上传,准备上传,上传中,上传失败,上传成功,未下载,准备下载,下载中,下载成功,下载失败,已和服务器同步,看似有点复杂,其实也挺简单。
下面我将从无到有,一个一个伴随着效果图以及代码片段进行讲解
一:空白的附件列表界面如下:
点击“添加图片”按钮后:会弹出如下的选择菜单,提示是从图库选择图片还是拍照获取图片
二:选择图片菜单界面如下:
三:当选择4张图片或者拍照得到图片后,显示界面如下所示:
可以看到每个条目有一张缩略图,文件名,文件大小,最后修改日期,文件状态,以及右侧的操作按钮组成,文件状态还有一个隐藏的TextView,可以用来显示上传或下载的进度
四:点击题目中的文件名,可以修改文件的名字(只有未上传状态可以修改)
这里点击第二张范爷的图片的文件名
界面如图所示:
五:重命名后的界面如图所示:文件名改成了范爷一枚.jpg了
六:点击每个条目的上传按钮,可以讲它们加入未上传队列,这时候图片将一张张上传到服务器,每一张图片的状态依次改变为:未上传→准备上传→上传中(这是现实进度)→上传完成→已和服务器同步
如图所示:
七:所有的上传队列中图片上传完成后,会弹出确认框,是否保存刚刚上传的这些图片,如果确认,图片的状态就变成了“已和服务器同步”状态了,失败的会变成未上传状态
如图所示:
这里可以看到最后又张图片上传失败了,可以进行重试
前面讲解的都是添加上传的操作,下载讲解删除和下载的操作
说明:所有的删除和取消相关的操作,都是长按条目弹出的
一:删除未上传的图片
长按上面图片的范爷条目,会弹出如下对话框
点击删除按钮后这张图片便被移除了
二:删除已和“已和服务器同步状态”,点击条目,会弹出一样的删除对话框,但是点击删除按钮后,可以选择只从本地删除还是从服务器和本地都删除,如图所示:
如果点击“服务器和本地都删除”则图片会被从本地列表和服务器删除,但是如果点击“只从本地删除”则图片变成“未下载”状态
三:将所有的图片只从本地删除后,界面如图所示
这时候,和上传功能相反,如果点击右侧的下载按钮,图片的状态变化如下:
未下载→准备下载→下载中(显示进度)→下载完成(下次进入附件列表会变成已和服务器同步),如果下载失败会显示“下载失败”并可以重试
四:下载界面如图所示:
五:位于上传下载队列中,但是还没有开始上传和下载的都是可以取消操作的,这里就不截图了
当然,点击本地存在的图片或者已下载完成的图片,是可以发起系统调用查看图片的(实际上任何文件都可以查看)
下面就是核心的代码了:主要是一个Activity:AttachmentActivity,这个就是主界面了,3个帮助类DownLoadUtil:用来下载的帮助类,UploadUtil:用来上传的帮助类,FileIconHelper:用来显示缩略图的帮助类,AttachmentInfo附件实体类,至于其他一些简单常量及没有提到的方法,就不多少了,自行替换就是了。
各个功能点都在代码中有详细的注释:请看代码
AttachmentInfo:
package com.flagcloud.android.mqservice.model.entity;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import com.flagcloud.android.mqservice.util.CommonHelper;
import com.flagcloud.android.mqservice.util.ConvertUtil;
import android.text.format.Time;
/**
* 附件信息实体类
*
* @author hdp
*
*/
public class AttachmentInfo {
public static final int NOT_UPLOAD = 1, PREPARE_UPLOAD = 2, UP_LOADING = 3,
UP_LOADING_SUCCESS = 4, UP_LOADING_FAIL = 5, NOT_DOWNLOAD = 6,
PREPARE_DOWNLOAD = 7, DOWN_LOADING = 8, DOWN_LOADING_SUCCESS = 9,
DOWN_LOADING_FAIL = 10, ALREADY_SAVE = 11;
// 本地有,服务器也已保存,则为已保存状态
static {
addToStateMap(1, "未上传");
addToStateMap(2, "准备上传");
addToStateMap(3, "上传中:");
addToStateMap(4, "上传完成");
addToStateMap(5, "上传失败");
addToStateMap(6, "未下载");
addToStateMap(7, "准备下载");
addToStateMap(8, "下载中:");
addToStateMap(9, "下载完成");
addToStateMap(10, "下载失败");
addToStateMap(11, "已和服务器同步");
}
public static HashMap<Integer, String> stateMap;
// 服务器返回属性
public String id;
public String fileName; // 文件名
public String path; // 文件路径,服务器路径
public long size; // 文件大小,字节
public String time;
// 自定义属性
public int state; //文件状态
public int progress = 0; // 操作进度
public String fileNativePath; // 文件在本地的地址
public static void addToStateMap(int state, String stateText) {
if (stateMap == null) {
stateMap = new HashMap<Integer, String>();
}
stateMap.put(state, stateText);
}
public AttachmentInfo() {
}
public AttachmentInfo(String name, String path, long size,
String modifyTime, int state, int progress, String fileNativePath) {
super();
this.fileName = name;
this.path = path;
this.size = size;
this.time = modifyTime;
this.state = state;
this.progress = progress;
this.fileNativePath = fileNativePath;
}
public AttachmentInfo(File file, int state) {
if (file.exists()) {
// 如果文件存在
this.state = state;
this.fileName = file.getName();
this.fileNativePath = file.getAbsolutePath();
this.size = file.length();
try {
this.time = ConvertUtil.dateToString(new Date(file
.lastModified()));
} catch (Exception e) {
CommonHelper.log("根据文件信息创建附件转化时间时不正确", e.getMessage());
}
}
}
}
AttachmentActivity:
package com.flagcloud.android.mqservice.biz.attachment;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.UUID;
import android.app.Activity;
import android.app.Dialog;
import android.content.ContentValues;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.flagcloud.android.mqservice.R;
import com.flagcloud.android.mqservice.adapter.AttachmentAdapter;
import com.flagcloud.android.mqservice.async.DownLoadAttachmentListTask;
import com.flagcloud.android.mqservice.async.DownLoadAttachmentListTask.OnDownLoadAtListFinishedListener;
import com.flagcloud.android.mqservice.async.ServiceNoteOperationTask;
import com.flagcloud.android.mqservice.async.ServiceNoteOperationTask.OnServiceNoteOperationFinishedListener;
import com.flagcloud.android.mqservice.biz.attachment.DownLoadUtil.OnDownLoadProcessListener;
import com.flagcloud.android.mqservice.biz.attachment.UploadUtil.OnUploadProcessListener;
import com.flagcloud.android.mqservice.common.Constant;
import com.flagcloud.android.mqservice.common.ResponseObjectUtil;
import com.flagcloud.android.mqservice.model.bindingmodel.ServiceNoteAttachmentsBindingModel;
import com.flagcloud.android.mqservice.model.entity.AttachmentInfo;
import com.flagcloud.android.mqservice.model.entity.ServiceNoteAttachmentInfo;
import com.flagcloud.android.mqservice.model.listitem.OperationListItemViewModel;
import com.flagcloud.android.mqservice.util.CommonHelper;
import com.flagcloud.android.mqservice.util.FileUtil;
import com.flagcloud.android.mqservice.util.GetAbsolutePathUtil;
import com.flagcloud.android.mqservice.util.GsonUtil;
import com.flagcloud.android.mqservice.util.ImageUtil;
import com.flagcloud.android.mqservice.view.dialog.ConfirmDialog;
import com.flagcloud.android.mqservice.view.dialog.InputAndConfirmDialog;
import com.google.gson.reflect.TypeToken;
//附件活动
public class AttachmentActivity extends Activity implements
OnUploadProcessListener, OnDownLoadProcessListener {
private static final String TAG = "AttachmentActivity";
private static final String PHOTO_PATH = FileUtil.sdcardPath
+ File.separator + FileUtil.APP_FILE_DIRECTOR + File.separator
+ FileUtil.PHOTO_DIR; // 压缩后的图片存放的目录
// 自定义上传相关消息
private static final int TO_UPLOAD_FILE = 1;// 去上传文件
private static final int UPLOAD_FILE_DONE = 2; // 上传完的响应
private static final int UPLOAD_IN_PROCESS = 4; // 上传中(更新进度)
// 自定义下载相关消息
private static final int TO_DOWNLOAD_FILE = 5; // 去下载文件
private static final int DOWNLOAD_FILE_DONE = 6; // 下载文件完成
private static final int DOWNLOAD_IN_PROCESS = 7; // 文件下载中(更新进度)
private ArrayList<AttachmentInfo> attachmentInfoList = new ArrayList<AttachmentInfo>();
private SharedPreferences sp;
private File photoFile;
public static final int REQUEST_CODE_JOBREPORT = 0x0061,
REQUEST_CODE_OTHER = 0x0062;
private Uri photoUri;
private String subPhotoPath; // 图片目录
private String serviceNoteId = null;
private AttachmentInfo currentUpLoadPhotoInfo; // 当前正在上传的对象
private AttachmentInfo currentDownLoadFileInfo; // 当前正在下载的对象
private AttachmentAdapter attachmentAdapter;
private boolean isFirstComeIn; // 是否是首次进入
private int longClickPosition = -1; // 长按的位置
private Boolean isUpLoading = false; // 是否有图片正在上传
private Boolean isDownLoading = false; // 是否有文件正在下载
private int currentUploadFileTotalSize = 0; // 图片大小加上头部尾部长度
private long currentDownLoadFileTotalSize = 0; // 当前下载的文件大小
private Button goBackButton;
private ListView fileInfoListView;
private TextView topTitle;
private InputAndConfirmDialog changeFileNameDialog;
private Button selectFileButton; // 选择附件的按钮
private RelativeLayout selectFileRL; // 下部选择文件的整体布局
private AttachmentInfo selectedNewInfo; // 用户选择的新的附件
private Button delButton;
private Button undoButton;
private Button cancelButton;
private Dialog menuDialog;
private Dialog selectImageDialog;
private ConfirmDialog confirmDialog;
private Dialog selectDeleteTypeDialog;
// 下载附件列表的异步任务
private DownLoadAttachmentListTask downLoadSNList;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
doGoBack();
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_up_load_attachment);
// 创建图片的保存目录
initializeView();
addListener();
sp = PreferenceManager.getDefaultSharedPreferences(this);
// 将选择的图片保存到应用目录下的photos+任务单id为文件夹的子目录下
// 进入即创建图片缓存目录,创建photos目录
boolean success = FileUtil.createSDDir(FileUtil.APP_FILE_DIRECTOR
+ File.separator + FileUtil.PHOTO_DIR);
if (!success) {
Toast.makeText(this, "文件夹创建失败", Toast.LENGTH_SHORT).show();
return;
}
Log.i(TAG, "getAttachmentListFromServer执行了");
Intent i = getIntent();
serviceNoteId = i.getStringExtra("serviceNoteId");
if (TextUtils.isEmpty(serviceNoteId)) {
Toast.makeText(this, "任务单id有误", Toast.LENGTH_SHORT).show();
return;
}
// 创建子目录
boolean success2 = FileUtil.createSDDir(FileUtil.APP_FILE_DIRECTOR
+ File.separator &#