多线程断点下载

这个demo是对前一篇断点后台下载的完善。

demo的总体效果是可以同时进行两个下载任务,任务的进行状态分为:开始,连接中,暂停,完成,继续;通知栏进度条显示的是开始任务的平均进度。

先看一下效果图:
这里写图片描述
这里写图片描述

先说一下实现思路,数据显示通过Recycleview显示,在Adapter中添加点击事件,将点击item的position和状态值传递给调用的Activity;后台Service在下载线程的个个状态通过广播发送给主线程并更新UI。

下面直接上代码。

数据库操作类

DownloadContract:

public class DownloadContract {
    // 为了防止有人意外地实例化合同类,使构造函数私有。
    private DownloadContract() {
    }

    /* 内部类定义表的内容 */
    public static class DownloadEntry implements BaseColumns {
        public static final String TABLE_NAME = "downloadentry";
        public static final String COLUMN_NAME_TID = "tid";
        public static final String COLUMN_NAME_JINDU = "jindu";
        public static final String COLUMN_NAME_YIXIAZAI = "yixiazai";
        public static final String COLUMN_NAME_PATH = "path";
        public static final String COLUMN_NAME_ZHUANGTAI = "zhuangtai";
        public static final String COLUMN_NAME_URL = "url";
    }
}

SQLTool:

public class SQLTool {
    private static final String TEXT_TYPE = " TEXT";
    private static final String INTEGER_TYPE = " INTEGER";
    private static final String COMMA_SEP = ",";
    public static final String SQL_CREATE_ENTRIES =
            "CREATE TABLE " + DownloadContract.DownloadEntry.TABLE_NAME + " (" +
                    DownloadContract.DownloadEntry._ID + " INTEGER PRIMARY KEY," +
                    DownloadContract.DownloadEntry.COLUMN_NAME_TID + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_JINDU + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_PATH + TEXT_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI + INTEGER_TYPE + COMMA_SEP +
                    DownloadContract.DownloadEntry.COLUMN_NAME_URL + TEXT_TYPE + " )";

    public static final String SQL_DELETE_ENTRIES =
            "DROP TABLE IF EXISTS " + DownloadContract.DownloadEntry.TABLE_NAME;
}

DownloadDbHelper:

public class DownloadDbHelper extends SQLiteOpenHelper {
    // 如果更改数据库模式,则必须增加数据库版本。
    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "dl.db";

    public DownloadDbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(SQL_CREATE_ENTRIES);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // 这个数据库只是一个用于在线数据的缓存,因此其升级策略是简单地丢弃数据并重新开始
        sqLiteDatabase.execSQL(SQL_DELETE_ENTRIES);
        onCreate(sqLiteDatabase);
    }

    @Override
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        onUpgrade(db, oldVersion, newVersion);
    }
}

DAOHelper:

public class DAOHelper {

    private DownloadDbHelper downloadDbHelper;

    public DAOHelper(Context context) {
        downloadDbHelper = new DownloadDbHelper(context);
    }

