Android實(shí)現(xiàn)多線程斷點(diǎn)續(xù)傳
本文實(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)文章
Android編程之絕對(duì)布局AbsoluteLayout和相對(duì)布局RelativeLayout實(shí)例詳解
這篇文章主要介紹了Android編程之絕對(duì)布局AbsoluteLayout和相對(duì)布局RelativeLayout實(shí)現(xiàn)方法,結(jié)合實(shí)例形式詳細(xì)分析了Android絕對(duì)布局AbsoluteLayout和相對(duì)布局RelativeLayout的原理與使用技巧,需要的朋友可以參考下2015-12-12ubuntu用wifi連接android調(diào)試程序的步驟
這篇文章主要介紹了ubuntu用wifi連接android調(diào)試程序的步驟,需要的朋友可以參考下2014-02-02Android開(kāi)發(fā)Jetpack組件Room使用講解
Room是一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)組件; 對(duì)SqLite數(shù)據(jù)庫(kù)做了友好的封裝,使我們?cè)诰幋a的時(shí)候,只需要注重邏輯的部分即可,數(shù)據(jù)庫(kù)就交給Room去流暢的訪問(wèn)即可2022-08-08談?wù)凙ndroid的三種網(wǎng)絡(luò)通信方式
Android平臺(tái)有三種網(wǎng)絡(luò)接口可以使用,他們分別是:java.net.*(標(biāo)準(zhǔn)Java接口)、Org.apache接口和Android.net.*(Android網(wǎng)絡(luò)接口)。本文詳細(xì)的介紹,有興趣的可以了解一下。2017-01-01Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車(chē)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單購(gòu)物車(chē),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06Android實(shí)現(xiàn)手電筒電源鍵關(guān)閉功能
這篇文章主要介紹了Android實(shí)現(xiàn)手電筒電源鍵關(guān)閉功能,在打開(kāi)手電筒之后,機(jī)器休眠,客戶要求點(diǎn)擊電源鍵,手電筒需要關(guān)閉,下面小編給大家分享實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-11-11Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題
這篇文章主要介紹了Android 解決游戲發(fā)行切包資源索引沖突的問(wèn)題,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03Android 使用手機(jī)NFC的讀取NFC標(biāo)簽數(shù)據(jù)的方法
這篇文章主要介紹了Android 使用手機(jī)NFC的讀取NFC標(biāo)簽數(shù)據(jù)的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07Windows下快速搭建安卓開(kāi)發(fā)環(huán)境Android studio
這篇文章主要介紹了Windows下快速搭建安卓開(kāi)發(fā)環(huán)境Android studio的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-07-07