软件测试界面
功能介绍:输入下载地址后,点击下载,进度条显示下载的百分比,处于下载时下载按钮无法使用,未开始下载,停止按钮无法使用
完整代码分析:
1.界面创建:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:orientation="vertical" > 6 7 <TextView 8 android:layout_width="fill_parent" 9 android:layout_height="wrap_content" 10 android:text="@string/path" /> 11 12 <EditText 13 android:id="@+id/path" 14 android:layout_width="fill_parent" 15 android:layout_height="wrap_content" 16 android:text="http://192.168.0.117/testxml/xunlei.exe" /> 17 <LinearLayout 18 android:layout_width="fill_parent" 19 android:layout_height="wrap_content" 20 android:orientation="horizontal" 21 > 22 <!--下载按钮--> 23 <Button 24 android:id="@+id/downloadbutton" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:text="@string/button" /> 28 <!--停止按钮--> 29 <Button 30 android:id="@+id/stopbutton" 31 android:layout_width="wrap_content" 32 android:layout_height="wrap_content" 33 android:text="@string/stopbutton" 34 android:enabled="false"/> 35 36 </LinearLayout> 37 38 <ProgressBar 39 android:id="@+id/progressBar" 40 style="?android:attr/progressBarStyleHorizontal" 41 android:layout_width="fill_parent" 42 android:layout_height="18dp" /> 43 <!--进度条下面的百分比--> 44 <TextView 45 android:id="@+id/resultview" 46 android:layout_width="fill_parent" 47 android:layout_height="wrap_content" 48 android:gravity="center" /> 49 50 </LinearLayout>
2.清单文件
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="caicai.cn.multhreaddownloader" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk android:minSdkVersion="8" /> 8 <uses-permission android:name="android.permission.INTERNET"/> 9 <!--允许装备或解除可移除的存储仓库的文件系统 --> 10 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 11 <!--允许写入外存储设备即SDcard --> 12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 13 14 <application 15 android:icon="@drawable/ic_launcher" 16 android:label="@string/app_name" > 17 <activity 18 android:label="@string/app_name" 19 android:name=".Cai_multhreaddownloaderActivity" > 20 <intent-filter > 21 <action android:name="android.intent.action.MAIN" /> 22 23 <category android:name="android.intent.category.LAUNCHER" /> 24 </intent-filter> 25 </activity> 26 </application> 27 28 </manifest>
3.界面操作
1 package caicai.cn.multhreaddownloader; 2 3 import java.io.File; 4 5 import net.download.DownloadProgressListener; 6 import net.download.FileDownloader; 7 8 import android.app.Activity; 9 import android.os.Bundle; 10 import android.os.Environment; 11 import android.os.Handler; 12 import android.os.Message; 13 import android.view.View; 14 import android.widget.Button; 15 import android.widget.EditText; 16 import android.widget.ProgressBar; 17 import android.widget.TextView; 18 import android.widget.Toast; 19 20 public class Cai_multhreaddownloaderActivity extends Activity { 21 private EditText pathtext; 22 private TextView resultview; 23 private Button downloadbutton; 24 private Button stopbutton; 25 private ProgressBar progressBar; 26 private Handler handler = new Uihandler(); 27 28 // handler用于往创建handler对象所在的线程所绑定的消息队列发送消息 29 30 private final class Uihandler extends Handler {// 接收从子线程传来的值,注意只有主线程才能对UI控件进行控制与更新 31 public void handleMessage(Message msg) { 32 switch (msg.what) { 33 case 1: 34 int size = msg.getData().getInt("size"); 35 progressBar.setProgress(size);// 当前刻度; 36 float num = (float) progressBar.getProgress() 37 / (float) progressBar.getMax(); 38 int result = (int) (num * 100); 39 resultview.setText(result + "%"); 40 if (progressBar.getProgress() == progressBar.getMax()) { 41 Toast.makeText(getApplicationContext(), "下载完成", 1).show(); 42 } 43 break; 44 case -1: 45 Toast.makeText(getApplicationContext(), R.string.error, 1) 46 .show(); 47 break; 48 } 49 50 } 51 } 52 53 public void onCreate(Bundle savedInstanceState) { 54 super.onCreate(savedInstanceState); 55 setContentView(R.layout.main); 56 pathtext = (EditText) this.findViewById(R.id.path); 57 resultview = (TextView) this.findViewById(R.id.resultview); 58 downloadbutton = (Button) this.findViewById(R.id.downloadbutton); 59 stopbutton = (Button) this.findViewById(R.id.stopbutton); 60 progressBar = (ProgressBar) this.findViewById(R.id.progressBar); 61 Buttonclicklistener listener = new Buttonclicklistener(); 62 downloadbutton.setOnClickListener(listener); 63 stopbutton.setOnClickListener(listener); 64 } 65 66 private final class Buttonclicklistener implements View.OnClickListener { 67 68 public void onClick(View v) { 69 switch (v.getId()) { 70 case R.id.downloadbutton: 71 String path = pathtext.getText().toString();// 获取下载路径 72 if (Environment.getExternalStorageState().equals( 73 Environment.MEDIA_MOUNTED)) {// 判断SDcard是否存在 或者可写数据 74 File savedir = Environment.getExternalStorageDirectory();// 获取sdcard跟目录,即保存路径 75 download(path, savedir); 76 }else{ 77 Toast.makeText(getApplicationContext(),R.string.sdcarderror, 1).show(); 78 } 79 downloadbutton.setEnabled(false); 80 stopbutton.setEnabled(true); 81 break; 82 case R.id.stopbutton: 83 exit(); 84 downloadbutton.setEnabled(true); 85 stopbutton.setEnabled(false); 86 break; 87 } 88 } 89 90 /* 91 * 由于用户的输入事件(点击button, 触摸屏幕....)是由主线程负责处理的,如果主线程处于工作状态, 92 * 此时用户产生的输入事件如果没能在5秒内得到处理,系统就会报“应用无响应”错误。 93 * 所以在主线程里不能执行一件比较耗时的工作,否则会因主线程阻塞而无法处理用户的输入事件, 94 * 导致“应用无响应”错误的出现。耗时的工作应该在子线程里执行。 95 */ 96 private DownloadTask task; 97 private void exit() {//退出下载 98 if (task!= null) { 99 task.exit(); 100 } 101 }; 102 103 private void download(String path, File savedir) { 104 task = new DownloadTask(path, savedir); 105 new Thread(task).start(); 106 } 107 108 private final class DownloadTask implements Runnable { 109 String path; 110 File savedir; 111 FileDownloader loader; 112 113 public DownloadTask(String path, File savedir) { 114 this.path = path; 115 this.savedir = savedir; 116 } 117 118 public void exit() { 119 if (loader != null) { 120 loader.exit();// 退出下载 121 } 122 } 123 124 @Override 125 public void run() { 126 try { 127 loader = new FileDownloader(getApplicationContext(), path, 128 savedir, 3); 129 progressBar.setMax(loader.getFileSize());// 设置进度条最大刻度 130 loader.download(new DownloadProgressListener() { 131 @Override 132 public void onDownloadSize(int size) { 133 Message msg = new Message(); 134 msg.what = 1;// 定义消息的ID,以便区别那个消息发过来的 135 msg.getData().putInt("size", size); 136 handler.sendMessage(msg); 137 138 } 139 }); 140 } catch (Exception e) { 141 e.printStackTrace(); 142 handler.sendMessage(handler.obtainMessage(-1));// 发送编号为-1的空消息 143 } 144 145 } 146 147 } 148 } 149 }
4.下载接口
1 package net.download; 2 3 public interface DownloadProgressListener { 4 public void onDownloadSize(int size); 5 }
5.下载线程类
1 package net.download; 2 3 import java.io.File; 4 import java.io.InputStream; 5 import java.io.RandomAccessFile; 6 import java.net.HttpURLConnection; 7 import java.net.URL; 8 9 import android.util.Log; 10 11 public class DownloadThread extends Thread { 12 private static final String TAG = "DownloadThread"; 13 private File saveFile; 14 private URL downUrl; 15 private int block; 16 /* 下载开始位置 */ 17 private int threadId = -1; 18 private int downLength; 19 private boolean finish = false; 20 private FileDownloader downloader; 21 22 public DownloadThread(FileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId) { 23 this.downUrl = downUrl; 24 this.saveFile = saveFile; 25 this.block = block; 26 this.downloader = downloader; 27 this.threadId = threadId; 28 this.downLength = downLength; 29 } 30 31 @Override 32 public void run() { 33 if(downLength < block){//未下载完成 34 try { 35 HttpURLConnection http = (HttpURLConnection) downUrl.openConnection(); 36 http.setConnectTimeout(5 * 1000); 37 http.setRequestMethod("GET"); 38 http.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); 39 http.setRequestProperty("Accept-Language", "zh-CN"); 40 http.setRequestProperty("Referer", downUrl.toString()); 41 http.setRequestProperty("Charset", "UTF-8"); 42 int startPos = block * (threadId - 1) + downLength;//开始位置 43 int endPos = block * threadId -1;//结束位置 44 http.setRequestProperty("Range", "bytes=" + startPos + "-"+ endPos);//设置获取实体数据的范围 45 http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); 46 http.setRequestProperty("Connection", "Keep-Alive"); 47 48 InputStream inStream = http.getInputStream(); 49 byte[] buffer = new byte[1024]; 50 int offset = 0; 51 print("Thread " + this.threadId + " start download from position "+ startPos); 52 RandomAccessFile threadfile = new RandomAccessFile(this.saveFile, "rwd"); 53 threadfile.seek(startPos); 54 while (!downloader.getExit() && (offset = inStream.read(buffer, 0, 1024)) != -1) { 55 threadfile.write(buffer, 0, offset); 56 downLength += offset; 57 downloader.update(this.threadId, downLength); 58 downloader.append(offset); 59 } 60 threadfile.close(); 61 inStream.close(); 62 print("Thread " + this.threadId + " download finish"); 63 this.finish = true; 64 } catch (Exception e) { 65 this.downLength = -1; 66 print("Thread "+ this.threadId+ ":"+ e); 67 } 68 } 69 } 70 private static void print(String msg){ 71 Log.i(TAG, msg); 72 } 73 /** 74 * 下载是否完成 75 * @return 76 */ 77 public boolean isFinish() { 78 return finish; 79 } 80 /** 81 * 已经下载的内容大小 82 * @return 如果返回值为-1,代表下载失败 83 */ 84 public long getDownLength() { 85 return downLength; 86 } 87 }
6.文件下载器
1 package net.download; 2 3 import java.io.File; 4 import java.io.RandomAccessFile; 5 import java.net.HttpURLConnection; 6 import java.net.URL; 7 import java.util.LinkedHashMap; 8 import java.util.Map; 9 import java.util.UUID; 10 import java.util.concurrent.ConcurrentHashMap; 11 import java.util.regex.Matcher; 12 import java.util.regex.Pattern; 13 import service.FileService; 14 15 import android.content.Context; 16 import android.util.Log; 17 /** 18 * 文件下载器使用类案例 19 * 20 try { 21 FileDownloader loader = new FileDownloader(context, "http://browse.babasport.com/ejb3/ActivePort.exe", 22 new File("D:\\androidsoft\\test"), 2); 23 loader.getFileSize();//得到文件总大小 24 loader.download(new DownloadProgressListener(){ 25 public void onDownloadSize(int size) { 26 print("已经下载:"+ size); 27 } 28 }); 29 } catch (Exception e) { 30 e.printStackTrace(); 31 } 32 */ 33 public class FileDownloader { 34 private static final String TAG = "FileDownloader"; 35 private Context context; 36 private FileService fileService; 37 /* 停止下载 */ 38 private boolean exit; 39 /* 已下载文件长度 */ 40 private int downloadSize = 0; 41 /* 原始文件长度 */ 42 private int fileSize = 0; 43 /* 线程数 */ 44 private DownloadThread[] threads; 45 /* 本地保存文件 */ 46 private File saveFile; 47 /* 缓存各线程下载的长度*/ 48 private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>(); 49 /* 每条线程下载的长度 */ 50 private int block; 51 /* 下载路径 */ 52 private String downloadUrl; 53 /** 54 * 获取线程数 55 */ 56 public int getThreadSize() { 57 return threads.length; 58 } 59 /** 60 * 退出下载 61 */ 62 public void exit(){ 63 this.exit = true; 64 } 65 public boolean getExit(){ 66 return this.exit; 67 } 68 /** 69 * 获取文件大小 70 * @return 71 */ 72 public int getFileSize() { 73 return fileSize; 74 } 75 /** 76 * 累计已下载大小 77 * @param size 78 */ 79 protected synchronized void append(int size) { 80 downloadSize += size; 81 } 82 /** 83 * 更新指定线程最后下载的位置 84 * @param threadId 线程id 85 * @param pos 最后下载的位置 86 */ 87 protected synchronized void update(int threadId, int pos) { 88 this.data.put(threadId, pos); 89 this.fileService.update(this.downloadUrl, threadId, pos); 90 } 91 /** 92 * 构建文件下载器 93 * @param downloadUrl 下载路径 94 * @param fileSaveDir 文件保存目录 95 * @param threadNum 下载线程数 96 */ 97 public FileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) { 98 try { 99 this.context = context; 100 this.downloadUrl = downloadUrl; 101 fileService = new FileService(this.context); 102 URL url = new URL(this.downloadUrl); 103 if(!fileSaveDir.exists()) fileSaveDir.mkdirs(); 104 this.threads = new DownloadThread[threadNum]; 105 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 106 conn.setConnectTimeout(5*1000); 107 conn.setRequestMethod("GET"); 108 conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"); 109 conn.setRequestProperty("Accept-Language", "zh-CN"); 110 conn.setRequestProperty("Referer", downloadUrl); 111 conn.setRequestProperty("Charset", "UTF-8"); 112 conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"); 113 conn.setRequestProperty("Connection", "Keep-Alive"); 114 conn.connect(); 115 printResponseHeader(conn); 116 if (conn.getResponseCode()==200) { 117 this.fileSize = conn.getContentLength();//根据响应获取文件大小 118 if (this.fileSize <= 0) throw new RuntimeException("Unkown file size "); 119 120 String filename = getFileName(conn);//获取文件名称 121 this.saveFile = new File(fileSaveDir, filename);//构建保存文件 122 Map<Integer, Integer> logdata = fileService.getData(downloadUrl);//获取下载记录 123 if(logdata.size()>0){//如果存在下载记录 124 for(Map.Entry<Integer, Integer> entry : logdata.entrySet()) 125 data.put(entry.getKey(), entry.getValue());//把各条线程已经下载的数据长度放入data中 126 } 127 if(this.data.size()==this.threads.length){//下面计算所有线程已经下载的数据总长度 128 for (int i = 0; i < this.threads.length; i++) { 129 this.downloadSize += this.data.get(i+1); 130 } 131 print("已经下载的长度"+ this.downloadSize); 132 } 133 //计算每条线程下载的数据长度 134 this.block = (this.fileSize % this.threads.length)==0? this.fileSize / this.threads.length : this.fileSize / this.threads.length + 1; 135 }else{ 136 throw new RuntimeException("server no response "); 137 } 138 } catch (Exception e) { 139 print(e.toString()); 140 throw new RuntimeException("don't connection this url"); 141 } 142 } 143 /** 144 * 获取文件名 145 */ 146 private String getFileName(HttpURLConnection conn) { 147 String filename = this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/') + 1); 148 if(filename==null || "".equals(filename.trim())){//如果获取不到文件名称 149 for (int i = 0;; i++) { 150 String mine = conn.getHeaderField(i); 151 if (mine == null) break; 152 if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){ 153 Matcher m = Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase()); 154 if(m.find()) return m.group(1); 155 } 156 } 157 filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名 158 } 159 return filename; 160 } 161 162 /** 163 * 开始下载文件 164 * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null 165 * @return 已下载文件大小 166 * @throws Exception 167 */ 168 public int download(DownloadProgressListener listener) throws Exception{ 169 try { 170 RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rw"); 171 if(this.fileSize>0) randOut.setLength(this.fileSize); 172 randOut.close(); 173 URL url = new URL(this.downloadUrl); 174 if(this.data.size() != this.threads.length){//如果原先未曾下载或者原先的下载线程数与现在的线程数不一致 175 this.data.clear(); 176 for (int i = 0; i < this.threads.length; i++) { 177 this.data.put(i+1, 0);//初始化每条线程已经下载的数据长度为0 178 } 179 this.downloadSize = 0; 180 } 181 for (int i = 0; i < this.threads.length; i++) {//开启线程进行下载 182 int downLength = this.data.get(i+1); 183 if(downLength < this.block && this.downloadSize<this.fileSize){//判断线程是否已经完成下载,否则继续下载 184 this.threads[i] = new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1); 185 this.threads[i].setPriority(7); 186 this.threads[i].start(); 187 }else{ 188 this.threads[i] = null; 189 } 190 } 191 fileService.delete(this.downloadUrl);//如果存在下载记录,删除它们,然后重新添加 192 fileService.save(this.downloadUrl, this.data); 193 boolean notFinish = true;//下载未完成 194 while (notFinish) {// 循环判断所有线程是否完成下载 195 Thread.sleep(900); 196 notFinish = false;//假定全部线程下载完成 197 for (int i = 0; i < this.threads.length; i++){ 198 if (this.threads[i] != null && !this.threads[i].isFinish()) {//如果发现线程未完成下载 199 notFinish = true;//设置标志为下载没有完成 200 if(this.threads[i].getDownLength() == -1){//如果下载失败,再重新下载 201 this.threads[i] = new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1); 202 this.threads[i].setPriority(7); 203 this.threads[i].start(); 204 } 205 } 206 } 207 if(listener!=null) listener.onDownloadSize(this.downloadSize);//通知目前已经下载完成的数据长度 208 } 209 if(downloadSize == this.fileSize) fileService.delete(this.downloadUrl);//下载完成删除记录 210 } catch (Exception e) { 211 print(e.toString()); 212 throw new Exception("file download error"); 213 } 214 return this.downloadSize; 215 } 216 /** 217 * 获取Http响应头字段 218 * @param http 219 * @return 220 */ 221 public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) { 222 Map<String, String> header = new LinkedHashMap<String, String>(); 223 for (int i = 0;; i++) { 224 String mine = http.getHeaderField(i); 225 if (mine == null) break; 226 header.put(http.getHeaderFieldKey(i), mine); 227 } 228 return header; 229 } 230 /** 231 * 打印Http头字段 232 * @param http 233 */ 234 public static void printResponseHeader(HttpURLConnection http){ 235 Map<String, String> header = getHttpResponseHeader(http); 236 for(Map.Entry<String, String> entry : header.entrySet()){ 237 String key = entry.getKey()!=null ? entry.getKey()+ ":" : ""; 238 print(key+ entry.getValue()); 239 } 240 } 241 242 private static void print(String msg){ 243 Log.i(TAG, msg); 244 } 245 }
7.数据库操作类
1 package service; 2 3 import android.content.Context; 4 import android.database.sqlite.SQLiteDatabase; 5 import android.database.sqlite.SQLiteOpenHelper; 6 7 public class DBOpenHelper extends SQLiteOpenHelper { 8 private static final String DBNAME = "download.db"; 9 private static final int VERSION = 1; 10 11 public DBOpenHelper(Context context) { 12 super(context, DBNAME, null, VERSION); 13 } 14 15 @Override 16 public void onCreate(SQLiteDatabase db) { 17 db.execSQL("CREATE TABLE IF NOT EXISTS filedownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)"); 18 } 19 20 @Override 21 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 22 db.execSQL("DROP TABLE IF EXISTS filedownlog"); 23 onCreate(db); 24 } 25 26 }
8.下载的进度存入数据库操作类
1 package service; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import android.content.Context; 7 import android.database.Cursor; 8 import android.database.sqlite.SQLiteDatabase; 9 /** 10 * 业务bean 11 * 12 */ 13 public class FileService { 14 private DBOpenHelper openHelper; 15 16 public FileService(Context context) { 17 openHelper = new DBOpenHelper(context); 18 } 19 /** 20 * 获取每条线程已经下载的文件长度 21 * @param path 22 * @return 23 */ 24 public Map<Integer, Integer> getData(String path){ 25 SQLiteDatabase db = openHelper.getReadableDatabase(); 26 Cursor cursor = db.rawQuery("select threadid, downlength from filedownlog where downpath=?", new String[]{path}); 27 Map<Integer, Integer> data = new HashMap<Integer, Integer>(); 28 while(cursor.moveToNext()){ 29 data.put(cursor.getInt(0), cursor.getInt(1)); 30 } 31 cursor.close(); 32 db.close(); 33 return data; 34 } 35 /** 36 * 保存每条线程已经下载的文件长度 37 * @param path 38 * @param map 39 */ 40 public void save(String path, Map<Integer, Integer> map){//int threadid, int position 41 SQLiteDatabase db = openHelper.getWritableDatabase(); 42 db.beginTransaction(); 43 try{ 44 for(Map.Entry<Integer, Integer> entry : map.entrySet()){ 45 db.execSQL("insert into filedownlog(downpath, threadid, downlength) values(?,?,?)", 46 new Object[]{path, entry.getKey(), entry.getValue()}); 47 } 48 db.setTransactionSuccessful(); 49 }finally{ 50 db.endTransaction(); 51 } 52 db.close(); 53 } 54 /** 55 * 实时更新每条线程已经下载的文件长度 56 * @param path 57 * @param map 58 */ 59 public void update(String path, int threadId, int pos){ 60 SQLiteDatabase db = openHelper.getWritableDatabase(); 61 db.execSQL("update filedownlog set downlength=? where downpath=? and threadid=?", 62 new Object[]{pos, path, threadId}); 63 db.close(); 64 } 65 /** 66 * 当文件下载完成后,删除对应的下载记录 67 * @param path 68 */ 69 public void delete(String path){ 70 SQLiteDatabase db = openHelper.getWritableDatabase(); 71 db.execSQL("delete from filedownlog where downpath=?", new Object[]{path}); 72 db.close(); 73 } 74 75 }
相关推荐
在Android应用开发中,实现多线程断点续传下载是一项重要的技术,它能提高下载效率,节省用户时间,并提供良好的用户体验。以下是对这个主题的详细解析: **1. 多线程下载** 多线程下载是将一个大文件分成多个小块...
在Android应用开发中,多线程断点续传下载是一项重要的技术,它使得用户可以在网络不稳定或者设备需要执行其他任务时暂停下载,并在条件允许时继续之前未完成的部分,极大地提升了用户体验。本篇文章将深入探讨...
VC FTP、HTTP 多线程断点续传下载文件,在断点下载时,可获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等。可设置下载的线程数、下载任务的线程函数、多线程断点续传下载一个文件、关于BOOL ...
通过学习和分析这些代码,你可以更好地理解和掌握Android上的多线程断点续传文件下载技术。 总之,Android中的多线程断点续传文件下载涉及到文件系统权限、HTTP连接、多线程同步、数据持久化等多个方面,是Android...
"Android多线程断点续传下载+在线播放音乐.zip"源码资源提供了实现上述功能的代码示例,开发者可以通过研究源码来学习如何在实际项目中应用这些技术。源码可能包含以下几个部分: 1. 下载管理器:负责创建和管理...
在Android平台上,开发一款具有多线程断点续传下载功能和在线播放音乐的应用是一项挑战性的任务,涉及到多个核心技术和组件。以下是对这个项目源码的详细解析: 首先,我们来了解一下多线程断点续传下载。在Android...
在Android开发中,多线程断点续传下载是一项重要的技术,它允许用户在中断下载后,从上次停止的地方继续下载,提高了用户体验。本篇主要介绍Android实现这一功能的原理和步骤。 首先,理解断点续传的概念。断点续传...
本文将深入探讨这两个概念,并结合"android 多线程下载源码(支持断点续传)"这一主题,分析相关知识点。 1. **多线程下载** 多线程下载是为了提高下载速度,通过同时开启多个下载任务,让每个任务负责一部分文件...
本项目完成的功能类似与迅雷等下载工具所实现的功能——实现多线程断点下载。 主要设计的技术有: 1、android中主线程与非主线程通信机制。 2、多线程的编程和管理。 3、android网络编程 4、自己设计实现设计...
在安卓开发中,多线程断点续传下载与在线播放音乐是两个关键的技术点,它们极大地提升了用户体验。本项目提供了完整的源码实现,帮助开发者深入理解这些功能的实现细节。 首先,多线程断点续传下载是解决大文件下载...
【标题】"Android应用源码之AndroidDownLoad(多线程断点续传)"是一个针对Android平台的开源项目,旨在实现高效、稳定的文件下载功能,特别是对于大文件,它支持多线程下载和断点续传。这个项目可以帮助开发者深入...
本项目"Python-HTTP大文件多线程下载工具支持断点续传"旨在解决这个问题,它利用Python的多线程技术来提高文件下载速度,并且具备断点续传功能,允许用户在中断下载后继续从上次停止的位置开始,提高了下载的效率和...
在Android开发中,多线程和断点续传下载是两个关键的技术点,尤其是在处理大文件下载时。同时,为了提升用户体验,实现在线播放音乐也是必不可少的技能。本压缩包包含了一个示例应用,用于演示如何在Android环境中...
本项目"安卓Andriod源码——多线程断点续传下载+在线播放音乐.zip"提供了一个完整的示例,它涵盖了两个关键的技术:多线程断点续传下载和在线播放音乐。下面我们将深入探讨这两个主题。 1. 多线程断点续传下载: ...
本资料“应用源码之DownLoad(多线程断点续传).zip”专注于讲解如何实现多线程下载并支持断点续传的功能。下面将详细阐述这个主题。 一、多线程下载原理 多线程下载是将一个大文件分成多个小部分,每个部分由不同的...
本主题聚焦于一个特定的小程序源码实现——多线程断点续传下载及在线播放音乐的功能。这个功能对于提升用户体验至关重要,尤其是在处理大文件下载和流媒体服务时。 首先,我们来深入理解“多线程断点续传下载”。在...
(1)“myDownloader_2.0”文件夹,保存下载器的源码, 其中包含的doc文件夹存放的是有MyEclipse,javadoc生成的关于下载器的API文档; (2)“jar包”文件夹,其中myDownloader2.0.jar可以双击运行下载器 ...
- "Android 文件断点续传源码"是实际的Java代码,可能包括下载管理器类、下载任务类、进度存储类等,用于实现断点续传的核心逻辑。 6. 实际应用: 在实际项目中,Android开发者可以借鉴这个源码,结合自己的需求...
我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现的源代码,原文地址:http://blog.csdn.net/ouyang_peng/article/details/10125409