    public long add(Download download) {
        // 以写入模式获取数据存储库
        SQLiteDatabase db = downloadDbHelper.getWritableDatabase();

        //创建一个新的值映射,其中列名称是键
        ContentValues values = new ContentValues();

        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_TID, download.gettId());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU, download.getJindu());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI, download.getYixiazai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_PATH, download.getPath());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI, download.getZhuangtai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_URL, download.getUrl());
        // 插入新行,返回新行的主键值,-1表示插入失败
        long newRowId = db.insert(DownloadContract.DownloadEntry.TABLE_NAME, null, values);
        return newRowId;
    }

    public void delete(int tID) {
        SQLiteDatabase db = downloadDbHelper.getWritableDatabase();
        // 定义查询的“where”部分。
        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " LIKE ?";
        // 在占位符顺序中指定参数。
        String[] selectionArgs = {tID + ""};
        // 发出SQL语句。
        db.delete(DownloadContract.DownloadEntry.TABLE_NAME, selection, selectionArgs);
    }

    public int update(Download download) {
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        ContentValues values = new ContentValues();
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU, download.getJindu());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI, download.getYixiazai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_PATH, download.getPath());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI, download.getZhuangtai());
        values.put(DownloadContract.DownloadEntry.COLUMN_NAME_URL, download.getUrl());
        // 要更新的行
        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " LIKE ?";
        String[] selectionArgs = {download.gettId() + ""};
        // 得到受影响的行数
        int count = db.update(
                DownloadContract.DownloadEntry.TABLE_NAME,
                values,
                selection,
                selectionArgs);
        return count;
    }

    public boolean include(int tID) {
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        String[] projection = {
                DownloadContract.DownloadEntry.COLUMN_NAME_TID,
                DownloadContract.DownloadEntry.COLUMN_NAME_JINDU,
                DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI,
                DownloadContract.DownloadEntry.COLUMN_NAME_PATH,
                DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI,
                DownloadContract.DownloadEntry.COLUMN_NAME_URL
        };

        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " = ?";
        String[] selectionArgs = {tID + ""};

        String sortOrder =
                DownloadContract.DownloadEntry.COLUMN_NAME_TID + " DESC";

        Cursor c = db.query(
                DownloadContract.DownloadEntry.TABLE_NAME,
                projection,
                selection,
                selectionArgs,
                null,
                null,
                sortOrder
        );

        if (c.moveToFirst()) {
            return true;
        } else {
            return false;
        }
    }

    public Download select(int tID) {
        Download download = new Download();
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        String[] projection = {
                DownloadContract.DownloadEntry.COLUMN_NAME_TID,
                DownloadContract.DownloadEntry.COLUMN_NAME_JINDU,
                DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI,
                DownloadContract.DownloadEntry.COLUMN_NAME_PATH,
                DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI,
                DownloadContract.DownloadEntry.COLUMN_NAME_URL
        };

        String selection = DownloadContract.DownloadEntry.COLUMN_NAME_TID + " = ?";
        String[] selectionArgs = {tID + ""};

        String sortOrder =
                DownloadContract.DownloadEntry.COLUMN_NAME_TID + " DESC";

        Cursor c = db.query(
                DownloadContract.DownloadEntry.TABLE_NAME,
                projection,
                selection,
                selectionArgs,
                null,
                null,
                sortOrder
        );

        if (c.moveToFirst()) {
            download.settId(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_TID)));
            download.setJindu(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU)));
            download.setYixiazai(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI)));
            download.setPath(c.getString(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_PATH)));
            download.setZhuangtai(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI)));
            download.setUrl(c.getString(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_URL)));
            return download;
        } else {
            return null;
        }
    }

    public List<Download> selectAll() {

        List<Download> dataList = new ArrayList<Download>();
        SQLiteDatabase db = downloadDbHelper.getReadableDatabase();

        Cursor c = db.query(
                DownloadContract.DownloadEntry.TABLE_NAME,
                null,
                null,
                null,
                null,
                null,
                null
        );
        while (c.moveToNext()) {
            Download download = new Download();
            download.settId(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_TID)));
            download.setJindu(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_JINDU)));
            download.setYixiazai(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_YIXIAZAI)));
            download.setPath(c.getString(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_PATH)));
            download.setZhuangtai(c.getInt(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_ZHUANGTAI)));
            download.setUrl(c.getString(c.getColumnIndexOrThrow(DownloadContract.DownloadEntry.COLUMN_NAME_URL)));
            dataList.add(download);
        }
        return dataList;
    }

}

布局

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.jqk.backgrounddownload.MainActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
</LinearLayout>

item_dl.xml:

<?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="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/progress"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.7"
        android:max="100" />

    <TextView
        android:id="@+id/jindu"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.1" />

    <Button
        android:id="@+id/start"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.2"
        android:text="" />
</LinearLayout>

remoteview.xml:

<?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="50dp"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.9" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.1" />

</LinearLayout>

实体类

Download:

public class Download {

