Android中Service+Notification断点续传下载

来源:互联网 发布:免费股票交易软件 编辑:程序博客网 时间:2024/06/13 05:21

转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53874148
本文出自【DylanAndroid的博客】


Android中Service+Notification断点续传下载

在Android开发中,我们经常会用到例如版本更新这种的文件下载,那么如何用service+notification去做一个支持断点续传的
文件下载呢?效果图如下

效果图

一.在启动Activity中启动Service

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intent = new Intent(this, TaskService.class);        startService(intent);    }}

2.在Service的启动命令中注册按钮点击广播

    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        registerBroadCast();        download();        return super.onStartCommand(intent, flags, startId);    }/**     * 注册按钮点击广播*     */    private void registerBroadCast() {        myBroadcastReceiver = new MyBroadcastReceiver();        IntentFilter filter = new IntentFilter();        filter.addAction(BROADCAST_ACTION_CLICK);        registerReceiver(myBroadcastReceiver, filter);    }    /**     * 更新通知界面的按钮的广播     */    private class MyBroadcastReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            if (!intent.getAction().equals(BROADCAST_ACTION_CLICK)) {                return;            }            Logger.d("status=" + status);            switch (status) {                case DOWNLOADING:                    /**当在下载中点击暂停按钮**/                    cancelable.cancel();                    mRemoteViews.setTextViewText(R.id.bt, "下载");                    mRemoteViews.setTextViewText(R.id.tv_message, "暂停中...");                    status = Status.PAUSE;                    notificationManager.notify(NOTIFICATION_ID, notification);                    break;                case SUCCESS:                    /**当下载完成点击完成按钮时关闭通知栏**/                    notificationManager.cancel(NOTIFICATION_ID);                    break;                case FAIL:                case PAUSE:                    /**当在暂停时点击下载按钮**/                    download();                    mRemoteViews.setTextViewText(R.id.bt, "暂停");                    mRemoteViews.setTextViewText(R.id.tv_message, "下载中...");                    status = Status.DOWNLOADING;                    notificationManager.notify(NOTIFICATION_ID, notification);                    break;            }        }    }

3.开始下载用xutils3

    /**     * 下载文件     */    private void download() {        final String url = "https://github.com/linglongxin24/DylanStepCount/raw/master/app-debug.apk";        RequestParams requestParams = new RequestParams(url);        String fileName = url.substring(url.lastIndexOf("/") + 1);        file = new File(filePath, fileName);        showNotificationProgress(TaskService.this);        showFileName(fileName);        requestParams.setSaveFilePath(file.getPath());        /**自动为文件命名**/        requestParams.setAutoRename(true);        /**自动为文件断点续传**/        requestParams.setAutoResume(true);        cancelable = x.http().get(requestParams, new Callback.ProgressCallback<File>() {            @Override            public void onSuccess(File result) {                Logger.d("下载完成");                Logger.d("result=" + result.getPath());                downloadSuccess();            }            @Override            public void onError(Throwable ex, boolean isOnCallback) {                Logger.d("下载异常");                downloadFail();            }            @Override            public void onCancelled(CancelledException cex) {                Logger.d("下载已取消");            }            @Override            public void onFinished() {            }            @Override            public void onWaiting() {            }            @Override            public void onStarted() {            }            @Override            public void onLoading(long total, long current, boolean isDownloading) {                Logger.d("total=" + total + "--" + "current=" + current);                updateNotification(total, current);            }        });    }

