欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳

 更新時(shí)間:2022年07月27日 10:09:55   作者:hello_1s  
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳的具體代碼,供大家參考,具體內(nèi)容如下

多線程下載涉及到的知識(shí)點(diǎn):

1、Service的使用:我們?cè)赟ervice中去下載文件;
2、Thread的使用:Service本身不支持耗時(shí)操作,所以我們要去開(kāi)啟線程;
3、Sqlite的使用:使用數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)每個(gè)線程下載的文件的進(jìn)度,和文件的下載情況;
4、權(quán)限:涉及到文件的讀寫(xiě)就要用到權(quán)限;
5、BroadCastReceiver的使用:通過(guò)廣播來(lái)更新下載進(jìn)度;
6、線程池使用:使用線程池來(lái)管理線程,減少資源的浪費(fèi)
7、HttpUrlConnection的使用:下載文件使用的
8、ListView和BaseAdapter的使用:下載列表的顯示
9、RandomAccessFile使用

先解釋一下我們要做什么:

1、我們現(xiàn)在有一個(gè)文件,然后要分成好幾個(gè)線程去下載,那么我們需要將這個(gè)文件平分,然后分給各個(gè)線程去下載,而每個(gè)線程在下載的時(shí)候,你不一定啥時(shí)候點(diǎn)了暫停,那么就要記錄我的下載進(jìn)度,所以要用到數(shù)據(jù)庫(kù)。

2、你可能又會(huì)問(wèn),怎么去知道誰(shuí)下載哪呢?我們的HttpURLConnection可以通過(guò)他的setRequestProperty()方法設(shè)置下載范圍,從哪開(kāi)始到哪結(jié)束。

3、同樣下載解決了,那么寫(xiě)文件呢,怎么往文件里面寫(xiě)呢,那么就要用到RandomAccessFile這個(gè)文件的特性了,從文件的任意位置開(kāi)始寫(xiě),是不是清晰了。

4、 還有問(wèn)題就是怎么更新界面,用我們的廣播,告訴什么時(shí)候去更新界面。

(實(shí)現(xiàn)的效果,是一個(gè)文件可以由多個(gè)線程下載,可以同時(shí)下載多個(gè)文件)