    private int tId;
    private int jindu;
    private int yixiazai;
    private String path;
    private int zhuangtai;
    private String url;

    public int gettId() {
        return tId;
    }

    public void settId(int tId) {
        this.tId = tId;
    }

    public int getJindu() {
        return jindu;
    }

    public void setJindu(int jindu) {
        this.jindu = jindu;
    }

    public int getYixiazai() {
        return yixiazai;
    }

    public void setYixiazai(int yixiazai) {
        this.yixiazai = yixiazai;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public int getZhuangtai() {
        return zhuangtai;
    }

    public void setZhuangtai(int zhuangtai) {
        this.zhuangtai = zhuangtai;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "Download{" +
                "tId=" + tId +
                ", jindu=" + jindu +
                ", yixiazai=" + yixiazai +
                ", path='" + path + '\'' +
                ", zhuangtai=" + zhuangtai +
                ", url='" + url + '\'' +
                '}';
    }
}

Jindu:

public class Jindu {
    // 进度状态:0为未开始,1为开始
    private int type;
    private int jindu;

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public int getJindu() {
        return jindu;
    }

    public void setJindu(int jindu) {
        this.jindu = jindu;
    }

    @Override
    public String toString() {
        return "Jindu{" +
                "type=" + type +
                ", jindu=" + jindu +
                '}';
    }
}

工具类

AppConstant:

public class AppConstant {
    public static final int START = 1;
    public static final int PAUSE = 2;
    public static final int WAIT = 3;
    public static final int CONNECTING = 4;
    public static final int FINISH = 5;
    public static final int GOON = 6;
}

FileUtil:

public class FileUtil {
    public static File getStorageDir(Context context, String albumName) {
        File file = new File(context.getExternalFilesDir(
                Environment.DIRECTORY_DOWNLOADS), albumName);
        if (file.mkdirs() || file.isDirectory()) {
            Log.d("dl", "文件夹已存在");
        } else {
            Log.d("dl", "文件夹创建失败");
        }
        return file;
    }
}

Activity

MainActivity:

public class MainActivity extends AppCompatActivity implements MyAdapter.OnClickTypeListener {

    private RecyclerView recyclerView;
    private File file;
    private List<Download> downloads;
    private DAOHelper daoHelper;
    private DownloadService mService;
    private boolean mBound = false;
    private LinearLayoutManager linearLayoutManager;
    private MyAdapter myAdapter;
    // 定时任务,更新下载进度
    private Timer timer;

