多线程断点续传GreenDao版

时间:2021-05-17 18:33:21

本文参考:

http://blog.csdn.net/inter_native/article/details/78603256

首先要引入GreenDao,具体引用请参考本人的前面的博客,这里就不再写了;

废话完就要开始写了

首先要写一个User类:

@Entity
public
class User { @Id
private Long id;
private Integer thread_id;
private Integer start_pos;
private Integer end_pos;
private Integer compelete_size;
private String url;
}

到这一步之后不要急不要慌,深呼吸然后运行一下子,看这个类和你的gen包都好了没,方方面面好了之后就开始粘贴下面的代码;

然后就先粘贴布局(这是本人多年粘贴代码的经验,先粘贴布局)

这个布局就非常简单了,在MainActivity的布局中粘贴

 
<TextView
android:id
="@+id/textView"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_alignParentLeft
="true"
android:layout_alignParentStart
="true"
android:layout_alignParentTop
="true"
android:layout_marginLeft
="23dp"
android:layout_marginStart
="23dp"
android:layout_marginTop
="18dp"
android:text
="TextView" />

<ProgressBar
android:id
="@+id/progressBar"
style
="?android:attr/progressBarStyleHorizontal"
android:layout_width
="fill_parent"
android:layout_height
="7.5dp"
android:layout_below
="@+id/textView"
android:layout_marginRight
="8dp"
android:max
="100"
android:progress
="100"
android:visibility
="visible" />

<Button
android:id
="@+id/start"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_alignParentBottom
="true"
android:layout_toEndOf
="@+id/textView"
android:layout_toRightOf
="@+id/textView"
android:text
="下载" />


<Button
android:id
="@+id/delete"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:layout_alignParentBottom
="true"
android:layout_marginLeft
="48dp"
android:layout_marginStart
="48dp"
android:layout_toEndOf
="@+id/start"
android:layout_toRightOf
="@+id/start"
android:text
="暂停" />
 

 

 
App
public class App extends Application {
public static UserDao userDao;

@Override
public void onCreate() {
super.onCreate();
DaoMaster.DevOpenHelper devOpenHelper
= new DaoMaster.DevOpenHelper(this, "lenvess.db", null);
DaoMaster daoMaster
= new DaoMaster(devOpenHelper.getWritableDb());
DaoSession daoSession
= daoMaster.newSession();
userDao
= daoSession.getUserDao();
}
}
DownlaodSqlTool
public class DownlaodSqlTool {
/**
* 创建下载的具体信息
*/
public void insertInfos(List<DownloadInfo> infos) {
for (DownloadInfo info : infos) {
User user
= new User(null, info.getThreadId(), info.getStartPos(), info.getEndPos(), info.getCompeleteSize(), info.getUrl());
userDao.insert(user);
}
}

/**
* 得到下载具体信息
*/
public List<DownloadInfo> getInfos(String urlstr) {
List
<DownloadInfo> list = new ArrayList<DownloadInfo>();
List
<User> list1 = userDao.queryBuilder().where(UserDao.Properties.Url.eq(urlstr)).build().list();
for (User user : list1) {
DownloadInfo infoss
= new DownloadInfo(
user.getThread_id(), user.getStart_pos(), user.getEnd_pos(),
user.getCompelete_size(), user.getUrl());
Log.d(
"main-----", infoss.toString());
list.add(infoss);
}

return list;
}

/**
* 更新数据库中的下载信息
*/
public void updataInfos(int threadId, int compeleteSize, String urlstr) {
User user
= userDao.queryBuilder()
.
where(UserDao.Properties.Thread_id.eq(threadId), UserDao.Properties.Url.eq(urlstr)).build().unique();
user.setCompelete_size(compeleteSize);
userDao.update(user);
}

/**
* 下载完成后删除数据库中的数据
*/
public void delete(String url) {
userDao.deleteAll();
}

}
DownloadHttpTool