**這里需要注意:**不可以在獲取長(zhǎng)度后直接去下載文件,因?yàn)?,我們獲取文件長(zhǎng)度的時(shí)候需要使用的請(qǐng)求碼是200,如果我們想要分段去下載(也就是設(shè)置了connection.setRequestProperty(“Range”,“bytes=”"之后就是分段下載了)那么使用到的請(qǐng)求碼是206。所以我們這里要將這兩個(gè)請(qǐng)求分開(kāi)來(lái)寫(xiě),我就一開(kāi)始將兩個(gè)寫(xiě)到一起了,但是是不可以的會(huì)報(bào)錯(cuò),更不要想著通過(guò)請(qǐng)求碼來(lái)區(qū)分,這個(gè)就更錯(cuò)了

1、下面貼出***服務(wù)類(lèi)***的代碼:

這里的工作主要就是開(kāi)啟下載任務(wù)和停止下載任務(wù),還有就是獲取下載文件的長(zhǎng)度,并創(chuàng)建本地文件并設(shè)置長(zhǎng)度。

public class DownLoadService extends Service {
? ? public static final int STATUS_START = 0;
? ? public static final int STATUS_STOP = 1;
? ? public static final String PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
? ? private FileInfo mFileInfo;
? ? //統(tǒng)一管理DownLoadTask,有個(gè)文件下載就有個(gè)DownLoadTask,所以使用Map去管理,主要控制暫停
? ? private Map<Integer,Object> downtaskMap = new HashMap<>();
? ? private DownLoadTask downLoadTask;

? ? @Override
? ? public void onCreate() {
? ? ? ? super.onCreate();
? ? }

? ? @Override
? ? public int onStartCommand(Intent intent, int flags, int startId) {
? ? ? ? if (intent != null) {
? ? ? ? ? ? int status = intent.getIntExtra("status", 0);
? ? ? ? ? ? if (status == STATUS_START) {
? ? ? ? ? ? ? ? //開(kāi)始下載
? ? ? ? ? ? ? ? mFileInfo = (FileInfo) intent.getSerializableExtra("fileinfo");
? ? ? ? ? ? ? ? DownLoadTask.sExecutorService.execute(new GetFileLenght(mFileInfo, this));

? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? //暫停下載
? ? ? ? ? ? ? ? mFileInfo = (FileInfo) intent.getSerializableExtra("fileinfo");
? ? ? ? ? ? ? ? Log.e("---------->","mFileInfo:"+mFileInfo);
? ? ? ? ? ? ? ? downLoadTask = (DownLoadTask) downtaskMap.get(mFileInfo.getId());
? ? ? ? ? ? ? ? if(downLoadTask!=null){
? ? ? ? ? ? ? ? ? ? downLoadTask.isPause = true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }

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

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


? ? /**
? ? ?* 獲得要下載的文件的長(zhǎng)度,并創(chuàng)建本地文件
? ? ?* 不能和下載的線程寫(xiě)在一起
? ? ?*/
? ? class GetFileLenght extends Thread {
? ? ? ? private FileInfo fileInfo;
? ? ? ? private Context context;

? ? ? ? public GetFileLenght(FileInfo fileInfo, Context context) {
? ? ? ? ? ? this.fileInfo = fileInfo;
? ? ? ? ? ? this.context = context;
? ? ? ? }

? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? super.run();
? ? ? ? ? ? HttpURLConnection conn = null;
? ? ? ? ? ? RandomAccessFile raf = null;
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? URL url = new URL(fileInfo.getUrl());
? ? ? ? ? ? ? ? conn = (HttpURLConnection) url.openConnection();
? ? ? ? ? ? ? ? conn.setConnectTimeout(5000);
? ? ? ? ? ? ? ? conn.setRequestMethod("GET");

? ? ? ? ? ? ? ? int length = -1;
? ? ? ? ? ? ? ? if (conn.getResponseCode() == 200) {
? ? ? ? ? ? ? ? ? ? length = conn.getContentLength();
? ? ? ? ? ? ? ? ? ? if (length > 0) {
? ? ? ? ? ? ? ? ? ? ? ? //創(chuàng)建本地文件
? ? ? ? ? ? ? ? ? ? ? ? File file = new File(PATH, fileInfo.getFile_name());
? ? ? ? ? ? ? ? ? ? ? ? raf = new RandomAccessFile(file, "rwd");
? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置本地文件的長(zhǎng)度
? ? ? ? ? ? ? ? ? ? ? ? raf.setLength(length);
? ? ? ? ? ? ? ? ? ? ? ? fileInfo.setLength(length);
? ? ? ? ? ? ? ? ? ? ? ? //開(kāi)始下載
? ? ? ? ? ? ? ? ? ? ? ? downLoadTask =new DownLoadTask(DownLoadService.this,fileInfo);
? ? ? ? ? ? ? ? ? ? ? ? downLoadTask.down();
? ? ? ? ? ? ? ? ? ? ? ? downtaskMap.put(fileInfo.getId(),downLoadTask);

? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? conn.disconnect();
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? if (raf != null) {
? ? ? ? ? ? ? ? ? ? ? ? raf.close();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }

}

2、DownLoadTask的代碼,也就是真正的核心的地方

這里的關(guān)系是一個(gè)FileInfo對(duì)應(yīng)一個(gè)DownLoadTask,一個(gè)DownLoadTask對(duì)應(yīng)著多個(gè)線程

package com.example.a_0102.mylearn.download;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
?* 下載文件的內(nèi)容
?*/

public class DownLoadTask {
? ? private Context context;
? ? private FileInfo fileInfo;
? ? private int countForThread = 3;//線程的數(shù)量
? ? private int mFinished;
? ? private DownLoadTaskImpl downLoadTask;
? ? private List<ThreadInfo> threadInfos;
? ? private List<DownLoadThread> downLoadThreads;
? ? public boolean isPause = false;
? ? public static ExecutorService sExecutorService = Executors.newCachedThreadPool();//共用一個(gè)線程池

? ? public DownLoadTask(Context context,FileInfo fileInfo) {
? ? ? ? this.fileInfo = fileInfo;
? ? ? ? this.context = context;
? ? ? ? downLoadTask = new DownLoadTaskImpl(context);
? ? }

? ? public void down(){
? ? ? ? threadInfos = downLoadTask.getThreadInfos(fileInfo.getUrl());
? ? ? ? if(threadInfos.size() == 0){
? ? ? ? ? ? mFinished = 0;
? ? ? ? ? ? //計(jì)算每個(gè)線程應(yīng)下載的長(zhǎng)度
? ? ? ? ? ? int every_length = fileInfo.getLength()/countForThread;
? ? ? ? ? ? for(int i = 0;i<countForThread;i++){
? ? ? ? ? ? ? ? ThreadInfo threadInfo = new ThreadInfo();
? ? ? ? ? ? ? ? threadInfo.setStart_flag(i*every_length);
? ? ? ? ? ? ? ? threadInfo.setEnd_flag((i+1)*every_length-1);
? ? ? ? ? ? ? ? threadInfo.setFinished(0);
? ? ? ? ? ? ? ? threadInfo.setUrl(fileInfo.getUrl());
? ? ? ? ? ? ? ? threadInfo.setThread_id(i);
? ? ? ? ? ? ? ? //可能不能平分,最后一個(gè)線程的長(zhǎng)度為剩余的所有
? ? ? ? ? ? ? ? if(i == countForThread-1){
? ? ? ? ? ? ? ? ? ? threadInfo.setEnd_flag(fileInfo.getLength());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? downLoadTask.insertThreadInfo(threadInfo);
? ? ? ? ? ? ? ? threadInfos.add(threadInfo);
? ? ? ? ? ? }
? ? ? ? }else {
? ? ? ? ? ? //該文件一共下載了多少了
? ? ? ? ? ? mFinished = fileInfo.getFinished();
? ? ? ? }

? ? ? ? downLoadThreads = new ArrayList<>();
? ? ? ? DownLoadThread downLoadThread = null;
? ? ? ? for(int i = 0;i<threadInfos.size();i++){
? ? ? ? ? ? downLoadThread = new DownLoadThread(threadInfos.get(i));
// ? ? ? ? ? ?downLoadThread.start();
? ? ? ? ? ? DownLoadTask.sExecutorService.execute(downLoadThread);//執(zhí)行線程,相當(dāng)于開(kāi)啟個(gè)線程使用這個(gè)就不需要使用.start方法
? ? ? ? ? ? downLoadThreads.add(downLoadThread);
? ? ? ? }
? ? }

? ? //真正開(kāi)始下載文件的線程
? ? class DownLoadThread extends Thread{
? ? ? ? private ThreadInfo threadInfo;
? ? ? ? private boolean isFinished;//該線程是否結(jié)束

? ? ? ? public DownLoadThread(ThreadInfo threadInfo) {
? ? ? ? ? ? this.threadInfo = threadInfo;
? ? ? ? ? ? Log.e("------------->","threadInfo:"+threadInfo);
? ? ? ? }

? ? ? ? @Override
? ? ? ? public void run() {
? ? ? ? ? ? super.run();

? ? ? ? ? ? HttpURLConnection connection = null;
? ? ? ? ? ? RandomAccessFile accessFile = null;
? ? ? ? ? ? InputStream inputStream = null;
? ? ? ? ? ? Intent intent = new Intent();
? ? ? ? ? ? intent.setAction("UPDATE_PROGRESSBAR");
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? URL url = new URL(threadInfo.getUrl());
? ? ? ? ? ? ? ? connection = (HttpURLConnection) url.openConnection();
? ? ? ? ? ? ? ? connection.setRequestMethod("GET");
? ? ? ? ? ? ? ? connection.setConnectTimeout(5000);

?? ??? ??? ??? ?//下載開(kāi)始的范圍是,這個(gè)線程的開(kāi)始下載的地方+已經(jīng)下載的進(jìn)度
? ? ? ? ? ? ? ? long start = threadInfo.getStart_flag()+threadInfo.getFinished();
? ? ? ? ? ? ? ? //設(shè)置下載的范圍
? ? ? ? ? ? ? ? connection.setRequestProperty("Range","bytes="+start+"-"+threadInfo.getEnd_flag());
? ? ? ? ? ? ? ? File file = new File(DownLoadService.PATH,fileInfo.getFile_name());
? ? ? ? ? ? ? ? accessFile = new RandomAccessFile(file,"rwd");
? ? ? ? ? ? ? ? //設(shè)置文件寫(xiě)入位置
? ? ? ? ? ? ? ? accessFile.seek(start);
? ? ? ? ? ? ? ? int len = -1;
? ? ? ? ? ? ? ? byte[] bytes = new byte[1024];
? ? ? ? ? ? ? ? if(connection.getResponseCode() == 206){
? ? ? ? ? ? ? ? ? ? inputStream = connection.getInputStream();
? ? ? ? ? ? ? ? ? ? long time = System.currentTimeMillis();
? ? ? ? ? ? ? ? ? ? while ((len = inputStream.read(bytes))!=-1){
? ? ? ? ? ? ? ? ? ? ? ? accessFile.write(bytes,0,len);
? ? ? ? ? ? ? ? ? ? ? ? //文件整體的下載進(jìn)度
? ? ? ? ? ? ? ? ? ? ? ? mFinished+=len;
? ? ? ? ? ? ? ? ? ? ? ? threadInfo.setFinished(threadInfo.getFinished()+len);
? ? ? ? ? ? ? ? ? ? ? ? //每1秒鐘發(fā)送一個(gè)廣播更新界面
? ? ? ? ? ? ? ? ? ? ? ? if(System.currentTimeMillis()-time>1000){
? ? ? ? ? ? ? ? ? ? ? ? ? ? time = System.currentTimeMillis();
? ? ? ? ? ? ? ? ? ? ? ? ? ? //以便區(qū)分下載的是那個(gè)文件
? ? ? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("id",fileInfo.getId());
? ? ? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("length",fileInfo.getLength());
? ? ? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("finished",mFinished);
? ? ? ? ? ? ? ? ? ? ? ? ? ? context.sendBroadcast(intent);
? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? //暫停更新數(shù)據(jù)庫(kù)
? ? ? ? ? ? ? ? ? ? ? ? if(isPause){
? ? ? ? ? ? ? ? ? ? ? ? ? ? downLoadTask.updateThreadInfo(threadInfo,threadInfo.getThread_id(),threadInfo.getUrl());
? ? ? ? ? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? Log.e("------------>","線程結(jié)束:"+threadInfo.toString());
? ? ? ? ? ? ? ? ? ? isFinished = true;
? ? ? ? ? ? ? ? ? ? downLoadTask.updateThreadInfo(threadInfo,threadInfo.getThread_id(),threadInfo.getUrl());
? ? ? ? ? ? ? ? ? ? checkAllThreadFinish();
? ? ? ? ? ? ? ? }

? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }finally {
? ? ? ? ? ? ? ? connection.disconnect();
? ? ? ? ? ? ? ? if(inputStream!=null){
? ? ? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? ? ? inputStream.close();
? ? ? ? ? ? ? ? ? ? ? ? accessFile.close();
? ? ? ? ? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }

? ? ? ? //所有的線程下載完成
? ? ? ? private synchronized void checkAllThreadFinish(){
? ? ? ? ? ? boolean finishAll = true;
? ? ? ? ? ? for(DownLoadThread downLoadThread:downLoadThreads){
? ? ? ? ? ? ? ? if(!downLoadThread.isFinished){
? ? ? ? ? ? ? ? ? ? finishAll = false;
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? if(finishAll){
? ? ? ? ? ? ? ? downLoadTask.deleteThreadInfo(fileInfo.getUrl());
? ? ? ? ? ? ? ? //有些時(shí)候可能剛好下完,但是那1秒的時(shí)候沒(méi)有取到所以進(jìn)度可能停在97%,所以這樣處理保證視覺(jué)的效果,可以直接將mFinished替換為fileInfo.getLength()。
? ? ? ? ? ? ? ? Intent intent = new Intent();
? ? ? ? ? ? ? ? intent.setAction("UPDATE_PROGRESSBAR");
? ? ? ? ? ? ? ? intent.putExtra("id",fileInfo.getId());
? ? ? ? ? ? ? ? intent.putExtra("length",fileInfo.getLength());
? ? ? ? ? ? ? ? intent.putExtra("finished",mFinished);
? ? ? ? ? ? ? ? context.sendBroadcast(intent);
? ? ? ? ? ? }
? ? ? ? }
? ? }

}

3、界面的代碼

上面羅列知識(shí)點(diǎn)的時(shí)候,說(shuō)到了權(quán)限,如果手機(jī)系統(tǒng)是6.0 以上的要獲取權(quán)限即請(qǐng)求用戶允許的那種,否則會(huì)出現(xiàn)android.system.ErrnoException: open failed: EACCES (Permission denied)異常,下面代碼中涉及權(quán)限的就是模擬一下,具體邏輯沒(méi)有嚴(yán)格的去實(shí)現(xiàn),大家看的時(shí)候需要注意。。

package com.example.a_0102.mylearn.download;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;

import com.example.a_0102.mylearn.R;

import java.util.ArrayList;
import java.util.List;

/**
?* 斷點(diǎn)續(xù)傳
?* 一個(gè)文件可以分成幾部分,使用不同的線程進(jìn)行下載,使用數(shù)據(jù)庫(kù)存儲(chǔ)每個(gè)線程的下載進(jìn)度
?*/
public class DownLoadActivity extends AppCompatActivity {

? ? private ListView mListView;
? ? private List<FileInfo> fileInfoList;
? ? private ListViewAdapter adapter;
? ? private UpdateUIReceiver mUpdateUIReceiver;
? ? private DownLoadTaskImpl downLoadTask;

? ? private Button mBtnDel;
? ? private Intent intent;

? ? @Override
? ? protected void onCreate(Bundle savedInstanceState) {
? ? ? ? super.onCreate(savedInstanceState);
? ? ? ? setContentView(R.layout.activity_down_load);
? ? ? ? //申請(qǐng)權(quán)限
? ? ? ? if (ContextCompat.checkSelfPermission(DownLoadActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
? ? ? ? ? ? //沒(méi)有權(quán)限
? ? ? ? ? ? Log.e("------------->", "沒(méi)有權(quán)限");


? ? ? ? ? ? ActivityCompat.requestPermissions(DownLoadActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
? ? ? ? } else {
? ? ? ? ? ? Log.e("------------->", "已經(jīng)有權(quán)限");
? ? ? ? }
? ? ? ? mBtnDel = findViewById(R.id.btn_del);

? ? ? ? downLoadTask = new DownLoadTaskImpl(this);

?? ??? ?//從數(shù)據(jù)庫(kù)獲取要下載的文件
? ? ? ? fileInfoList = new ArrayList<>();
? ? ? ? fileInfoList = downLoadTask.getFileInfo();
? ? ? ? //這里是用來(lái)模擬,具體請(qǐng)按照需求來(lái)寫(xiě)
? ? ? ? if (fileInfoList.size() == 0) {
? ? ? ? ? ? FileInfo fileInfo1 = new FileInfo(0, "http://oslw24znh.bkt.clouddn.com/android2017_07_05.apk", "xiaobang.apk", 0, 0, 0);
? ? ? ? ? ? FileInfo fileInfo2 = new FileInfo(1, "http://ofmudsqae.bkt.clouddn.com/%E5%91%A8%E5%86%AC%E9%9B%A8%20-%20%E4%B8%8D%E5%AE%8C%E7%BE%8E%E5%A5%B3%E5%AD%A9.mp3", "buwanmei.mp3", 0, 0, 0);
? ? ? ? ? ? fileInfoList.add(fileInfo1);
? ? ? ? ? ? fileInfoList.add(fileInfo2);
? ? ? ? }

? ? ? ? mListView = findViewById(R.id.listview);
? ? ? ? adapter = new ListViewAdapter();
? ? ? ? mListView.setAdapter(adapter);
?? ??? ?//為了測(cè)試寫(xiě)的,可忽略
? ? ? ? mBtnDel.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? Log.e("------------>","dddsize:"+downLoadTask.getFileInfo().size());
? ? ? ? ? ? ? ? downLoadTask.deleteFileInfo();
? ? ? ? ? ? ? ? Log.e("------------>","size:"+downLoadTask.getFileInfo().size());
? ? ? ? ? ? ? ? downLoadTask.deleteThreadInfo();
? ? ? ? ? ? }
? ? ? ? });

? ? }
? ? //申請(qǐng)權(quán)限的回調(diào)
?? ?@Override
? ? public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
? ? ? ? super.onRequestPermissionsResult(requestCode, permissions, grantResults);
? ? ? ? Log.e("------------->", "requestCode:" + requestCode + "," + permissions[0]);

? ? ? ? if (requestCode == 0) {
? ? ? ? ? ? if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
? ? ? ? ? ? ? ? Log.e("------------->", "授權(quán)被允許" );
? ? ? ? ? ? }else {
? ? ? ? ? ? ? ? Log.e("------------->", "授權(quán)沒(méi)有被允許" );
? ? ? ? ? ? }
? ? ? ? }
? ? }

? ? @Override
? ? protected void onResume() {
? ? ? ? super.onResume();
? ? ? ? // 1. 實(shí)例化BroadcastReceiver子類(lèi) & ?IntentFilter
? ? ? ? mUpdateUIReceiver = new UpdateUIReceiver();
? ? ? ? IntentFilter intentFilter = new IntentFilter();

? ? ? ? // 2. 設(shè)置接收廣播的類(lèi)型
? ? ? ? intentFilter.addAction("UPDATE_PROGRESSBAR");

? ? ? ? // 3. 動(dòng)態(tài)注冊(cè):調(diào)用Context的registerReceiver()方法
? ? ? ? registerReceiver(mUpdateUIReceiver, intentFilter);
? ? }


? ? // 注冊(cè)廣播后,要在相應(yīng)位置記得銷(xiāo)毀廣播
// 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
// 當(dāng)此Activity實(shí)例化時(shí),會(huì)動(dòng)態(tài)將MyBroadcastReceiver注冊(cè)到系統(tǒng)中
// 當(dāng)此Activity銷(xiāo)毀時(shí),動(dòng)態(tài)注冊(cè)的MyBroadcastReceiver將不再接收到相應(yīng)的廣播。
? ? @Override
? ? protected void onPause() {
? ? ? ? super.onPause();
? ? ? ? //銷(xiāo)毀在onResume()方法中的廣播
? ? ? ? unregisterReceiver(mUpdateUIReceiver);
? ? }


? ? @Override
? ? protected void onDestroy() {
? ? ? ? super.onDestroy();
? ? ? ? if (intent == null) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? stopService(intent);
? ? }

? ? private class ListViewAdapter extends BaseAdapter {

? ? ? ? @Override
? ? ? ? public int getCount() {
? ? ? ? ? ? return fileInfoList.size();
? ? ? ? }

? ? ? ? @Override
? ? ? ? public Object getItem(int position) {
? ? ? ? ? ? return fileInfoList.get(position);
? ? ? ? }

? ? ? ? @Override
? ? ? ? public long getItemId(int position) {
? ? ? ? ? ? return position;
? ? ? ? }

? ? ? ? @Override
? ? ? ? public View getView(final int position, View convertView, ViewGroup parent) {
? ? ? ? ? ? ViewHolder viewHolder = null;
? ? ? ? ? ? if (convertView == null) {
? ? ? ? ? ? ? ? convertView = LayoutInflater.from(DownLoadActivity.this).inflate(R.layout.layout_down_item, parent, false);
? ? ? ? ? ? ? ? viewHolder = new ViewHolder();
? ? ? ? ? ? ? ? viewHolder.mProgress = convertView.findViewById(R.id.progress);
? ? ? ? ? ? ? ? viewHolder.mBtnDown = convertView.findViewById(R.id.btn_down);
? ? ? ? ? ? ? ? viewHolder.mBtnStop = convertView.findViewById(R.id.btn_stop);
? ? ? ? ? ? ? ? convertView.setTag(viewHolder);
? ? ? ? ? ? ? ? //不用更新的盡量寫(xiě)在這里,防止每次都調(diào)用,進(jìn)度設(shè)置為100
? ? ? ? ? ? ? ? viewHolder.mProgress.setMax(100);
? ? ? ? ? ? ? ? viewHolder.mBtnDown.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? ? ? ? ? intent = new Intent(DownLoadActivity.this, DownLoadService.class);
? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("status", DownLoadService.STATUS_START);
? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("fileinfo", fileInfoList.get(position));
? ? ? ? ? ? ? ? ? ? ? ? startService(intent);
? ? ? ? ? ? ? ? ? ? ? ? if (!downLoadTask.isExitFileInfo(fileInfoList.get(position).getId())) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? downLoadTask.insertFileInfo(fileInfoList.get(position));
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });

? ? ? ? ? ? ? ? viewHolder.mBtnStop.setOnClickListener(new View.OnClickListener() {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public void onClick(View v) {
? ? ? ? ? ? ? ? ? ? ? ? intent = new Intent(DownLoadActivity.this, DownLoadService.class);
? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("status", DownLoadService.STATUS_STOP);
? ? ? ? ? ? ? ? ? ? ? ? intent.putExtra("fileinfo", fileInfoList.get(position));
? ? ? ? ? ? ? ? ? ? ? ? startService(intent);
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? });
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? viewHolder = (ViewHolder) convertView.getTag();
? ? ? ? ? ? }
? ? ? ? ? ? FileInfo fileInfo = fileInfoList.get(position);
? ? ? ? ? ? viewHolder.mProgress.setProgress(fileInfo.getProgress());

? ? ? ? ? ? return convertView;
? ? ? ? }

? ? ? ? class ViewHolder {
? ? ? ? ? ? private ProgressBar mProgress;
? ? ? ? ? ? private Button mBtnDown;
? ? ? ? ? ? private Button mBtnStop;
? ? ? ? }
? ? }


? ? /**
? ? ?* 用于更新UI的廣播
? ? ?* 使用靜態(tài)注冊(cè)的廣播,廣播的類(lèi)如果是內(nèi)部類(lèi),那么,該類(lèi)必須為static修飾的類(lèi),否則has no zero argument constructor 這個(gè)異常
? ? ?* https://blog.csdn.net/zhongjianblackberry/article/details/56670084
? ? ?* 或者用動(dòng)態(tài)注冊(cè)廣播
? ? ?*/
? ? public class UpdateUIReceiver extends BroadcastReceiver {

? ? ? ? @Override
? ? ? ? public void onReceive(Context context, Intent intent) {
? ? ? ? ? ? if (intent.getAction().equals("UPDATE_PROGRESSBAR")) {
? ? ? ? ? ? ? ? int id = intent.getIntExtra("id", 0);
? ? ? ? ? ? ? ? int finished = intent.getIntExtra("finished", 0);
? ? ? ? ? ? ? ? int length = intent.getIntExtra("length", 0);
? ? ? ? ? ? ? ? if (length == 0 || length < 0) {
? ? ? ? ? ? ? ? ? ? return;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? int progress = finished * 100 / length;
? ? ? ? ? ? ? ? FileInfo fileInfo = fileInfoList.get(id);
? ? ? ? ? ? ? ? fileInfo.setFinished(finished);
? ? ? ? ? ? ? ? fileInfo.setLength(length);
? ? ? ? ? ? ? ? fileInfo.setProgress(progress);
? ? ? ? ? ? ? ? adapter.notifyDataSetChanged();
? ? ? ? ? ? ? ? downLoadTask.updateFileInfo(fileInfo, id);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}

4、接下來(lái)是文件類(lèi)和線程類(lèi)的代碼

public class FileInfo implements Serializable {
? ? private int id;
? ? private String url;//文件的URL
? ? private String file_name;//文件名稱
? ? private int progress;//當(dāng)前進(jìn)度(顯示在進(jìn)度條上的)
? ? private int finished;//已下載完的(實(shí)際下載的大小)
? ? private int length;//文件的大小

? ? public FileInfo() {
? ? }

? ? public FileInfo(int id, String url, String file_name, int progress, int finished, int length) {
? ? ? ? this.id = id;
? ? ? ? this.url = url;
? ? ? ? this.file_name = file_name;
? ? ? ? this.progress = progress;
? ? ? ? this.finished = finished;
? ? ? ? this.length = length;
? ? }

? ? public int getId() {
? ? ? ? return id;
? ? }

? ? public void setId(int id) {
? ? ? ? this.id = id;
? ? }

? ? public String getUrl() {
? ? ? ? return url;
? ? }

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

? ? public String getFile_name() {
? ? ? ? return file_name;
? ? }

? ? public void setFile_name(String file_name) {
? ? ? ? this.file_name = file_name;
? ? }

? ? public int getProgress() {
? ? ? ? return progress;
? ? }

? ? public void setProgress(int progress) {
? ? ? ? this.progress = progress;
? ? }

? ? public int getLength() {
? ? ? ? return length;
? ? }

? ? public void setLength(int length) {
? ? ? ? this.length = length;
? ? }

? ? public int getFinished() {
? ? ? ? return finished;
? ? }

? ? public void setFinished(int finished) {
? ? ? ? this.finished = finished;
? ? }

? ? @Override
? ? public String toString() {
? ? ? ? return "FileInfo{" +
? ? ? ? ? ? ? ? "id=" + id +
? ? ? ? ? ? ? ? ", url='" + url + '\'' +
? ? ? ? ? ? ? ? ", file_name='" + file_name + '\'' +
? ? ? ? ? ? ? ? ", progress=" + progress +
? ? ? ? ? ? ? ? ", finished=" + finished +
? ? ? ? ? ? ? ? ", length=" + length +
? ? ? ? ? ? ? ? '}';
? ? }
}
public class ThreadInfo implements Serializable {
? ? private int id;//主鍵自增
? ? private int thread_id;//如果沒(méi)有id,唯一的標(biāo)識(shí),多線程的時(shí)候就不知道更新哪個(gè)了
? ? private String url;
? ? private long start_flag;
? ? private long end_flag;
? ? private long finished;//該線程的下載進(jìn)度

? ? public ThreadInfo() {
? ? }

? ? public ThreadInfo(int thread_id, String url, long start_flag, long end_flag, long finished) {
? ? ? ? this.thread_id = thread_id;
? ? ? ? this.url = url;
? ? ? ? this.start_flag = start_flag;
? ? ? ? this.end_flag = end_flag;
? ? ? ? this.finished = finished;
? ? }

? ? public int getId() {
? ? ? ? return id;
? ? }

? ? public void setId(int id) {
? ? ? ? this.id = id;
? ? }

? ? public int getThread_id() {
? ? ? ? return thread_id;
? ? }

? ? public void setThread_id(int thread_id) {
? ? ? ? this.thread_id = thread_id;
? ? }

? ? public String getUrl() {
? ? ? ? return url;
? ? }

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

? ? public long getStart_flag() {
? ? ? ? return start_flag;
? ? }

? ? public void setStart_flag(long start_flag) {
? ? ? ? this.start_flag = start_flag;
? ? }

? ? public long getEnd_flag() {
? ? ? ? return end_flag;
? ? }

? ? public void setEnd_flag(long end_flag) {
? ? ? ? this.end_flag = end_flag;
? ? }

? ? public long getFinished() {
? ? ? ? return finished;
? ? }

? ? public void setFinished(long finished) {
? ? ? ? this.finished = finished;
? ? }

? ? @Override
? ? public String toString() {
? ? ? ? return "ThreadInfo{" +
? ? ? ? ? ? ? ? "id=" + id +
? ? ? ? ? ? ? ? ", thread_id=" + thread_id +
? ? ? ? ? ? ? ? ", url='" + url + '\'' +
? ? ? ? ? ? ? ? ", start_flag=" + start_flag +
? ? ? ? ? ? ? ? ", end_flag=" + end_flag +
? ? ? ? ? ? ? ? ", finished=" + finished +
? ? ? ? ? ? ? ? '}';
? ? }
}

5、數(shù)據(jù)庫(kù)的代碼

這里要用單例模式,否則會(huì)報(bào)錯(cuò)

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
?* 要用單例的,否則會(huì)出現(xiàn)Cannot perform this operation because the connection pool has been closed
?*/

public class DbHalper extends SQLiteOpenHelper {
? ? private static final String DB_NAME = "downloadfile";
? ? private static final int DB_VERSION = 1;
? ? private static final String CREATE_THREAD_INFO = "create table thread_info (id integer primary key autoincrement,thread_id int,url text ,start_flag int,end_flag int,finished int);";
? ? private static final String CREATE_FILE_INFO = "create table file_info (id integer primary key,url text ,file_name text,length int,progress int,finished int);";

? ? private static DbHalper dbHalper;

? ? public static DbHalper getDbHalper(Context context){
? ? ? ? if(dbHalper == null){
? ? ? ? ? ? dbHalper = new DbHalper(context);
? ? ? ? }
? ? ? ? return dbHalper;
? ? }
? ? private DbHalper(Context context) {
? ? ? ? super(context, DB_NAME, null, DB_VERSION);
? ? }

? ? @Override
? ? public void onCreate(SQLiteDatabase db) {
? ? ? ? db.execSQL(CREATE_THREAD_INFO);
? ? ? ? db.execSQL(CREATE_FILE_INFO);
? ? }

? ? @Override
? ? public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

? ? }
}
public interface IDownLoadTask {

? ? /**
? ? ?* 插入線程信息
? ? ?*
? ? ?* @param threadInfo
? ? ?*/
? ? void insertThreadInfo(ThreadInfo threadInfo);

? ? /**
? ? ?* 更新線程信息
? ? ?*
? ? ?* @param threadInfo
? ? ?* @param id
? ? ?*/
? ? void updateThreadInfo(ThreadInfo threadInfo, int id, String url);

? ? /**
? ? ?* 刪除下載完成的線程記錄
? ? ?*
? ? ?* @param url
? ? ?*/
? ? void deleteThreadInfo(String url);

? ? /**
? ? ?* 獲取所有線程信息
? ? ?*
? ? ?* @param url
? ? ?* @return
? ? ?*/
? ? List<ThreadInfo> getThreadInfos(String url);

? ? /**
? ? ?* 獲取所有線程信息
? ? ?*
? ? ?* @return
? ? ?*/
? ? List<ThreadInfo> getThreadInfos();

? ? /**
? ? ?* 插入文件信息
? ? ?*
? ? ?* @param fileInfo
? ? ?*/
? ? void insertFileInfo(FileInfo fileInfo);


? ? /**
? ? ?* 修改文件的信息
? ? ?*
? ? ?* @param fileInfo
? ? ?* @param id
? ? ?*/
? ? void updateFileInfo(FileInfo fileInfo, int id);


? ? /**
? ? ?* 該文件信息是否存在
? ? ?*
? ? ?* @param id
? ? ?* @return
? ? ?*/
? ? boolean isExitFileInfo(int id);


? ? /**
? ? ?* 查詢文件信息
? ? ?*
? ? ?* @return
? ? ?*/
? ? List<FileInfo> getFileInfo();

? ? /**
? ? ?* 刪除文件信息
? ? ?*/
? ? void deleteFileInfo();

? ? /**
? ? ?* 刪除文件下載的線程信息
? ? ?*/
? ? void deleteThreadInfo();
}

接口類(lèi)的實(shí)現(xiàn),注意同步,否則多個(gè)線程一起操作一個(gè)方法會(huì)出現(xiàn)“驚喜“

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import java.util.ArrayList;
import java.util.List;

/**
?* 增、刪、改方法要保證線程安全,同一時(shí)刻只能有一個(gè)線程訪問(wèn)
?*/

public class DownLoadTaskImpl implements IDownLoadTask {
? ? private DbHalper dbHalper;
? ? private SQLiteDatabase db;

? ? public DownLoadTaskImpl(Context context) {
? ? ? ? dbHalper = DbHalper.getDbHalper(context);
? ? }

? ? @Override
? ? public synchronized void insertThreadInfo(ThreadInfo threadInfo) {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("insert into thread_info (thread_id,url,start_flag,end_flag,finished) values (?,?,?,?,?);",
? ? ? ? ? ? ? ? new Object[]{threadInfo.getThread_id(),threadInfo.getUrl(),threadInfo.getStart_flag(),
? ? ? ? ? ? ? ? ? ? ? ? threadInfo.getEnd_flag(),threadInfo.getFinished()});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public synchronized void updateThreadInfo(ThreadInfo threadInfo, int thread_id,String url) {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("update thread_info set thread_id=?, url=?,start_flag=?,end_flag=?,finished=? ?where thread_id = ? and url = ?;",
? ? ? ? ? ? ? ? new Object[]{threadInfo.getThread_id(),threadInfo.getUrl(), threadInfo.getStart_flag(),
? ? ? ? ? ? ? ? ? ? ? ? threadInfo.getEnd_flag(),threadInfo.getFinished(),thread_id,url});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public synchronized void deleteThreadInfo(String url) {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("delete from thread_info where url=?;",new String[]{url});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public List<ThreadInfo> getThreadInfos(String url) {
? ? ? ? ? ? List<ThreadInfo> threadInfos = new ArrayList<>();
? ? ? ? ? ? SQLiteDatabase db = dbHalper.getReadableDatabase();
? ? ? ? ? ? Cursor cursor = db.rawQuery("select * from thread_info where url=?;",new String[]{url});
? ? ? ? ? ? while (cursor.moveToNext()){
? ? ? ? ? ? ? ? ThreadInfo threadInfo = new ThreadInfo();
? ? ? ? ? ? ? ? threadInfo.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
? ? ? ? ? ? ? ? threadInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
? ? ? ? ? ? ? ? threadInfo.setStart_flag(cursor.getInt(cursor.getColumnIndex("start_flag")));
? ? ? ? ? ? ? ? threadInfo.setEnd_flag(cursor.getInt(cursor.getColumnIndex("end_flag")));
? ? ? ? ? ? ? ? threadInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
? ? ? ? ? ? ? ? threadInfos.add(threadInfo);
? ? ? ? ? ? }
? ? ? ? ? ? cursor.close();
? ? ? ? ? ? db.close();
? ? ? ? ? ? return threadInfos;
? ? ? ? }

? ? @Override
? ? public List<ThreadInfo> getThreadInfos() {
? ? ? ? List<ThreadInfo> threadInfos = new ArrayList<>();
? ? ? ? SQLiteDatabase db = dbHalper.getReadableDatabase();
? ? ? ? Cursor cursor = db.rawQuery("select * from thread_info;",new String[]{});
? ? ? ? while (cursor.moveToNext()){
? ? ? ? ? ? ThreadInfo threadInfo = new ThreadInfo();
? ? ? ? ? ? threadInfo.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
? ? ? ? ? ? threadInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
? ? ? ? ? ? threadInfo.setStart_flag(cursor.getInt(cursor.getColumnIndex("start_flag")));
? ? ? ? ? ? threadInfo.setEnd_flag(cursor.getInt(cursor.getColumnIndex("end_flag")));
? ? ? ? ? ? threadInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
? ? ? ? ? ? threadInfos.add(threadInfo);
? ? ? ? }
? ? ? ? cursor.close();
? ? ? ? db.close();
? ? ? ? return threadInfos;
? ? }

? ? @Override
? ? public synchronized void insertFileInfo(FileInfo fileInfo) {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("replace into file_info (id,url,file_name,length,progress,finished) values (?,?,?,?,?,?);",
? ? ? ? ? ? ? ? new Object[]{fileInfo.getId(),fileInfo.getUrl(),fileInfo.getFile_name(),fileInfo.getLength(),
? ? ? ? ? ? ? ? ? ? ? ? fileInfo.getProgress(),fileInfo.getFinished()});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public synchronized void updateFileInfo(FileInfo fileInfo, int id) {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("update file_info set id=?, url=?,file_name=?,length=?,progress=?,finished=? ?where id = ?;",
? ? ? ? ? ? ? ? new Object[]{fileInfo.getId(),fileInfo.getUrl(), fileInfo.getFile_name(),fileInfo.getLength(),
? ? ? ? ? ? ? ? ? ? ? ? fileInfo.getProgress(),fileInfo.getFinished(),id});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public boolean isExitFileInfo(int id) {
? ? ? ? SQLiteDatabase db = dbHalper.getReadableDatabase();
? ? ? ? boolean isExit = false;
? ? ? ? Cursor cursor = db.rawQuery("select * from file_info where id=?;",new String[]{id+""});
? ? ? ? while (cursor.moveToNext()){
? ? ? ? ? ? isExit = true;
? ? ? ? }
? ? ? ? cursor.close();
? ? ? ? db.close();
? ? ? ? return isExit;
? ? }

? ? @Override
? ? public List<FileInfo> getFileInfo() {
? ? ? ? List<FileInfo> fileInfos = new ArrayList<>();
? ? ? ? SQLiteDatabase db = dbHalper.getReadableDatabase();
? ? ? ? Cursor cursor = db.rawQuery("select * from file_info;",new String[]{});
? ? ? ? while (cursor.moveToNext()){
? ? ? ? ? ? FileInfo fileInfo = new FileInfo();
? ? ? ? ? ? fileInfo.setId(cursor.getInt(cursor.getColumnIndex("id")));
? ? ? ? ? ? fileInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
? ? ? ? ? ? fileInfo.setFile_name(cursor.getString(cursor.getColumnIndex("file_name")));
? ? ? ? ? ? fileInfo.setLength(cursor.getInt(cursor.getColumnIndex("length")));
? ? ? ? ? ? fileInfo.setProgress(cursor.getInt(cursor.getColumnIndex("progress")));
? ? ? ? ? ? fileInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
? ? ? ? ? ? fileInfos.add(fileInfo);
? ? ? ? }
? ? ? ? cursor.close();
? ? ? ? db.close();
? ? ? ? return fileInfos;
? ? }

? ? @Override
? ? public synchronized void deleteFileInfo() {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("delete from file_info;",new String[]{});
? ? ? ? db.close();
? ? }

? ? @Override
? ? public void deleteThreadInfo() {
? ? ? ? SQLiteDatabase db = dbHalper.getWritableDatabase();
? ? ? ? db.execSQL("delete from thread_info;",new String[]{});
? ? ? ? db.close();
? ? }
}

提示:可以直接使用FileDownloader一個(gè)開(kāi)源的下載大文件的框架,使用就自行百度吧

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論