    private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            DownloadService.DLBinder binder = (DownloadService.DLBinder) service;
            mService = binder.getService();
            timer = new Timer();
            // 开启刷新UI的任务
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    Message message = new Message();
                    message.what = 1000;
                    handler.sendMessage(message);
                }
            }, 0, 700);
            mBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1000:
                    shuaxin(downloads, mService.getJindu());
                    break;
            }
        }
    };

    private BroadcastReceiver typeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case "type":
                    int position = intent.getIntExtra("position", 0);
                    int type = intent.getIntExtra("type", 0);
                    downloads.get(position).setZhuangtai(type);
                    myAdapter.notifyDataSetChanged();
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();

        daoHelper = new DAOHelper(this);
        initData();
        adaptationData();

        // 启动服务
        Intent intent = new Intent(this, DownloadService.class);
        startService(intent);
        // 绑定服务
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("type");
        registerReceiver(typeReceiver, intentFilter);


    }

    public void initView() {
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    }

    /**
     * 初始化数据
     */
    public void initData() {
        file = FileUtil.getStorageDir(getApplicationContext(), "apk");
        Log.d("dl", "path = " + file.getAbsolutePath());

        if (!daoHelper.include(1)) {
            Download download = new Download();
            download.settId(1);
            download.setJindu(0);
            download.setYixiazai(0);
            download.setPath(file.getAbsolutePath() + "/111.apk");
            download.setZhuangtai(1);
            download.setUrl("http://msoftdl.360.cn/mobilesafe/shouji360/360safe/500192/360MobileSafe.apk");
            long i = daoHelper.add(download);
            if (i != -1) {
                Log.d("dl", "插入成功1");
            } else {
                Log.d("dl", "插入失败1");
            }
        } else {
            Log.d("dl", "数据已存在1");
        }

        if (!daoHelper.include(2)) {
            Download download = new Download();
            download.settId(2);
            download.setJindu(0);
            download.setYixiazai(0);
            download.setPath(file.getAbsolutePath() + "/222.apk");
            download.setZhuangtai(1);
            download.setUrl("http://msoftdl.360.cn/mobilesafe/shouji360/360safe/500192/360MobileSafe.apk");
            long i = daoHelper.add(download);
            if (i != -1) {
                Log.d("dl", "插入成功2");
            } else {
                Log.d("dl", "插入失败2");
            }
        } else {
            Log.d("dl", "数据已存在2");
        }

        if (!daoHelper.include(3)) {
            Download download = new Download();
            download.settId(3);
            download.setJindu(0);
            download.setYixiazai(0);
            download.setPath(file.getAbsolutePath() + "/333.apk");
            download.setZhuangtai(1);
            download.setUrl("http://msoftdl.360.cn/mobilesafe/shouji360/360safe/500192/360MobileSafe.apk");
            long i = daoHelper.add(download);
            if (i != -1) {
                Log.d("dl", "插入成功3");
            } else {
                Log.d("dl", "插入失败3");
            }
        } else {
            Log.d("dl", "数据已存在3");
        }

        if (!daoHelper.include(4)) {
            Download download = new Download();
            download.settId(4);
            download.setJindu(0);
            download.setYixiazai(0);
            download.setPath(file.getAbsolutePath() + "/444.apk");
            download.setZhuangtai(1);
            download.setUrl("http://msoftdl.360.cn/mobilesafe/shouji360/360safe/500192/360MobileSafe.apk");
            long i = daoHelper.add(download);
            if (i != -1) {
                Log.d("dl", "插入成功4");
            } else {
                Log.d("dl", "插入失败4");
            }
        } else {
            Log.d("dl", "数据已存在4");
        }
    }

    /**
     * 适配数据
     */
    public void adaptationData() {
        downloads = daoHelper.selectAll();
        for (Download download : downloads) {
            Log.d("dl", "适配的数据:" + "线程ID = " + download.gettId() + ",type = " + download.getZhuangtai() + ",进度 = " + download.getJindu());
        }
        linearLayoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(linearLayoutManager);
        myAdapter = new MyAdapter(this, downloads, this);
        recyclerView.setAdapter(myAdapter);

    }

    /**
     * 刷新进度条
     *
     * @param downloads
     * @param jindus
     */
    public void shuaxin(List<Download> downloads, List<Jindu> jindus) {
        for (int i = 0; i < downloads.size(); i++) {
            downloads.get(i).setJindu(jindus.get(i).getJindu());
        }

        myAdapter.notifyDataSetChanged();
    }

    @Override
    public void onClickType(int position, int type) {
        Log.d("dl", "点击position" + position + ", type = " + type);
        switch (type) {
            case AppConstant.START: // 开始
                mService.startDL(position);
                break;
            case AppConstant.PAUSE: // 暂停
                mService.pauseDL(position);
                break;
            case AppConstant.WAIT: // 等待

                break;
            case AppConstant.CONNECTING: // 连接中

                break;
            case AppConstant.FINISH: // 完成

                break;
            case AppConstant.GOON:
                mService.startDL(position);
                break;
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
//        Intent intent = new Intent(this, DownloadService.class);
//        stopService(intent);
        unregisterReceiver(typeReceiver);
        timer.cancel();
    }
}

Service

DownloadService:

public class DownloadService extends Service {
    private File dlFile, file;
    private Timer timer;
    // 数据库帮助类
    private DAOHelper daoHelper;
    // 线程池,大小为2
    private ExecutorService fixedThreadPool;
    // 线程集合 大小为2
    private List<DownloadThread> threads;
    // 进度集合
    private List<Jindu> jindus;
    // 下载实例集合
    private List<Download> downloads;
    // 等待集合
    private List<Integer> waits;