4.显示通知

    /**     * 显示一个下载带进度条的通知     *     * @param context 上下文     */    public void showNotificationProgress(Context context) {        /**进度条通知构建**/        NotificationCompat.Builder builderProgress = new NotificationCompat.Builder(context);        /**设置为一个正在进行的通知**/        builderProgress.setOngoing(true);        /**设置小图标**/        builderProgress.setSmallIcon(R.mipmap.ic_launcher);        /**新建通知自定义布局**/        mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.notification);        /**进度条ProgressBar**/        mRemoteViews.setProgressBar(R.id.pb, 100, 0, false);        /**提示信息的TextView**/        mRemoteViews.setTextViewText(R.id.tv_message, "下载中...");        /**操作按钮的Button**/        mRemoteViews.setTextViewText(R.id.bt, "暂停");        /**设置左侧小图标*/        mRemoteViews.setImageViewResource(R.id.iv, R.mipmap.ic_launcher);        /**设置通过广播形式的PendingIntent**/        Intent intent = new Intent(BROADCAST_ACTION_CLICK);        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_BROADCAST, intent, 0);        mRemoteViews.setOnClickPendingIntent(R.id.bt, pendingIntent);        /**设置自定义布局**/        builderProgress.setContent(mRemoteViews);        /**设置滚动提示**/        builderProgress.setTicker("开始下载...");        notification = builderProgress.build();        /**设置不可手动清除**/        notification.flags = Notification.FLAG_NO_CLEAR;        /**获取通知管理器**/        notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);        /**发送一个通知**/        notificationManager.notify(NOTIFICATION_ID, notification);    }

5.显示通知的自定义布局

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="60dp"    android:orientation="horizontal">    <ImageView        android:id="@+id/iv"        android:layout_width="40dp"        android:layout_height="40dp" />    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout_marginLeft="10dp"        android:layout_marginRight="10dp"        android:layout_weight="1"        android:orientation="vertical">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content">            <TextView                android:id="@+id/tv_name"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_weight="1"                android:text="随时随地"                android:textColor="@color/colorAccent"                android:textSize="12sp" />        </LinearLayout>        <ProgressBar            android:id="@+id/pb"            style="?android:attr/progressBarStyleHorizontal"            android:layout_width="match_parent"            android:layout_height="20dp"            android:max="100"            android:progressBackgroundTint="@color/colorPrimaryDark"            android:progress="50" />        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content">            <TextView                android:id="@+id/tv_message"                android:layout_width="wrap_content"                android:layout_height="match_parent"                android:text="正在下载中..."                android:textColor="@color/colorAccent"                android:textSize="12sp" />            <TextView                android:id="@+id/tv_progress"                android:layout_width="wrap_content"                android:layout_height="match_parent"                android:layout_weight="1"                android:layout_gravity="center_vertical"                android:gravity="center"                android:textColor="@color/colorAccent"                android:textSize="12sp" />            <TextView                android:id="@+id/tv_size"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:textColor="@color/colorAccent"                android:textSize="12sp" />        </LinearLayout>    </LinearLayout>    <Button        android:id="@+id/bt"        android:layout_width="50dp"        android:layout_height="30dp"        android:layout_gravity="center_vertical"        android:gravity="center"        android:text="下载"        android:textColor="@color/colorAccent"        android:textSize="12sp" /></LinearLayout>

