下载的流程:
文件下载的代码:public class DownloadActivity extends AppCompatActivity { PRivate ProgressBar mProgressBar; //准备下载 public static final int BEGIN = 0; //正在下载 public static final int DOWNLOADING = 1; //结束下载 public static final int END = 2; //下载的进度 private static int progress; //是否停止下载 private boolean cancel ; OkHttpClient okHttpClient = new OkHttpClient(); MyHandler mHandler = new MyHandler(this); private ImageView mShowImage; ByteArrayOutputStream baos = new ByteArrayOutputStream(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_download); mProgressBar = (ProgressBar) findViewById(R.id.down_progress_bar); mShowImage = (ImageView) findViewById(R.id.down_image); } public void click2(View view) { cancel = true; } public void click(View view) { cancel = false; new Thread(new Runnable() { @Override public void run() { //实例化Builder对象 Request.Builder builder = new Request.Builder(); //设置Url builder.url(Config.IMAGE_URL); //获取已经下载的大小 int size = baos.size(); //size表示已经下载的大小。如果不为0,则进行断点续传。 if (size > 0) { //设置断点续传的开始位置,格式bytes=123456- builder.header("Range", "bytes=" + size + "-"); //设置ProgressBar的当前进度从停止位置开始 progress = size; } //创建Request对象 Request request = builder.build(); try { //执行下载请求,并获得Response对象 Response response = okHttpClient.newCall(request).execute(); //请求成功 if (response.isSuccessful()) { //从Response对象中获取输入流对象 InputStream inputStream = response.body().byteStream(); //size==0表示第一次下载,非断点续传 if (size == 0) { //获取文件的大小 int contentLength = (int) response.body().contentLength(); //将文件总大小通过Handler传递到UI线程,设置ProgressBar的总进度值 mHandler.obtainMessage(BEGIN,contentLength,0).sendToTarget(); } int len = 0; byte[] buffer = new byte[1024]; //循环读取文件流,开始下载 while((len = inputStream.read(buffer)) != -1) { if (cancel) { //如果点击了停止按钮,cancel为true。则结束循环 break; } //将流写入缓存 baos.write(buffer,0,len); baos.flush(); //发送下载进度 mHandler.obtainMessage(DOWNLOADING,len,0).sendToTarget(); } //下载完成,结束请求,关闭body response.body().close(); //将字节转成Bitmap对象 byte[] bytes = baos.toByteArray(); Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); //下载完成通知更新试图 mHandler.obtainMessage(END,bitmap).sendToTarget(); } } catch (IOException e) { e.printStackTrace(); } } }).start(); } static class MyHandler extends Handler { private WeakReference<DownloadActivity> activityWeakReference; public MyHandler(DownloadActivity activity) { this.activityWeakReference = new WeakReference<DownloadActivity>(activity); } @Override public void handleMessage(Message msg) { switch (msg.what) { case BEGIN: activityWeakReference.get().mProgressBar.setMax(msg.arg1); break; case DOWNLOADING: progress += msg.arg1; activityWeakReference.get().mProgressBar.setProgress(progress); break; case END: progress = 0; activityWeakReference.get().mShowImage.setImageBitmap((Bitmap)msg.obj); break; } } }}复制代码以上是文件下的代码。实现了断点续传,其中能进行断点续传的关键代码为builder.header("Range", "bytes=" + size + "-");代码中都有注释,结合上面的流程图应该不难理解。代码解释:源码的效果是点击开始按钮出发click事件开始下载,点击停止按钮触发click2事件中断下载。下载的进度监听是在while循环中,通过Handler进行的进度更新。文件上传本案例中,实现带参数的文件上传功能-----同时完成参数传递和文件上传。代码如下:public class UploadActivity extends AppCompatActivity { public static final int GET_PIC = 1; private ImageView mShowImage; private Uri uri; OkHttpClient okHttpClient = new OkHttpClient(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_upload); mShowImage = (ImageView) findViewById(R.id.upload_show_image); } public void click(View view) { switch (view.getId()) { case R.id.upload_choose_file: choosePic();//选择图片 break; case R.id.upload_start: upload();//上传 break; } } /** * 上传 */ private void upload() { if (uri == null) { Toast.makeText(UploadActivity.this, "请先选择文件", Toast.LENGTH_SHORT).show(); return; } //设置文件的媒体类型,image/*表示匹配所有的图片文件 MediaType mediaType = MediaType.parse("image/*"); MultipartBody.Builder builder = new MultipartBody.Builder(); //文件上传,此处是关键,设置媒体类型为multipart/form-data,表示多种格式的表单数据上传 builder.setType(MultipartBody.FORM); //添加上传的参数username=androidxx builder.addFormDataPart("username","androidxx"); //添加上传的文件。文件是从相册读取的文件流。 try { //获得需要上传的文件流 InputStream inputStream = getContentResolver().openInputStream(uri); int len = 0; byte[] buffer = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while((len = inputStream.read(buffer)) != -1) { baos.write(buffer, 0, len); } inputStream.close(); /* * 添加文件到Builder中。如果要实现多文件同时上传,可以添加多个addFormDataPart。 * 注意: * 参数一:上传的文件的标示,同username。也就是可以在服务器端通过upload找到对应的文件流 * 参数二:文件的名称。上传到服务器之后以此名称命名文件 * 参数三:需要上传的文件。包含在RequestBody中 * RequestBody.create方法有多个重载的方法,可以选择不同的数据源。此处选择的是字节形式(baos.toByteArray())的数据眼。 */builder.addFormDataPart("upload", "test.jpg", RequestBody.create(mediaType, baos.toByteArray())); } catch (IOException e) { e.printStackTrace(); } //创建MultipartBody对象,MultipartBody是RequestBody的子类,用于文件上传。 MultipartBody multipartBody = builder.build(); Request request = new Request.Builder() .url("http://192.168.3.4:8080/WebServer/upload.do")//上传的服务器地址 .post(multipartBody) .build(); //开始上传。采用Post异步请求的方式 okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d("androidxx.cn","--" + e.getMessage()); e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { //接受到成功的返回结果 if (response.isSuccessful()) { Log.d("androidxx.cn","-上传成功-"); } else { Log.d("androidxx.cn","-失败--" + response.body().string()); } } }); } /** * 打开相册,选择文件后返回 */ private void choosePic() { Intent intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("image/*"); startActivityForResult(intent,GET_PIC); } /** * 接收选择的图片 * @param requestCode * @param resultCode * @param data */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_CANCELED) { return; } //获得图片的URI uri = data.getData(); //通过ContentResolver获得图片对象 ContentResolver contentResolver = getContentResolver(); InputStream inputStream = null; try { inputStream = contentResolver.openInputStream(uri); } catch (FileNotFoundException e) { e.printStackTrace(); } //将流转换成图片,显示到ImageView中 Bitmap bitmap = BitmapFactory.decodeStream(inputStream); mShowImage.setImageBitmap(bitmap); }}复制代码如上代码,第37行和第59行是上传能成功的重点。多文件长传实现多文件上传,只需将上面单文件上传中的builder.addFormDataPart("upload", "test.jpg", RequestBody.create(mediaType, baos.toByteArray()));这一句执行多次,即使用多个addFormDataPart方法添加多个文件,然后就可以同时上传多个文件了。总结1、文件上传和下载的过程其实就是一种特殊的Post和Get请求。总体的过程与Post请求和Get请求方式一样。2、下载相当于一个特殊的Get请求,只是服务器返回的数据格式是文件流。我们也只能通过读取流来获得数据。3、上传相当于一个特殊的Post请求,前面我们说过,Post请求就是传参数比较特殊和多样化。文件上传就是一种特殊的参数传递----参数是一个文件。大家在看如上代码的时候,不要觉得陌生,其实代码的流程和逻辑同Post和Get请求一样,只是多了几行代码。本案例的android端源码:Github本案例的上传服务器配置方式【点击查看】,上传服务端源码:Github 服务器端代码请阅读Github中的readme.md文件。服务器端代码导入工程没有错之后,可以将代码加载到服务器,之后启动服务器就可以运行。本案例使用的是Tomcat服务器。备注:对于android程序员如果想运行服务器代码,按照readme.md文档。然后有不懂的,可以留言。转载请注明:androidxx.cn最后附上下载效果(注意点击按钮开始和停止后下载进度条的变化,实现断点续传)。
新闻热点
疑难解答