    private Intent typeIntent;
    // IBinder对象
    private final IBinder mBinder = new DLBinder();

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1000:
                    int jindu = getPingJunJindu(jindus);
                    NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
                    builder.setSmallIcon(R.mipmap.ic_launcher);
                    builder.setContentTitle("自定义布局");
                    RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.remoteview);
                    remoteViews.setProgressBar(R.id.progressBar, 100, jindu, false);
                    remoteViews.setTextViewText(R.id.textView, jindu + "%");

                    builder.setContent(remoteViews);
                    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                    startForeground(1, builder.build());
                    break;
            }
        }
    };

    public class DLBinder extends Binder {
        public DownloadService getService() {
            return DownloadService.this;
        }
    }

    @Override
    public void onCreate() {
        daoHelper = new DAOHelper(this);

        file = FileUtil.getStorageDir(getApplicationContext(), "apk");
        Log.d("dl", "path = " + file.getAbsolutePath());

        fixedThreadPool = Executors.newFixedThreadPool(2);
        jindus = new ArrayList<Jindu>();
        threads = new ArrayList<DownloadThread>();
        downloads = daoHelper.selectAll();
        for (int i = 0; i < downloads.size(); i++) {
            Jindu jindu = new Jindu();
            if (downloads.get(i).getZhuangtai() != 1) { // 根据存储的状态值设置进度的状态
                // 已经开始
                jindu.setType(1);
            } else {
                // 还未开始
                jindu.setType(0);
            }
            jindu.setJindu(downloads.get(i).getJindu());
            jindus.add(jindu);
        }

        for (int i = 0; i < 2; i++) {
            DownloadThread downloadThread = new DownloadThread();
            threads.add(downloadThread);
        }

        waits = new ArrayList<Integer>();

        typeIntent = new Intent();
        typeIntent.setAction("type");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentTitle("自定义点击事件");
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.remoteview);
        remoteViews.setProgressBar(R.id.progressBar, 100, 0, false);
        remoteViews.setTextViewText(R.id.textView, 0 + "%");

        builder.setContent(remoteViews);
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        startForeground(1, builder.build());

        start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    /**
     * 开始下载
     */
    public void startDL(int position) {
        for (int i = 0; i < 2; i++) { // 遍历线程集合,判断线程ID,如果线程ID为-1则通过线程池运行线程
            if (threads.get(i).gettID() == -1) {
                DownloadThread downloadThread = threads.get(i);
                downloadThread.settID(position + 1);
                Log.d("dl", "线程" + i + "启动");
                downloadThread.setDlUrl(downloads.get(position).getUrl());
                fixedThreadPool.execute(downloadThread);
                return;
            }
        }
        // 如果两个线程都被使用,则加入等待集合
        if (threads.get(0).gettID() != -1 && threads.get(1).gettID() != -1) {
            Log.d("dl", "等待增加" + position);
            waits.add(position);
            saveType(position, AppConstant.WAIT);
        }
    }

    /**
     * 暂停下载
     * @param position
     */
    public void pauseDL(int position) {
        for (int i = 0; i < 2; i++) {
            if (threads.get(i).gettID() != -1 && threads.get(i).gettID() == position + 1) {
                Log.d("dl", "线程" + i + "暂停");
                threads.get(i).pause();
                break;
            }
        }
    }

    /**
     * 开始显示通知栏的定时任务
     */
    public void start() {
        timer = new Timer();
        timer.schedule(new TimerTask() {
            public void run() {
                Message msg = new Message();
                msg.what = 1000;
                handler.sendMessage(msg);
            }
        }, 0, 700);
    }

    /**
     * 停止显示通知栏的定时任务
     */
    public void stop() {
        timer.cancel();
    }

    public void saveType(int position, int type) {
        typeIntent.putExtra("position", position);
        typeIntent.putExtra("type", type);
        sendBroadcast(typeIntent);
        Download download = downloads.get(position);
        download.setZhuangtai(type);
        download.setJindu(jindus.get(position).getJindu());
//        daoHelper.update(download);
        if (daoHelper.update(download) == 1) {
            Log.d("dl", "数据保存成功:" + "线程ID = " + download.gettId() + ",type = " + download.getZhuangtai() + ",进度 = " + download.getJindu());
        }
    }

    /**
     * 获取平均进度,显示在通知栏中
     *
     * @param jindus
     * @return
     */
    public int getPingJunJindu(List<Jindu> jindus) {
        int jindu = 0;
        int i = 0;
        for (Jindu jd : jindus) {
            if (jd.getType() == 1) {
                jindu += jd.getJindu();
                i++;
            }
        }
        if (i == 0) {
            return jindu;
        } else {
            return jindu / i;
        }
    }

    /**
     * 返回进度
     * @return
     */
    public List<Jindu> getJindu() {
        return jindus;
    }

    public class DownloadThread implements Runnable {
        private boolean pause = false;
        private int tID = -1;
        private String dlUrl = "";

        public int gettID() {
            return tID;
        }

        public void settID(int tID) {
            this.tID = tID;
        }

        public String getDlUrl() {
            return dlUrl;
        }

        public void setDlUrl(String dlUrl) {
            this.dlUrl = dlUrl;
        }

        @Override
        public void run() {
            try {
                //创建URL对象
                Log.d("dl", "线程ID = " + tID);
                URL url = new URL(dlUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                //已经下载的字节数
                long alreadySize = 0;
                //将文件写到指定目录中
                Download download = daoHelper.select(tID);
                File file = new File(download.getPath());
                if (file.exists()) {
                    //如果文件存在,就获取当前文件的大小
                    alreadySize = file.length();
                }

                conn.addRequestProperty("range", "bytes=" + alreadySize + "-");
                saveType(tID - 1, AppConstant.CONNECTING); // 正在连接
                conn.connect();
                // 获得返回结果
                int code = conn.getResponseCode();
                // 响应成功返回206
                if (code == 206) {
                    jindus.get(tID - 1).setType(1);
                    saveType(tID - 1, AppConstant.PAUSE); // 暂停
                    // 获取未下载的文件的大小
                    long unfinishedSize = conn.getContentLength();
                    // 文件的大小
                    long size = alreadySize + unfinishedSize;
                    Log.d("dl", "size = " + size);
                    // 获取输入流
                    InputStream in = conn.getInputStream();
                    // 获取输出对象,在原文件后追加
                    OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true));

                    // 开始下载
                    byte[] buff = new byte[2048];
                    int len;
                    StringBuilder sb = new StringBuilder();

                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                        // 累加已下载的大小
                        alreadySize += len;
                        // 更新进度
                        jindus.get(tID - 1).setJindu((int) (alreadySize * 1.0 / size * 100));
                        synchronized (this) {
                            if (pause) {
                                saveType(tID - 1, AppConstant.GOON); // 继续
                                Log.d("dl", "线程ID" + tID + "停止");
                                break; // 暂停后跳出while循环继续执行后面的代码
                            }
                        }
                    }
                    out.close();
                    conn.disconnect();
                    if (alreadySize == size) {
                        saveType(tID - 1, AppConstant.FINISH); // 完成
                    }

                    pause = false; // 重置pause常量
                    tID = -1; // 重置线程编号

                    if (waits.size() != 0) {
                        pause = false; // 重置pause常量
                        tID = -1; // 重置线程编号
                        Log.d("dl", "等待执行" + waits.get(0));
                        startDL(waits.get(0)); // 执行等待的任务
                        waits.remove(0);
                    }
                } else {
                    Toast.makeText(DownloadService.this, "下载失败", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        public void pause() {
            pause = true;
        }
    }
}

最后别忘了添加权限,声明Service:

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<service android:name=".DownloadSerivce"></service>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值