6.更新通知栏状态

    /**     * 在通知栏显示文件名     *     * @param url 下载地址     */    private void showFileName(String url) {        mRemoteViews.setTextViewText(R.id.tv_name, url.substring(url.lastIndexOf("/") + 1));        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载更改进度     *     * @param total   总大小     * @param current 当前已下载大小     */    private void updateNotification(long total, long current) {        mRemoteViews.setTextViewText(R.id.tv_size, formatSize(current) + "/" + formatSize(total));        int result = Math.round((float) current / (float) total * 100);        mRemoteViews.setTextViewText(R.id.tv_progress, result + "%");        mRemoteViews.setProgressBar(R.id.pb, 100, result, false);        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载失败     */    private void downloadFail() {        status = Status.FAIL;        if (!cancelable.isCancelled()) {            cancelable.cancel();        }        mRemoteViews.setTextViewText(R.id.bt, "重试");        mRemoteViews.setTextViewText(R.id.tv_message, "下载失败");        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载成功     */    private void downloadSuccess() {        status = Status.SUCCESS;        mRemoteViews.setTextViewText(R.id.bt, "完成");        mRemoteViews.setTextViewText(R.id.tv_message, "下载完成");        notificationManager.notify(NOTIFICATION_ID, notification);    }

7.TaskService完整代码

package cn.bluemobi.dylan.servicetask;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.os.Environment;import android.os.IBinder;import android.support.annotation.Nullable;import android.support.v7.app.NotificationCompat;import android.widget.RemoteViews;import com.orhanobut.logger.Logger;import org.xutils.common.Callback;import org.xutils.http.RequestParams;import org.xutils.x;import java.io.File;/** * Created by yuandl on 2016-12-19. */public class TaskService extends Service {    /****     * 发送广播的请求码     */    private final int REQUEST_CODE_BROADCAST = 0X0001;    /****     * 发送广播的action     */    private final String BROADCAST_ACTION_CLICK = "servicetask";    /**     * 通知     */    private Notification notification;    /**     * 通知的Id     */    private final int NOTIFICATION_ID = 1;    /**     * 通知管理器     */    private NotificationManager notificationManager;    /**     * 通知栏的远程View     */    private RemoteViews mRemoteViews;    /**     * 下载是否可取消     */    private Callback.Cancelable cancelable;    /**     * 自定义保存路径,Environment.getExternalStorageDirectory():SD卡的根目录     */    private String filePath = Environment.getExternalStorageDirectory() + "/ServiceTask/";    private File file;    /**     * 通知栏操作的四种状态     */    private enum Status {        DOWNLOADING, PAUSE, FAIL, SUCCESS    }    /**     * 当前在状态 默认正在下载中     */    private Status status = Status.DOWNLOADING;    private MyBroadcastReceiver myBroadcastReceiver;    @Nullable    @Override    public IBinder onBind(Intent intent) {        return null;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        registerBroadCast();        download();        return super.onStartCommand(intent, flags, startId);    }    /**     * 注册按钮点击广播*     */    private void registerBroadCast() {        myBroadcastReceiver = new MyBroadcastReceiver();        IntentFilter filter = new IntentFilter();        filter.addAction(BROADCAST_ACTION_CLICK);        registerReceiver(myBroadcastReceiver, filter);    }    /**     * 更新通知界面的按钮的广播     */    private class MyBroadcastReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            if (!intent.getAction().equals(BROADCAST_ACTION_CLICK)) {                return;            }            Logger.d("status=" + status);            switch (status) {                case DOWNLOADING:                    /**当在下载中点击暂停按钮**/                    cancelable.cancel();                    mRemoteViews.setTextViewText(R.id.bt, "下载");                    mRemoteViews.setTextViewText(R.id.tv_message, "暂停中...");                    status = Status.PAUSE;                    notificationManager.notify(NOTIFICATION_ID, notification);                    break;                case SUCCESS:                    /**当下载完成点击完成按钮时关闭通知栏**/                    notificationManager.cancel(NOTIFICATION_ID);                    break;                case FAIL:                case PAUSE:                    /**当在暂停时点击下载按钮**/                    download();                    mRemoteViews.setTextViewText(R.id.bt, "暂停");                    mRemoteViews.setTextViewText(R.id.tv_message, "下载中...");                    status = Status.DOWNLOADING;                    notificationManager.notify(NOTIFICATION_ID, notification);                    break;            }        }    }    /**     * 下载文件     */    private void download() {        final String url = "https://github.com/linglongxin24/DylanStepCount/raw/master/app-debug.apk";        RequestParams requestParams = new RequestParams(url);        String fileName = url.substring(url.lastIndexOf("/") + 1);        file = new File(filePath, fileName);        showNotificationProgress(TaskService.this);        showFileName(fileName);        requestParams.setSaveFilePath(file.getPath());        /**自动为文件命名**/        requestParams.setAutoRename(true);        /**自动为文件断点续传**/        requestParams.setAutoResume(true);        cancelable = x.http().get(requestParams, new Callback.ProgressCallback<File>() {            @Override            public void onSuccess(File result) {                Logger.d("下载完成");                Logger.d("result=" + result.getPath());                downloadSuccess();            }            @Override            public void onError(Throwable ex, boolean isOnCallback) {                Logger.d("下载异常");                downloadFail();            }            @Override            public void onCancelled(CancelledException cex) {                Logger.d("下载已取消");            }            @Override            public void onFinished() {            }            @Override            public void onWaiting() {            }            @Override            public void onStarted() {            }            @Override            public void onLoading(long total, long current, boolean isDownloading) {                Logger.d("total=" + total + "--" + "current=" + current);                updateNotification(total, current);            }        });    }    /**     * 显示一个下载带进度条的通知     *     * @param context 上下文     */    public void showNotificationProgress(Context context) {        /**进度条通知构建**/        NotificationCompat.Builder builderProgress = new NotificationCompat.Builder(context);        /**设置为一个正在进行的通知**/        builderProgress.setOngoing(true);        /**设置小图标**/        builderProgress.setSmallIcon(R.mipmap.ic_launcher);        /**新建通知自定义布局**/        mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.notification);        /**进度条ProgressBar**/        mRemoteViews.setProgressBar(R.id.pb, 100, 0, false);        /**提示信息的TextView**/        mRemoteViews.setTextViewText(R.id.tv_message, "下载中...");        /**操作按钮的Button**/        mRemoteViews.setTextViewText(R.id.bt, "暂停");        /**设置左侧小图标*/        mRemoteViews.setImageViewResource(R.id.iv, R.mipmap.ic_launcher);        /**设置通过广播形式的PendingIntent**/        Intent intent = new Intent(BROADCAST_ACTION_CLICK);        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE_BROADCAST, intent, 0);        mRemoteViews.setOnClickPendingIntent(R.id.bt, pendingIntent);        /**设置自定义布局**/        builderProgress.setContent(mRemoteViews);        /**设置滚动提示**/        builderProgress.setTicker("开始下载...");        notification = builderProgress.build();        /**设置不可手动清除**/        notification.flags = Notification.FLAG_NO_CLEAR;        /**获取通知管理器**/        notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);        /**发送一个通知**/        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 在通知栏显示文件名     *     * @param url 下载地址     */    private void showFileName(String url) {        mRemoteViews.setTextViewText(R.id.tv_name, url.substring(url.lastIndexOf("/") + 1));        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载更改进度     *     * @param total   总大小     * @param current 当前已下载大小     */    private void updateNotification(long total, long current) {        mRemoteViews.setTextViewText(R.id.tv_size, formatSize(current) + "/" + formatSize(total));        int result = Math.round((float) current / (float) total * 100);        mRemoteViews.setTextViewText(R.id.tv_progress, result + "%");        mRemoteViews.setProgressBar(R.id.pb, 100, result, false);        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载失败     */    private void downloadFail() {        status = Status.FAIL;        if (!cancelable.isCancelled()) {            cancelable.cancel();        }        mRemoteViews.setTextViewText(R.id.bt, "重试");        mRemoteViews.setTextViewText(R.id.tv_message, "下载失败");        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 下载成功     */    private void downloadSuccess() {        status = Status.SUCCESS;        mRemoteViews.setTextViewText(R.id.bt, "完成");        mRemoteViews.setTextViewText(R.id.tv_message, "下载完成");        notificationManager.notify(NOTIFICATION_ID, notification);    }    /**     * 格式化文件大小     *     * @param size     * @return     */    private String formatSize(long size) {        String format;        if (size >= 1024 * 1024) {            format = byteToMB(size) + "M";        } else if (size >= 1024) {            format = byteToKB(size) + "k";        } else {            format = size + "b";        }        return format;    }    /**     * byte转换为MB     *     * @param bt 大小     * @return MB     */    private float byteToMB(long bt) {        int mb = 1024 * 1024;        float f = (float) bt / (float) mb;        float temp = (float) Math.round(f * 100.0F);        return temp / 100.0F;    }    /**     * byte转换为KB     *     * @param bt 大小     * @return K     */    private int byteToKB(long bt) {        return Math.round((bt / 1024));    }    /**     * 销毁时取消下载,并取消注册广播,防止内存溢出     */    @Override    public void onDestroy() {        if (cancelable != null && !cancelable.isCancelled()) {            cancelable.cancel();        }        if (myBroadcastReceiver != null) {            unregisterReceiver(myBroadcastReceiver);        }        super.onDestroy();    }}

8.GitHub

1 0