public class DownloadHttpTool {
/**
* 利用Http协议进行多线程下载具体实践类
*/

private static final String TAG = DownloadHttpTool.class.getSimpleName();
private int threadCount;//线程数量
private String urlstr;//URL地址
private Context mContext;
private Handler mHandler;
private List<DownloadInfo> downloadInfos;//保存下载信息的类

private String localPath;//目录
private String fileName;//文件名
private int fileSize;
private DownlaodSqlTool sqlTool;//文件信息保存的数据库操作类

private enum Download_State {
Downloading, Pause, Ready;
//利用枚举表示下载的三种状态
}

private Download_State state = Download_State.Ready;//当前下载状态

private int globalCompelete = 0;//所有线程下载的总数

public DownloadHttpTool(int threadCount, String urlString,
String localPath, String fileName, Context context, Handler handler) {
super();
this.threadCount = threadCount;
this.urlstr = urlString;
this.localPath = localPath;
this.mContext = context;
this.mHandler = handler;
this.fileName = fileName;
sqlTool
= new DownlaodSqlTool();
}

//在开始下载之前需要调用ready方法进行配置
public void ready() {
Log.w(TAG,
"ready");
globalCompelete
= 0;
downloadInfos
= sqlTool.getInfos(urlstr);
if (downloadInfos.size() == 0) {
initFirst();
}
else {
File file
= new File(localPath + "/" + fileName);
if (!file.exists()) {
sqlTool.delete(urlstr);
initFirst();
}
else {
fileSize
= downloadInfos.get(downloadInfos.size() - 1)
.getEndPos();
for (DownloadInfo info : downloadInfos) {
globalCompelete
+= info.getCompeleteSize();
}
Log.w(TAG,
"globalCompelete:::" + globalCompelete);
}
}
}

public void start() {
Log.w(TAG,
"start");
if (downloadInfos != null) {
if (state == Download_State.Downloading) {
return;
}
state
= Download_State.Downloading;
for (DownloadInfo info : downloadInfos) {
Log.v(TAG,
"startThread");
new DownloadThread(info.getThreadId(), info.getStartPos(),
info.getEndPos(), info.getCompeleteSize(),
info.getUrl()).start();
}
}
}

public void pause() {
state
= Download_State.Pause;
}

public void delete() {
compelete();
File file
= new File(localPath + "/" + fileName);
file.delete();
}

public void compelete() {
sqlTool.delete(urlstr);
}

public int getFileSize() {
return fileSize;
}

public int getCompeleteSize() {
return globalCompelete;
}

//第一次下载初始化
private void initFirst() {
Log.w(TAG,
"initFirst");
try {
URL url
= new URL(urlstr);
HttpURLConnection connection
= (HttpURLConnection) url
.openConnection();
connection.setConnectTimeout(
5000);
connection.setRequestMethod(
"GET");
fileSize
= connection.getContentLength();
Log.w(TAG,
"fileSize::" + fileSize);
File fileParent
= new File(localPath);
if (!fileParent.exists()) {
fileParent.mkdir();
}
File file
= new File(fileParent, fileName);
if (!file.exists()) {
file.createNewFile();
}
// 本地访问文件
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
accessFile.setLength(fileSize);
accessFile.close();
connection.disconnect();
}
catch (Exception e) {
e.printStackTrace();
}
int range = fileSize / threadCount;
downloadInfos
= new ArrayList<DownloadInfo>();
for (int i = 0; i < threadCount - 1; i++) {
DownloadInfo info
= new DownloadInfo(i, i * range, (i + 1) * range
- 1, 0, urlstr);
downloadInfos.add(info);
}
DownloadInfo info
= new DownloadInfo(threadCount - 1, (threadCount - 1)
* range, fileSize - 1, 0, urlstr);
downloadInfos.add(info);
sqlTool.insertInfos(downloadInfos);
}

//自定义下载线程
private class DownloadThread extends Thread {

private int threadId;
private int startPos;
private int endPos;
private int compeleteSize;
private String urlstr;
private int totalThreadSize;

public DownloadThread(int threadId, int startPos, int endPos,
int compeleteSize, String urlstr) {
this.threadId = threadId;
this.startPos = startPos;
this.endPos = endPos;
totalThreadSize
= endPos - startPos + 1;
this.urlstr = urlstr;
this.compeleteSize = compeleteSize;
}

@Override
public void run() {
HttpURLConnection connection
= null;
RandomAccessFile randomAccessFile
= null;
InputStream
is = null;
try {
randomAccessFile
= new RandomAccessFile(localPath + "/"
+ fileName, "rwd");
randomAccessFile.seek(startPos
+ compeleteSize);
URL url
= new URL(urlstr);
connection
= (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(
5000);
connection.setRequestMethod(
"GET");
connection.setRequestProperty(
"Range", "bytes="
+ (startPos + compeleteSize) + "-" + endPos);
is = connection.getInputStream();
byte[] buffer = new byte[1024];
int length = -1;
while ((length = is.read(buffer)) != -1) {
randomAccessFile.write(buffer,
0, length);
compeleteSize
+= length;
Message message
= Message.obtain();
message.what
= threadId;
message.obj
= urlstr;
message.arg1
= length;
mHandler.sendMessage(message);
sqlTool.updataInfos(threadId, compeleteSize, urlstr);
Log.w(TAG,
"Threadid::" + threadId + " compelete::"
+ compeleteSize + " total::" + totalThreadSize);
if (compeleteSize >= totalThreadSize) {
break;
}
if (state != Download_State.Downloading) {
break;
}
}

}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (is != null) {
is.close();
}
randomAccessFile.close();
connection.disconnect();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
DownloadInfo
public class DownloadInfo {
/**
* 保存每个下载线程下载信息类
*
*/

private int threadId;// 下载器id
private int startPos;// 开始点
private int endPos;// 结束点
private int compeleteSize;// 完成度
private String url;// 下载文件的URL地址

public DownloadInfo(int threadId, int startPos, int endPos,
int compeleteSize, String url) {
this.threadId = threadId;
this.startPos = startPos;
this.endPos = endPos;
this.compeleteSize = compeleteSize;
this.url = url;
}

public DownloadInfo() {
}

public String getUrl() {
return url;
}

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

public int getThreadId() {
return threadId;
}

public void setThreadId(int threadId) {
this.threadId = threadId;
}

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 getCompeleteSize() {
return compeleteSize;
}

public void setCompeleteSize(int compeleteSize) {
this.compeleteSize = compeleteSize;
}

@Override
public String toString() {
return "DownloadInfo [threadId=" + threadId + ", startPos=" + startPos
+ ", endPos=" + endPos + ", compeleteSize=" + compeleteSize
+ "]";
}

}
DownloadUtil

public class DownloadUtil {
private DownloadHttpTool mDownloadHttpTool;
private OnDownloadListener onDownloadListener;

private int fileSize;
private int downloadedSize = 0;

@SuppressLint(
"HandlerLeak")
private Handler mHandler = new Handler() {

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
int length = msg.arg1;
synchronized (
this) {//加锁保证已下载的正确性
downloadedSize += length;
}
if (onDownloadListener != null) {
onDownloadListener.downloadProgress(downloadedSize);
}
if (downloadedSize >= fileSize) {
mDownloadHttpTool.compelete();
if (onDownloadListener != null) {
onDownloadListener.downloadEnd();
}
}
}

};

public DownloadUtil(int threadCount, String filePath, String filename,
String urlString, Context context) {

mDownloadHttpTool
= new DownloadHttpTool(threadCount, urlString,
filePath, filename, context, mHandler);
}

//下载之前首先异步线程调用ready方法获得文件大小信息,之后调用开始方法
public void start() {
new AsyncTask<Void,Void,Void>() {

@Override
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
mDownloadHttpTool.ready();
return null;
}

@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
fileSize
= mDownloadHttpTool.getFileSize();
downloadedSize
= mDownloadHttpTool.getCompeleteSize();
Log.w(
"Tag", "downloadedSize::" + downloadedSize);
if (onDownloadListener != null) {
onDownloadListener.downloadStart(fileSize);
}
mDownloadHttpTool.start();
}
}.execute();
}

public void pause() {
mDownloadHttpTool.pause();
}

public void delete(){
mDownloadHttpTool.delete();
}

public void reset(){
mDownloadHttpTool.delete();
start();
}

public void setOnDownloadListener(OnDownloadListener onDownloadListener) {
this.onDownloadListener = onDownloadListener;
}

//下载回调接口
public interface OnDownloadListener {
public void downloadStart(int fileSize);

public void downloadProgress(int downloadedSize);//记录当前所有线程下总和

public void downloadEnd();
}

}
MainActivity(!!注意,注意这是MainActivity不是自己创的类,不要粘贴错了)
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private ProgressBar mProgressBar;
private Button start;
private Button pause;


private TextView total;
private int max;
private DownloadUtil mDownloadUtil;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
total
= (TextView) findViewById(R.id.textView);
start
= (Button) findViewById(R.id.start);
pause
= (Button) findViewById(R.id.delete);
mProgressBar
= (ProgressBar) findViewById(R.id.progressBar);
String urlString
= "http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4";
String localPath
= Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ "/local2";
mDownloadUtil
= new DownloadUtil(2, localPath, "adc.mp4", urlString,
this);
mDownloadUtil.setOnDownloadListener(
new DownloadUtil.OnDownloadListener() {

@Override
public void downloadStart(int fileSize) {
// TODO Auto-generated method stub
Log.w(TAG, "fileSize::" + fileSize);
max
= fileSize;
mProgressBar.setMax(fileSize);
}

@Override
public void downloadProgress(int downloadedSize) {
// TODO Auto-generated method stub
Log.w(TAG, "Compelete::" + downloadedSize);
mProgressBar.setProgress(downloadedSize);
total.setText((
int) downloadedSize * 100 / max + "%");
}

@Override
public void downloadEnd() {
// TODO Auto-generated method stub
Log.w(TAG, "ENd");
}
});
start.setOnClickListener(
new View.OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
mDownloadUtil.start();
}
});
pause.setOnClickListener(
new View.OnClickListener() {

@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
mDownloadUtil.pause();
}
});


}
}

这样代码方面就完事了;如果有报错一般是Handler的事这个千万记的倒OS那个包

然后就是权限:

 

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

 如果运行了还报错,可能是你的App没有配,不要慌,仔细检查