Android开发笔记(六十一)文件下载与上传
2016-02-10 23:15
501 查看
下载管理DownloadManager
文件下载其实是网络数据访问的一种特殊形式,使用普通的http请求也能完成,就是实现起来会繁琐一些。因为下载功能比较常用,而且业务功能相对统一,所以从Android 2.3(API level 9)开始,Android提供了DownloadManager用于统一管理下载功能。下载请求
要想使用下载功能,首先得构建一个下载请求,说明从哪里下载、下载参数为何、下载的文件保存到哪里等等。这个下载请求便是DownloadManager的子类Request,下面是该类的常用方法Request构造函数 : 指定从哪个网络地址下载文件。
Request.setAllowedNetworkTypes : 指定允许进行下载的网络类型。Request.NETWORK_WIFI表示wifi环境(推荐),Request.NETWORK_MOBILE表示数据连接环境(不推荐),Request.NETWORK_BLUETOOTH表示蓝牙环境。
Request.setDestinationInExternalFilesDir : 设置下载文件在本地的保存路径。
Request.addRequestHeader : 给HTTP请求添加头部参数。
Request.setMimeType : 设置下载文件的媒体类型。
Request.setVisibleInDownloadsUi : 设置下载页面是否可见。
Request.setNotificationVisibility : 设置通知栏上的下载任务的可见类型。Request.VISIBILITY_HIDDEN表示隐藏,Request.VISIBILITY_VISIBLE表示下载时可见(下载完成后消失),Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED表示下载进行时与完成后都可见,Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION表示只有下载完成后可见。注意可见类型设置为VISIBILITY_HIDDEN时,需要在AndroidManifest.xml中加入对应权限,即android.permission.DOWNLOAD_WITHOUT_NOTIFICATION
Request.setTitle : 设置通知栏上的消息标题。不建议自行设置标题,因为默认标题是下载的文件名。
Request.setDescription : 设置通知栏上的消息描述。不建议自行设置描述,因为默认描述是系统估算的下载剩余时间。
下载操作
构建下载请求完毕,然后才能进行下载的相关操作。下面是DownloadManager常用的下载方法:enqueue : 将下载请求加入到任务队列中,即开始下载任务。该方法返回本次下载任务的编号。
remove : 取消指定编号的下载任务。
restartDownload : 重新下载指定编号的任务。
openDownloadedFile : 打开下载完成的文件。
getMimeTypeForDownloadedFile : 获取下载完成的文件的媒体类型。
查询下载进度
虽然下载进度可在通知栏上查看,但是有时APP自身也想了解当前的下载进度,那就要调用DownloadManager的query方法。该方法的输入参数是一个Query对象,返回结果集的Cursor游标,有关Cursor的用法参见《Android开发笔记(三十一)SQLite游标及其数据结构》。下面是Query类的常用方法:query : 查询指定编号任务的当前下载信息。
Query.setFilterById : 根据编号来过滤下载任务。
Query.setFilterByStatus : 根据状态来过滤下载任务。
下载事件
与文件下载有关的事件不是由监听器实现,而是由广播来实现。主要的下载事件有下面三个:1、下载完成事件:在下载完成时,系统会发出一个action为DownloadManager.ACTION_DOWNLOAD_COMPLETE(android.intent.action.DOWNLOAD_COMPLETE)的广播,因此可注册一个该广播的接收器,用来判断当前下载任务是否已下载完毕,以及后续的处理。
2、下载进行时的通知栏点击事件:在下载过程中,用户点击通知栏上的下载任务,系统便发出action为DownloadManager.ACTION_NOTIFICATION_CLICKED(android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED)的广播,所以可注册该广播的接收器进行相关处理,比如说跳转到该任务的下载进度页面;
3、下载完成后的通知栏点击事件:在不同时刻点击下载任务,会触发不同的事件。下载未完成时点击,触发的是系统广播DownloadManager.ACTION_NOTIFICATION_CLICKED;下载完成后点击,触发的是系统的ACTION_VIEW即浏览页,该动作由系统根据媒体类型去寻找对应的程序来打开,并没有发出广播消息。如果我们要控制此时的点击行为,可以在Request中通过setMimeType方法设置媒体类型,这样Android就会按照这个类型做对应的浏览处理。
断点续传及其他
博主一开始学习DownloadManager时,就觉得好奇怪,该工具竟然没有提供暂停方法和恢复方法,这岂不意味着,文件下载没法断点续传了么?后来在实际开发中测试发现,DownloadManager其实比较智能,当网络一直是允许类型时,任务会一直下载;当网络断开或者不在允许范围内时,任务会自动暂停下载;只要网络连上或者切换到允许范围内,那么任务会自动恢复下载(这里会断点续传)。所以呢,开发者不用关心异常中断,也不用关心网络切换时的额外处理了,原来DownloadManager都已经帮我们实现了。另外,同一个文件被重复下载时,已经下载完的文件并不会被覆盖,后来下载的文件会自动重命名。所以有时会发现下载下来的文件名与源文件名不一致,这很可能是重复下载造成了文件重命名。
自定义进度条
文件下载和上传都经常用到进度条,可是Android自带的ProgressBar无法显示进度百分比的文本。既然如此,我们还是基于ProgressBar自定义一个附带百分比文本的进度条,顺便复习一下自定义视图的用法。首先在自定义类CustomProgressBar中声明一个画笔与百分比文本,然后提供百分比文本的设置和获取方法,最后重写onDraw方法,在控件中央使用drawText函数画上百分比文本。百分比文本的颜色可通过画笔的setColor来设置,文本大小可通过画笔的setTextSize来设置。
下面是CustomProgressBar的代码示例:
import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.ProgressBar; public class CustomProgressBar extends ProgressBar { private String mProgressText; private Paint mPaint; public CustomProgressBar(Context context) { super(context); initPaint(); } public CustomProgressBar(Context context, AttributeSet attrs) { super(context, attrs); initPaint(); } public CustomProgressBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initPaint(); } private void initPaint() { mPaint = new Paint(); mPaint.setColor(Color.BLACK); mPaint.setTextSize(30); } public void setProgressText(String text) { mProgressText = text; } public String getProgressText() { return mProgressText; } @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); Rect rect = new Rect(); mPaint.getTextBounds(mProgressText, 0, mProgressText.length(), rect); int x = (getWidth() / 2) - rect.centerX(); int y = (getHeight() / 2) - rect.centerY(); canvas.drawText(mProgressText, x, y, this.mPaint); } }
文件上传
很可惜Android没有提供专门的文件上传工具类,所以我们要自己写代码实现上传功能了。其实也不难,一样是按照普通网络访问的POST流程,只是要采用multipart方式来分段传输。另外文件上传需要运用打开文件的对话框,文件对话框的介绍参见《Android开发笔记(二十三)文件对话框FileDialog》。下面是文件上传的工具类代码:
public int uploadFile(String uploadUrl, String uploadFile) { String fileName = ""; int pos = uploadFile.lastIndexOf("/"); if (pos >= 0) { fileName = uploadFile.substring(pos + 1); } String end = "/r/n"; String Hyphens = "--"; String boundary = "*****"; try { URL url = new URL(uploadUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); /* 允许Input、Output,不使用Cache */ conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); /* 设定传送的method=POST */ conn.setRequestMethod("POST"); /* setRequestProperty */ conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); /* 设定DataOutputStream */ DataOutputStream ds = new DataOutputStream(conn.getOutputStream()); ds.writeBytes(Hyphens + boundary + end); ds.writeBytes("Content-Disposition: form-data; " + "name=\"file1\";filename=\"" + fileName + "\"" + end); ds.writeBytes(end); /* 取得文件的FileInputStream */ FileInputStream fStream = new FileInputStream(uploadFile); /* 设定每次写入1024bytes */ int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; int length = -1; /* 从文件读取数据到缓冲区 */ do { length = fStream.read(buffer); /* 将数据写入DataOutputStream中 */ ds.write(buffer, 0, length); } while (length != -1); ds.writeBytes(end); ds.writeBytes(Hyphens + boundary + Hyphens + end); fStream.close(); ds.flush(); /* 取得Response内容 */ InputStream is = conn.getInputStream(); int ch; StringBuffer b = new StringBuffer(); while ((ch = is.read()) != -1) { b.append((char) ch); } ds.close(); Log.d(TAG, "上传成功"); } catch (Exception e) { Log.d(TAG, "上传失败" + e.getMessage()); mUploadId = -1; } return mUploadId; }
系统服务清单
到本文为止,Android的系统服务基本都用过了一遍,下面统计一下这些系统服务及其对应的章节说明:CONNECTIVITY_SERVICE : 网络连接服务(android.net.ConnectivityManager),参见《Android开发笔记(五十五)手机设备基本操作》与《Android开发笔记(六十)网络检测与连接》。
TELEPHONY_SERVICE : 电话设备服务(android.telephony.TelephonyManager),参见《Android开发笔记(四十六)手机相关事件》和《Android开发笔记(五十五)手机设备基本操作》。
WIFI_SERVICE : wifi与热点服务(android.net.wifi.WifiManager),参见《Android开发笔记(五十五)手机设备基本操作》与《Android开发笔记(六十)网络检测与连接》。
LAYOUT_INFLATER_SERVICE : 布局填充服务(android.view.LayoutInflater),参见《Android开发笔记(十二)测量尺寸与下拉刷新》。
SEARCH_SERVICE : 搜索管理服务(android.app.SearchManager),参见《Android开发笔记(二十)顶部导航栏ActionBar》。
WINDOW_SERVICE : 视窗管理服务(android.view.WindowManager),参见《Android开发笔记(三)屏幕分辨率》。
LOCATION_SERVICE : 定位服务(android.location.LocationManager),参见《Android开发笔记(四十六)手机相关事件》和《Android开发笔记(五十五)手机设备基本操作》。
ALARM_SERVICE : 闹钟/定时器服务(android.app.AlarmManager),参见《Android开发笔记(五十)定时器AlarmManager》。
NOTIFICATION_SERVICE : 通知推送服务(android.app.NotificationManager),参见《Android开发笔记(五十二)通知推送Notification》。
AUDIO_SERVICE : 铃声服务(android.media.AudioManager),参见《Android开发笔记(五十八)铃声与震动》。
VIBRATOR_SERVICE : 震动服务(android.os.Vibrator),参见《Android开发笔记(五十八)铃声与震动》。
SENSOR_SERVICE : 传感器服务(android.hardware.SensorManager),参见《Android开发笔记(五十九)巧用传感器》。
ACTIVITY_SERVICE : 活动管理服务(android.app.ActivityManager),参见《Android开发笔记(七十九)资源与权限校验》和《Android开发笔记(八十)运行状态检查》。
DOWNLOAD_SERVICE : 下载管理服务(android.app.DownloadManager),参见《Android开发笔记(六十一)文件下载与上传》。
INPUT_METHOD_SERVICE : 输入法服务(android.view.inputmethod.InputMethodManager),参见《Android开发笔记(三十六)展示类控件》。
KEYGUARD_SERVICE : 键盘锁服务(android.app.KeyguardManager)
MEDIA_ROUTER_SERVICE : 媒体路由服务(android.media.MediaRouter)
POWER_SERVICE : 电源管理服务(android.os.PowerManager)
STORAGE_SERVICE : 存储管理服务(android.os.storage.StorageManager),参见《Android开发笔记(七十九)资源与权限校验》。
UI_MODE_SERVICE : 界面模式服务(android.app.UiModeManager)
代码示例
下面是文件下载查询进度的效果截图:下面是文件下载的代码例子:
import java.util.HashMap; import com.example.exmload.R; import com.example.exmload.util.Utils; import android.annotation.SuppressLint; import android.app.Activity; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.app.DownloadManager.Request; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @SuppressLint({ "DefaultLocale", "SimpleDateFormat" }) public class DownloadActivity extends Activity implements OnClickListener { private static final String TAG = "DownloadActivity"; private ConnectivityManager mConnectMgr; private DownloadManager mDownloadManager; private Button btn_download_notify_apk; private Button btn_download_notify_jpg; private Button btn_download_without_notify; private Button btn_cancel; private static TextView tv_download; private static TextView tv_notify; private ProgressBar pb_download; private static long mDownloadId = 0; private Uri mApkUri = Uri.parse("http://www.lenovomm.com/appdown/20091038-2"); private Uri mJpgUri = Uri.parse("http://c.hiphotos.baidu.com/news/q%3D100/sign=b8e532c9ee50352ab76121086343fb1a/9c16fdfaaf51f3de3699841a93eef01f3a2979a0.jpg"); private String mApkDir = "Download/alipay.apk"; private String mJpgDir = "Download/news.jpg"; private HashMap<Integer,String> mStatusMap = new HashMap<Integer,String>(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_download); mConnectMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); mDownloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); btn_download_notify_apk = (Button) findViewById(R.id.btn_download_notify_apk); btn_download_notify_jpg = (Button) findViewById(R.id.btn_download_notify_jpg); btn_download_without_notify = (Button) findViewById(R.id.btn_download_without_notify); btn_cancel = (Button) findViewById(R.id.btn_cancel); tv_download = (TextView) findViewById(R.id.tv_download); tv_notify = (TextView) findViewById(R.id.tv_notify); pb_download = (ProgressBar) findViewById(R.id.pb_download); pb_download = (ProgressBar) findViewById(R.id.pb_download); btn_download_notify_apk.setOnClickListener(this); btn_download_notify_jpg.setOnClickListener(this); btn_download_without_notify.setOnClickListener(this); btn_cancel.setOnClickListener(this); mStatusMap.put(DownloadManager.STATUS_PENDING, "挂起"); mStatusMap.put(DownloadManager.STATUS_RUNNING, "运行中"); mStatusMap.put(DownloadManager.STATUS_PAUSED, "暂停"); mStatusMap.put(DownloadManager.STATUS_SUCCESSFUL, "成功"); mStatusMap.put(DownloadManager.STATUS_FAILED, "失败"); } //接收下载完成后的intent public static class DownloadCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); Log.d(TAG," download complete! id : "+downId+", mDownloadId="+mDownloadId); tv_download.setVisibility(View.VISIBLE); tv_download.setText(Utils.getNowDateTime()+" 编号"+downId+"的下载任务已完成"); } } } //接收通知栏点击的intent public static class NotificationClickReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d(TAG," NotificationClickReceiver onReceive"); if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) { long[] downIds = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); for (long downId : downIds) { Log.d(TAG," notify click! id : "+downId+", mDownloadId="+mDownloadId); if (downId == mDownloadId) { tv_notify.setVisibility(View.VISIBLE); tv_notify.setText(Utils.getNowDateTime()+" 编号"+downId+"的下载进度条被点击了一下"); } } } } } @Override public void onClick(View v) { pb_download.setVisibility(View.GONE); tv_download.setVisibility(View.GONE); tv_notify.setVisibility(View.GONE); NetworkInfo info = mConnectMgr.getActiveNetworkInfo(); if (info == null || info.getState() != NetworkInfo.State.CONNECTED) { Toast.makeText(this, "当前无可用的上网连接", Toast.LENGTH_LONG).show(); } else if (info.getType() != ConnectivityManager.TYPE_WIFI) { Toast.makeText(this, "当前非wifi环境,请连接wifi后下载", Toast.LENGTH_LONG).show(); } if (v.getId() == R.id.btn_download_notify_apk) { Request down = new Request(mApkUri); down.setAllowedNetworkTypes(Request.NETWORK_MOBILE|Request.NETWORK_WIFI); // down.setTitle("APK下载信息"); // down.setDescription("这是一个APK下载任务"); down.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); down.setVisibleInDownloadsUi(true); down.setDestinationInExternalFilesDir(this, null, mApkDir); mDownloadId = mDownloadManager.enqueue(down); } else if (v.getId() == R.id.btn_download_notify_jpg) { Request down_request = new Request(mJpgUri); down_request.setAllowedNetworkTypes(Request.NETWORK_MOBILE|Request.NETWORK_WIFI); down_request.setTitle("JPG下载信息"); down_request.setDescription("这是一个JPG下载任务"); down_request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); down_request.setVisibleInDownloadsUi(true); down_request.setDestinationInExternalFilesDir(this, null, mJpgDir); mDownloadId = mDownloadManager.enqueue(down_request); } else if (v.getId() == R.id.btn_download_without_notify) { Request down_request = new Request(mApkUri); down_request.setAllowedNetworkTypes(Request.NETWORK_MOBILE|Request.NETWORK_WIFI); down_request.setNotificationVisibility(Request.VISIBILITY_HIDDEN); down_request.setVisibleInDownloadsUi(false); down_request.setDestinationInExternalFilesDir(this, null, mApkDir); mDownloadId = mDownloadManager.enqueue(down_request); mHandler.postDelayed(mRefresh, 1000); } else if (v.getId() == R.id.btn_cancel) { mDownloadManager.remove(mDownloadId); tv_download.setVisibility(View.VISIBLE); tv_download.setText(Utils.getNowDateTime()+" 编号"+mDownloadId+"的下载任务已取消"); mHandler.removeCallbacks(mRefresh); } } private Handler mHandler = new Handler(); private Runnable mRefresh = new Runnable() { @Override public void run() { boolean bFinish = false; Query down_query = new Query(); down_query.setFilterById(mDownloadId); Cursor cursor = mDownloadManager.query(down_query); if (cursor.moveToFirst()) { for (;; cursor.moveToNext()) { int nameIdx = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); int mediaTypeIdx = cursor.getColumnIndex(DownloadManager.COLUMN_MEDIA_TYPE); int totalSizeIdx = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES); int nowSizeIdx = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); int statusIdx = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); int progress = (int)(pb_download.getMax()* cursor.getLong(nowSizeIdx)/cursor.getLong(totalSizeIdx)); pb_download.setVisibility(View.VISIBLE); pb_download.setProgress(progress); if (cursor.getString(nameIdx) == null) { break; } String desc = ""; desc = String.format("%s文件路径:%s\n", desc, cursor.getString(nameIdx)); desc = String.format("%s媒体类型:%s\n", desc, cursor.getString(mediaTypeIdx)); desc = String.format("%s文件总大小:%d\n", desc, cursor.getLong(totalSizeIdx)); desc = String.format("%s已下载大小:%d\n", desc, cursor.getLong(nowSizeIdx)); desc = String.format("%s下载进度:%d%%\n", desc, progress); desc = String.format("%s下载状态:%s\n", desc, mStatusMap.get(cursor.getInt(statusIdx))); tv_notify.setVisibility(View.VISIBLE); tv_notify.setText(desc); if (progress == pb_download.getMax()) { bFinish = true; } if (cursor.isLast() == true) { break; } } } cursor.close(); if (bFinish != true) { mHandler.postDelayed(this, 1000); } } }; }
下面是文件上传的代码例子:
import java.util.ArrayList; import java.util.Map; import com.example.exmload.util.FileResource; import com.example.exmload.util.UploadUtil; import com.example.exmload.util.Utils; import com.example.exmload.widget.CustomProgressBar; import com.example.exmload.widget.FileSelectFragment; import com.example.exmload.widget.FileSelectFragment.FileSelectCallbacks; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; public class UploadActivity extends Activity implements OnClickListener,FileSelectCallbacks { private static final String TAG = "DownloadActivity"; private static EditText et_server; private static TextView tv_filename; private Button btn_select; private Button btn_upload; private CustomProgressBar pb_upload; private int mUploadId; private UploadUtil mUpload = new UploadUtil(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_upload); et_server = (EditText) findViewById(R.id.et_server); tv_filename = (TextView) findViewById(R.id.tv_filename); btn_select = (Button) findViewById(R.id.btn_select); btn_upload = (Button) findViewById(R.id.btn_upload); pb_upload = (CustomProgressBar) findViewById(R.id.pb_upload); btn_select.setOnClickListener(this); btn_upload.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.btn_select) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); //软键盘如果已经打开则关闭之 if (imm.isActive() == true) { imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); } FileResource fileRes = new FileResource(this); FileSelectFragment fsf = FileSelectFragment.newInstance( FileSelectFragment.Mode.FileSelector, fileRes.dialog_height, // 对话框高度 R.string.btn_ok, R.string.btn_cancel, R.string.tag_title_OpenFile, fileRes.resourceID_Icon, fileRes.resourceID_Directory, fileRes.resourceID_UpDirectory, fileRes.resourceID_File); ArrayList<String> allowedExtensions = new ArrayList<String>(); allowedExtensions.add(".jpg"); allowedExtensions.add(".png"); allowedExtensions.add(".gif"); fsf.setFilter(FileSelectFragment.FiletypeFilter(allowedExtensions), null); String fragTag = getResources().getString(R.string.tag_fragment_FileSelect); fsf.show(getFragmentManager(), fragTag); } else if (v.getId() == R.id.btn_upload) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(et_server.getWindowToken(), 0); if (et_server.getText().toString().length() <= 0) { Toast.makeText(this, "请输入服务器上传地址", Toast.LENGTH_LONG).show(); } else if (tv_filename.getText().toString().length() <= 0) { Toast.makeText(this, "请选择要上传的文件", Toast.LENGTH_LONG).show(); } else { //上传文件需要服务端配合。所以这里使用了测试方法来代替 mUploadId = mUpload.uploadFileTest(et_server.getText().toString(), tv_filename.getText().toString()); mHandler.postDelayed(mRefresh, 100); } } } private Handler mHandler = new Handler(); private Runnable mRefresh = new Runnable() { @Override public void run() { double progress = mUpload.getProgress(mUploadId); String text = String.format("编号%d目前上传进度是%s%%", mUploadId, Utils.getDotOne(progress)); pb_upload.setVisibility(View.VISIBLE); pb_upload.setProgress((int)progress); pb_upload.setProgressText(text); if (progress < 100) { mHandler.postDelayed(this, 1000); } } }; @Override public void onConfirmSelect(String absolutePath, String fileName, Map<String, Object> map_param) { String path = absolutePath + "/" + fileName; tv_filename.setText(path); } @Override public boolean isFileValid(String absolutePath, String fileName, Map<String, Object> map_param) { return true; } }
点此查看Android开发笔记的完整目录
相关文章推荐
- Android TV Study 1-1
- android 中的Uri详解
- 21天学习android开发教程之XML解析与生成
- 21天学习android开发教程之SQLite分页读取
- Android实现创意LoadingView动画效果
- Android聊天工具基于socket实现
- android 中的Cursor
- Android开发中如何实现外部其他Activity类与指定fragment碎片的相互跳转
- Android 解析 xml
- Android ndk jni log 输出 打印 调试
- Android studio的那些bug
- android.os.NetworkOnMainThreadException
- Android Volley完全解析(一),初识Volley的基本用法
- AndroidStudio出现错误
- 【Android】7.3 GridLayout(网格布局)
- 【Android开发小记--19】数据存储3--ContentProvider
- 【Android】7.2 LinearLayout(线性布局)
- 【Android】7.1 布局控件常用的公共属性
- android 注解框架 butterKnife 和AndroidAnnotations
- Android EditText取消焦点并关闭输入法