现在我开始介绍我的多线程断点下载器.. 这是项目的目录 先看看项目运行的截图 从我的项目工程目录来看. 我是采用DAO操作类来对数据库进行增删改查的操作. 然后通过实体类ThreadInfo像DAO操作类传送对象. 我们先来看看数据库帮助类的代码. 从代码中可以看出..我在数据库中定义了 thread_id代表线程的ID url代表下载路径 startPos代表开始位置 endPos代表结束位置 finished代表实时下载的大小 1.数据库帮助类
- package com.hgq.download.data;
-
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
-
- public class MyDatabaseHepler extends SQLiteOpenHelper
- {
-
- public static final String DB_NAME = "download.db";
- public static final int DB_VERSION = 1;
- public static final String TABLE_NAME = "thread_info";
- private static final String CREATE_TABLE = "CREATE TABLE "+ TABLE_NAME
- + " ( "
- + "_id INTEGER PRIMARY KEY,"
- + "thread_id INTEGER,"
- + "url TEXT,"
- + "startPos INTEGER,"
- + "endPos INTEGER,"
- + "finished INTEGER"
- + " ) ";
- private static final String DROP_TABLE =
- "DROP TABLE IF EXISTS " + TABLE_NAME;
-
- public MyDatabaseHepler(Context context)
- {
- super(context, DB_NAME, null, DB_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db)
- {
- db.execSQL(CREATE_TABLE);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
- {
- db.execSQL(DROP_TABLE);
- onCreate(db);
- }
-
- }
-
复制代码
为了操作数据库方便. 我写了一个实体类 2.实体类
- package com.hgq.download.entities;
-
- /**
- * 线程下载记录 实体类
- */
- public class ThreadInfo
- {
- private int thread_id;
- private String url;
- private int startPos;
- private int endPos;
- private int finished;
-
- public ThreadInfo()
- {
- super();
- };
-
- public ThreadInfo(int threadId, String url, int startPos, int endPos,
- int finished)
- {
- super();
- this.thread_id = threadId;
- this.url = url;
- this.startPos = startPos;
- this.endPos = endPos;
- this.finished = finished;
-
- };
-
- 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 int getStartPos()
- {
- return startPos;
- }
-
- public void setStartPos(int startPos)
- {
- this.startPos = startPos;
- }
-
- public int getEndPos()
- {
- return endPos;
- }
-
- public void setEndPos(int endPos)
- {
- this.endPos = endPos;
- }
-
- public int getFinished()
- {
- return finished;
- }
-
- public void setFinished(int finished)
- {
- this.finished = finished;
- }
-
- @Override
- public String toString()
- {
- return "ThreadInfo [thread_id=" + thread_id + ", url=" + url
- + ", startPos=" + startPos + ", endPos=" + endPos
- + ", finished=" + finished + "]";
- }
-
- }
-
复制代码
3.DAO操作类
- package com.hgq.download.data;
-
- import java.util.ArrayList;
- import java.util.List;
-
- import android.content.ContentValues;
- import android.content.Context;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.util.Log;
-
- import com.hgq.download.entities.ThreadInfo;
-
- /**
- * 操作类
- */
- public class ThreadDAO
- {
- private MyDatabaseHepler dbHeple;
- private SQLiteDatabase db;
-
- public ThreadDAO(Context context)
- {
- dbHeple = new MyDatabaseHepler(context);
- db = dbHeple.getWritableDatabase();
- }
-
- // 插入
- public void insert(ThreadInfo info)
- {
- System.out.println(info);
- System.out.println("thread_id" + info.getThread_id());
-
- ContentValues values = new ContentValues();
- values.put("thread_id", info.getThread_id());
- values.put("url", info.getUrl());
- values.put("startPos", info.getStartPos());
- values.put("endPos", info.getEndPos());
- values.put("finished", info.getFinished());
-
- db.insert(MyDatabaseHepler.TABLE_NAME, null, values);
- }
-
- // 更新
- public void update(int len,String url,int id){
- db.execSQL(
- "UPDATE thread_info SET finished = finished+? WHERE url=? AND thread_id=?",
- new Object[]{len,url,id});
- }
-
- // 删除
- public void delete(String url)
- {
- Log.i("ThreadDao", url);
- db.delete(MyDatabaseHepler.TABLE_NAME, "url=?", new String[]
- { url });
- }
-
- // 查询
- public List<ThreadInfo> getThreadInfos(String url)
- {
- List<ThreadInfo> list = new ArrayList<ThreadInfo>();
- Cursor cursor = db.query(MyDatabaseHepler.TABLE_NAME, null, "url=?",
- new String[]
- { url }, null, null, null);
-
- while (cursor.moveToNext())
- {
- ThreadInfo info = new ThreadInfo();
- info.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
- info.setUrl(cursor.getString(cursor.getColumnIndex("url")));
- info.setStartPos(cursor.getInt(cursor.getColumnIndex("startPos")));
- info.setEndPos(cursor.getInt(cursor.getColumnIndex("endPos")));
- info.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
- list.add(info);
- }
- cursor.close();
- return list;
- }
- }
-
复制代码
构建下载器是整个项目的最核心部分. 4.下载器类
- package com.hgq.download.http;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.RandomAccessFile;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.List;
-
- import android.content.Context;
- import android.os.Handler;
- import android.util.Log;
-
- import com.hgq.download.data.ThreadDAO;
- import com.hgq.download.entities.ThreadInfo;
-
- /**
- * 下载器
- *
- * @author 洪国强
- *
- */
- public class Downloader
- {
- public static final int INIT = 1;
- public static final int DOWNLOADING = 2;
- public static final int FINISHED = 3;
- public static final int STOP = 4;
-
- // 下载路径
- private String urlPath = null;
- // 保存文件路径
- private String filePath = null;
- // 线程数
- private int threadNum;
- // 保存文件大小
- private int fileSize;
- // 实例化操作类
- private ThreadDAO dao;
- // 下载状态
- public int state;
- // 消息
- public Handler handler = null;
-
- public Downloader(Context context, String urlPath, String filePath,
- int threadNum, Handler handler)
- {
- this.urlPath = urlPath;
- this.filePath = filePath;
- this.threadNum = threadNum;
- this.handler = handler;
- dao = new ThreadDAO(context);
- }
-
- /**
- * 获取网络文件长度,设置本地文件长度
- */
- public void start()
- {
- // 下载进度
- int finished = 0;
- List<ThreadInfo> threads = dao.getThreadInfos(urlPath);
-
- // 第一次下载就初始化文件
- if (threads.size() == 0)
- {
- try
- {
- // 创建URL
- URL url = new URL(urlPath);
- // 创建HttpURLConnection连接
- HttpURLConnection conn = (HttpURLConnection) url
- .openConnection();
- // 设置连接超时
- conn.setConnectTimeout(1000 * 5);
- // 设置连接方式
- conn.setRequestMethod("GET");
- // 获取文件大小
- fileSize = conn.getContentLength();
- Log.i("info", "fileSize----------->" + fileSize);
-
- // 创建本地文件
- File file = new File(filePath);
- Log.i("info", "file----------->" + file);
-
- Log.i("info", "!file.exists()-------->" + !file.exists());
- if (!file.exists())
- file.createNewFile();
-
- RandomAccessFile raf = new RandomAccessFile(file, "rwd");
- Log.i("info", "start() raf" + raf);
-
- // 设置本地文件长度
- raf.setLength(fileSize);
- raf.close();
- conn.disconnect();
-
- /**
- * 计算每个线程开始位置和结束位置
- */
- // 每个线程的长度
- int len = fileSize / threadNum + 1;
- for (int i = 0; i < threadNum; i++)
- {
- int startPos = i * len;
- int endPos = startPos + len;
- if (i == threadNum - 1)
- {
- endPos = fileSize;
- }
-
- Log.i("info", "Downloader.start()---------------->i:" + i
- + ",startPos" + startPos + ",endPos" + endPos);
- // 启动下载线程
- new Thread(new DownloadThread(i, startPos, endPos)).start();
- // 将下载线程加入到数据库中
- ThreadInfo info = new ThreadInfo(i, urlPath, startPos,
- endPos, 0);
- dao.insert(info);
- }
-
- } catch (MalformedURLException e)
- {
- e.printStackTrace();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- } else
- {
- // 启动所有线程
- for (ThreadInfo info : threads)
- {
- fileSize += info.getEndPos() - info.getStartPos();
- finished += info.getFinished();
- new Thread(new DownloadThread(info.getThread_id(),
- info.getStartPos(), info.getEndPos())).start();
- }
- }
- // 发送消息
- handler.obtainMessage(INIT, fileSize, finished).sendToTarget();
- }
-
- /**
- * 下载线程
- */
- public class DownloadThread implements Runnable
- {
- int id;
- int startPos = 0;
- int endPos = 0;
-
- public DownloadThread(int id, int startPos, int endPos)
- {
- this.id = id;
- this.startPos = startPos;
- this.endPos = endPos;
- }
-
- @Override
- public void run()
- {
- RandomAccessFile raf = null;
- InputStream is = null;
- try
- {
- // 获取url
- URL url = new URL(urlPath);
- Log.i("info", "url------------->" + url);
-
- HttpURLConnection conn = (HttpURLConnection) url
- .openConnection();
- // 设置超时
- conn.setConnectTimeout(1000 * 5);
- // 设置连接类型
- conn.setRequestMethod("GET");
- // 设置下载范围
- conn.setRequestProperty("Range", "btyes=" + startPos + "-"
- + endPos);
- raf = new RandomAccessFile(new File(filePath), "rwd");
- Log.i("info", "raf------------->" + raf);
-
- // 设置写入位置
- raf.seek(startPos);
- // 获取输入流
- is = conn.getInputStream();
-
- byte[] buffer = new byte[1024];
- int len;
- while ((len = is.read(buffer)) != -1)
- {
- raf.write(buffer, 0, len);
- // 更新下载进度条到数据库
- dao.update(len, urlPath, id);
- // 发送消息
- handler.obtainMessage(DOWNLOADING, len, 0).sendToTarget();
- if (state == STOP)
- {
- break;
- }
- }
-
- } catch (MalformedURLException e)
- {
- e.printStackTrace();
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- }
-
- }
-
复制代码
5.Activity类
- package com.hgq.download;
-
- import java.io.File;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Environment;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.ArrayAdapter;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ProgressBar;
- import android.widget.Spinner;
- import android.widget.TextView;
- import android.widget.Toast;
-
- import com.hgq.download.data.ThreadDAO;
- import com.hgq.download.http.Downloader;
-
- public class MainActivity extends Activity implements OnClickListener
- {
- private static final String SD_PATH = Environment
- .getExternalStorageDirectory().getAbsolutePath() + File.separator;
-
- private Button butDown = null;
- private Button butPause = null;
- private EditText editPath = null;
- private EditText editName = null;
- private Spinner spinner = null;
- private ProgressBar bar = null;
- private TextView tvResult = null;
-
- String[] arr = new String[]
- { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
-
- private Downloader mDownloader = null;
- private ThreadDAO mDao = null;
- // 线程数
- int threadNum = 0;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- // 实例化操作类
- mDao = new ThreadDAO(getApplicationContext());
-
- butDown = (Button) findViewById(R.id.butDown);
- butPause = (Button) findViewById(R.id.butPause);
- editPath = (EditText) findViewById(R.id.editPath);
- editName = (EditText) findViewById(R.id.editName);
- spinner = (Spinner) findViewById(R.id.spinner);
- bar = (ProgressBar) findViewById(R.id.bar);
- tvResult = (TextView) findViewById(R.id.tvResult);
-
- // 获取保存文件名
- String path = editPath.getText().toString();
- String name = path.substring(path.lastIndexOf("/") + 1);
- editName.setText(name);
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_spinner_item, arr);
- // 设置下拉列表显示风格
- adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- spinner.setAdapter(adapter);
-
- butDown.setOnClickListener(this);
- butPause.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v)
- {
- switch (v.getId())
- {
- case R.id.butDown:
- Log.i("info", "单击下载按钮");
-
- threadNum = spinner.getSelectedItemPosition() + 1;
- Log.i("info", "threadNum------------->" + threadNum);
-
- // 创建下载器,开始下载
- if (mDownloader == null)
- {
- mDownloader = new Downloader(this, editPath.getText()
- .toString(), SD_PATH + editName.getText().toString(),
- threadNum, mHandler);
- }
- // 将状态设置成开始状态
- mDownloader.state = Downloader.DOWNLOADING;
- mDownloader.start();
-
- break;
- case R.id.butPause:
- if (mDownloader != null)
- {
- mDownloader.state = Downloader.STOP;
- }
- break;
- default:
- break;
- }
- }
-
- @Override
- protected void onDestroy()
- {
- super.onDestroy();
- mDownloader.state = Downloader.STOP;
- }
-
- // 线程消息处理
- public Handler mHandler = new Handler()
- {
- public void handleMessage(Message msg)
- {
- switch (msg.what)
- {
- case Downloader.INIT:
- bar.setMax(msg.arg1);
- bar.setProgress(msg.arg2);
- bar.setVisibility(View.VISIBLE);
- tvResult.setVisibility(View.VISIBLE);
- break;
- case Downloader.DOWNLOADING:
- bar.incrementProgressBy(msg.arg1);
- float result1 = (float) bar.getProgress()
- / (float) bar.getMax();
- int p = (int) (result1 * 100);
- tvResult.setText(p + "%");
-
- if (bar.getProgress() >= bar.getMax())
- {
- Toast.makeText(MainActivity.this, "文件下载完成", 1).show();
- bar.setProgress(0);
- bar.setVisibility(View.GONE);
- tvResult.setVisibility(View.GONE);
- mDownloader = null;
- // 删除文件记录
- mDao.delete(editPath.getText().toString());
- }
- break;
- }
- };
- };
- }
-
复制代码
在做这个项目之前.我看了传智播客的多线程断点下载器的教程.. |
|