本文基于AsyncHttpClient实现了断点续传的功能(对于AsyncHttpClient导入及基本用法请参照我的上一篇文章)
1、先看下功能UI界面(下载:实现对文件的请求;取消:取消当前下载;删除:取消当前下载,删除下载的文件,将进度条重置)
注意:您应该验证,当你在下载过程中,取消了下载后,再次点击下载时是否从上次下载结束的地方开始请求。
2、UI布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" tools:context="com.analysys.asynchttpclientdemothree.activities.MainActivity" android:padding="5dp"> <LinearLayout android:id="@+id/linearLayoutId" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="下载" android:id="@+id/getButtonId" android:layout_alignParentTop="true" android:layout_centerHorizontal="true"/> <Button android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="取消" android:id="@+id/cancelButtonId" android:layout_alignParentTop="true" android:layout_centerHorizontal="true"/> <Button android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="删除" android:id="@+id/deleteButtonId" android:layout_alignParentTop="true" android:layout_centerHorizontal="true"/> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前进度" android:layout_marginTop="10dp" android:id="@+id/textViewId" android:layout_below="@+id/linearLayoutId" android:layout_alignParentRight="true"/> <ProgressBar android:id="@+id/progressBarId" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal" android:layout_below="@id/linearLayoutId" android:layout_toLeftOf="@id/textViewId" android:layout_alignParentLeft="true"/> </RelativeLayout>三、activity类文件
package com.analysys.asynchttpclientdemothree.activities; import android.media.MediaPlayer; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import com.analysys.asynchttpclientdemothree.R; import com.analysys.asynchttpclientdemothree.http_request_engine.HttpRequestEngine; import java.io.File; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private Button get; private Button cancel; private Button deleteButton; private TextView textView; private ProgressBar progressBar; //下面的地址是mp3文件地址,可能会失效;如果失效,您自己替换啊 private String url = "http://wzg.free.fr/Joyeux-anniversaire.mp3"; private MediaPlayer mediaPlayer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView(){ get = (Button)findViewById(R.id.getButtonId); get.setOnClickListener(this); cancel = (Button)findViewById(R.id.cancelButtonId); cancel.setOnClickListener(this); deleteButton = (Button)findViewById(R.id.deleteButtonId); deleteButton.setOnClickListener(this); textView = (TextView)findViewById(R.id.textViewId); progressBar = (ProgressBar)findViewById(R.id.progressBarId); } private void get(){ File filesDir = this.getFilesDir(); filesDir = new File(filesDir.getAbsoluteFile() + "/App"); filesDir.mkdirs(); HttpRequestEngine.get(url, new MainHandle(), filesDir.getAbsolutePath() + "/my.mp3"); } private void cancel(){ //先停止网络请求 HttpRequestEngine.cancelGet(); } private void delete(){ //先停止网络请求 HttpRequestEngine.cancelGet(); //再处理本地UI progressBar.setProgress(0); if (mediaPlayer != null){ mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } //再删除文件 File filesDir = MainActivity.this.getFilesDir(); File file = new File(filesDir.getAbsoluteFile() + "/App/my.mp3"); if (file.exists()){ file.delete(); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.getButtonId: get(); break; case R.id.cancelButtonId: cancel(); break; case R.id.deleteButtonId: delete(); break; } } public class MainHandle extends Handler{ public void handleMessage(Message msg) { //处理下载进度的回调 if (msg.what == HttpRequestEngine.progressNotificationId){ progressBar.setProgress(msg.arg1); textView.setText(msg.arg1 + "%"); } //处理下载完成的回调 if (msg.what == HttpRequestEngine.successNotificationId){ File filesDir = MainActivity.this.getFilesDir(); File file = new File(filesDir.getAbsoluteFile() + "/App/my.mp3"); if (file.exists()){ Log.d("MQL", "大小: " + file.length()); MainActivity.this.installMp3(file); } } //处理下载失败的回调 if (msg.what == HttpRequestEngine.failureNotificationId){ Toast toast = Toast.makeText(MainActivity.this, (String)msg.obj, Toast.LENGTH_LONG); toast.show(); } } } //播放 private void installMp3(File file) {
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
return;
} mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(file.getAbsolutePath()); mediaPlayer.prepare(); mediaPlayer.start(); } catch (Exception e) { e.printStackTrace(); } } }四、HttpRequestEngine文件(该文件实现了断点续传的功能,提供对外的请求接口、取消接口)
package com.analysys.asynchttpclientdemothree.http_request_engine; import android.os.Handler; import android.os.Message; import android.util.Log; import java.io.File; import com.loopj.android.http.*; import cz.msebera.android.httpclient.Header; import cz.msebera.android.httpclient.HttpResponse; /** * Created by MQL on 2016/9/27. * 功能:提供网络请求 */ public class HttpRequestEngine { private static AsyncHttpClient client = new AsyncHttpClient(); private static RequestHandle getRequestHandle; //使用它取消具体某个请求 private static Handler mainHandler; //回调通知 private static String Tag = "MQL"; private static String targetFilePath; //目标文件保存路径 private static long fromLength = 0; //请求前,本地已有的字节大小 public static final int progressNotificationId = 1000; public static final int successNotificationId = 1001; public static final int failureNotificationId = 1002; //不带参数的get请求 public static void get(String url, Handler mainHandler,String targetFilePath ){ //先取消当前活动的请求 cancelGet(); //记录Handler For Callback;记录目标文件保存路径 HttpRequestEngine.mainHandler = mainHandler; HttpRequestEngine.targetFilePath = targetFilePath; //发送新的请求 HttpRequestEngine.get(url, new FileAsyncHttpResponseHandler(new File(targetFilePath), true) { @Override public void onPreProcessResponse(ResponseHandlerInterface instance, HttpResponse response) { Log.d("MQL", "onPreProcessResponse"); if (response.getStatusLine().getStatusCode() == 416){//416: request Range Not Satisfiable, 出现这种请求立即取消请求 if (HttpRequestEngine.mainHandler != null){ Message msg1 = new Message(); msg1.what = HttpRequestEngine.progressNotificationId; msg1.arg1 = 100; HttpRequestEngine.mainHandler.sendMessage(msg1); Message msg2 = new Message(); msg2.what = HttpRequestEngine.successNotificationId; HttpRequestEngine.mainHandler.sendMessage(msg2); } cancelGet(); }else if (response.getStatusLine().getStatusCode() == 403){//Forbidden if (HttpRequestEngine.mainHandler != null){ Message msg = new Message(); msg.what = HttpRequestEngine.failureNotificationId; msg.obj = "Forbidden"; HttpRequestEngine.mainHandler.sendMessage(msg); } cancelGet(); } } public void onSuccess(int statusCode, Header[] headers, File file){ Log.d("MQL", "onSuccess"); if (statusCode == 206) { if (HttpRequestEngine.mainHandler != null){ Message msg = new Message(); msg.what = HttpRequestEngine.successNotificationId; HttpRequestEngine.mainHandler.sendMessage(msg); } } } public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file){ Log.d("MQL", "onFailure: " + throwable.toString()); if (HttpRequestEngine.mainHandler != null){ Message msg = new Message(); msg.what = HttpRequestEngine.failureNotificationId; msg.obj = throwable.toString(); HttpRequestEngine.mainHandler.sendMessage(msg); } } public void onProgress(long bytesWritten, long totalSize) { Log.d("MQL", "" + (bytesWritten + HttpRequestEngine.fromLength) + ", " + (totalSize + HttpRequestEngine.fromLength)); int progress = (int)((totalSize > 0) ? ((bytesWritten + HttpRequestEngine.fromLength) * 1.0 / (totalSize + HttpRequestEngine.fromLength)) * 100 : -1); if (HttpRequestEngine.mainHandler != null){ Message msg = new Message(); msg.what = HttpRequestEngine.progressNotificationId; msg.arg1 = progress; HttpRequestEngine.mainHandler.sendMessage(msg); } } } ); } //不带参数的get请求 private static void get(String url, AsyncHttpResponseHandler responseHandler) { //获取文件大小 File file = new File(HttpRequestEngine.targetFilePath); HttpRequestEngine.fromLength = 0; if (file.exists()){ HttpRequestEngine.fromLength = file.length(); } //通过设置请求头,使请求可以断点处继续请求 client.addHeader("Range", "bytes=" + HttpRequestEngine.fromLength + "-"); HttpRequestEngine.getRequestHandle = client.get(url, responseHandler); } //取消不带参数的get请求 public static void cancelGet(){ if (HttpRequestEngine.getRequestHandle != null){ HttpRequestEngine.getRequestHandle.cancel(true); HttpRequestEngine.getRequestHandle = null; } if (HttpRequestEngine.mainHandler != null){ HttpRequestEngine.mainHandler = null; } } }