例子编写

pull/2/head
lyy 9 years ago
parent 3496022c60
commit 2ad2f31594
  1. 2
      .idea/misc.xml
  2. 6
      app/src/androidTest/java/com/example/arial/downloaddemo/ApplicationTest.java
  3. 40
      app/src/main/AndroidManifest.xml
  4. 12
      app/src/main/java/com/arialyy/simple/activity/MainActivity.java
  5. 95
      app/src/main/java/com/arialyy/simple/activity/SimpleTestActivity.java
  6. 87
      app/src/main/java/com/arialyy/simple/module/DownloadModule.java
  7. 51
      app/src/main/java/com/arialyy/simple/widget/HorizontalProgressBarWithNumber.java
  8. 20
      app/src/main/res/layout/activity_main.xml
  9. 68
      app/src/main/res/layout/activity_simple.xml
  10. 122
      app/src/main/res/layout/content_simple.xml
  11. 40
      app/src/main/res/layout/item_download.xml
  12. 16
      app/src/main/res/menu/menu_main.xml
  13. 12
      app/src/main/res/values-v21/styles.xml
  14. 8
      app/src/main/res/values-w820dp/dimens.xml
  15. 26
      app/src/main/res/values/attr.xml
  16. 6
      app/src/main/res/values/colors.xml
  17. 8
      app/src/main/res/values/dimens.xml
  18. 18
      app/src/main/res/values/strings.xml
  19. 26
      app/src/main/res/values/styles.xml
  20. 6
      app/src/test/java/com/example/arial/downloaddemo/ExampleUnitTest.java
  21. 6
      downloadutil/src/androidTest/java/com/arialyy/downloadutil/ApplicationTest.java
  22. 12
      downloadutil/src/main/AndroidManifest.xml
  23. 193
      downloadutil/src/main/java/com/arialyy/downloadutil/core/DownloadManager.java
  24. 151
      downloadutil/src/main/java/com/arialyy/downloadutil/core/DownloadTarget.java
  25. 337
      downloadutil/src/main/java/com/arialyy/downloadutil/core/IDownloadTarget.java
  26. 339
      downloadutil/src/main/java/com/arialyy/downloadutil/core/Task.java
  27. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/core/TaskEnum.java
  28. 49
      downloadutil/src/main/java/com/arialyy/downloadutil/core/TaskFactory.java
  29. 13
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/AddCommand.java
  30. 13
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/CancelCommand.java
  31. 185
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/CommandFactory.java
  32. 59
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/IDownloadCommand.java
  33. 13
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StartCommand.java
  34. 21
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StateCommand.java
  35. 21
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StopCommand.java
  36. 48
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IDownloader.java
  37. 74
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java
  38. 66
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/ITask.java
  39. 159
      downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java
  40. 233
      downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/ExecutePool.java
  41. 353
      downloadutil/src/main/java/com/arialyy/downloadutil/entity/DownloadEntity.java
  42. 66
      downloadutil/src/main/java/com/arialyy/downloadutil/help/CheckHelp.java
  43. 63
      downloadutil/src/main/java/com/arialyy/downloadutil/help/PathHelp.java
  44. 329
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/DbEntity.java
  45. 567
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/DbUtil.java
  46. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/Id.java
  47. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/Ignore.java
  48. 34
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/SqlHelper.java
  49. 809
      downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java
  50. 98
      downloadutil/src/main/java/com/arialyy/downloadutil/util/IDownloadListener.java
  51. 383
      downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java
  52. 10
      downloadutil/src/main/res/values/strings.xml
  53. 6
      downloadutil/src/test/java/com/arialyy/downloadutil/ExampleUnitTest.java

@ -37,7 +37,7 @@
<ConfirmationsSetting value="0" id="Add" /> <ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" /> <ConfirmationsSetting value="0" id="Remove" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

@ -7,7 +7,7 @@ import android.test.ApplicationTestCase;
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/ */
public class ApplicationTest extends ApplicationTestCase<Application> { public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() { public ApplicationTest() {
super(Application.class); super(Application.class);
} }
} }

@ -1,28 +1,28 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arialyy.simple"> package="com.arialyy.simple">
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application <application
android:name=".base.BaseApplication" android:name=".base.BaseApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activity.SimpleTestActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar"> android:supportsRtl="true"
<intent-filter> android:theme="@style/AppTheme">
<action android:name="android.intent.action.MAIN"/> <activity
android:name=".activity.SimpleTestActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>

@ -1,10 +1,14 @@
package com.arialyy.simple.activity; package com.arialyy.simple.activity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.adapter.DownloadAdapter;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMainBinding; import com.arialyy.simple.databinding.ActivityMainBinding;
import com.arialyy.simple.module.DownloadModule;
import butterknife.Bind; import butterknife.Bind;
@ -13,10 +17,16 @@ import butterknife.Bind;
*/ */
public class MainActivity extends BaseActivity<ActivityMainBinding> { public class MainActivity extends BaseActivity<ActivityMainBinding> {
@Bind(R.id.list) RecyclerView mList; @Bind(R.id.list) RecyclerView mList;
DownloadAdapter mAdapter;
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_main; return R.layout.activity_main;
} }
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
mAdapter = new DownloadAdapter(this, getModule(DownloadModule.class).getDownloadData());
mList.setLayoutManager(new LinearLayoutManager(this));
mList.setAdapter(mAdapter);
}
} }

@ -1,5 +1,8 @@
package com.arialyy.simple.activity; package com.arialyy.simple.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
@ -11,13 +14,19 @@ import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.command.CommandFactory;
import com.arialyy.downloadutil.core.command.IDownloadCommand;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.DownLoadUtil; import com.arialyy.downloadutil.util.DownLoadUtil;
import com.arialyy.downloadutil.util.Util; import com.arialyy.downloadutil.util.Util;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivitySimpleBinding; import com.arialyy.simple.databinding.ActivitySimpleBinding;
import com.arialyy.simple.module.DownloadModule;
import java.net.HttpURLConnection; import java.util.ArrayList;
import java.util.List;
import butterknife.Bind; import butterknife.Bind;
@ -58,7 +67,9 @@ public class SimpleTestActivity extends BaseActivity<ActivitySimpleBinding> {
mStart.setText("开始"); mStart.setText("开始");
break; break;
case DOWNLOAD_RESUME: case DOWNLOAD_RESUME:
Toast.makeText(SimpleTestActivity.this, "恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj), Toast.LENGTH_SHORT).show(); Toast.makeText(SimpleTestActivity.this,
"恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj),
Toast.LENGTH_SHORT).show();
mStart.setEnabled(false); mStart.setEnabled(false);
break; break;
case DOWNLOAD_COMPLETE: case DOWNLOAD_COMPLETE:
@ -71,12 +82,27 @@ public class SimpleTestActivity extends BaseActivity<ActivitySimpleBinding> {
} }
}; };
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
}
};
@Override protected void onCreate(Bundle savedInstanceState) { @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
init(); init();
} }
@Override protected void onResume() {
super.onResume();
registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter());
}
@Override protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
@Override protected int setLayoutId() { @Override protected int setLayoutId() {
return R.layout.activity_simple; return R.layout.activity_simple;
} }
@ -111,58 +137,19 @@ public class SimpleTestActivity extends BaseActivity<ActivitySimpleBinding> {
} }
private void start() { private void start() {
mUtil.download(this, mDownloadUrl, Environment.getExternalStorageDirectory().getPath() + "/test.apk", new DownLoadUtil.DownloadListener() { DownloadEntity entity = new DownloadEntity();
long fileSize = 1; entity.setFileName("test.apk");
entity.setDownloadUrl(mDownloadUrl);
@Override public void onPreDownload(HttpURLConnection connection) { entity.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk");
super.onPreDownload(connection); List<IDownloadCommand> commands = new ArrayList<>();
mPb.setMax(100); IDownloadCommand addCommand = CommandFactory.getInstance()
fileSize = connection.getContentLength(); .createCommand(this, entity, CommandFactory.TASK_CREATE);
mUpdateHandler.obtainMessage(DOWNLOAD_PRE, fileSize).sendToTarget(); IDownloadCommand startCommand = CommandFactory.getInstance()
} .createCommand(this, entity, CommandFactory.TASK_START);
commands.add(addCommand);
@Override public void onStart(long startLocation) { commands.add(startCommand);
super.onStart(startLocation); DownloadManager.getInstance(this).setCommands(commands).exe();
}
@Override public void onChildResume(long resumeLocation) {
super.onChildResume(resumeLocation);
}
@Override public void onChildComplete(long finishLocation) {
super.onChildComplete(finishLocation);
}
@Override public void onProgress(long currentLocation) {
super.onProgress(currentLocation);
mPb.setProgress((int) (currentLocation * 100 / fileSize));
}
@Override public void onStop(long stopLocation) {
super.onStop(stopLocation);
mUpdateHandler.obtainMessage(DOWNLOAD_STOP).sendToTarget();
}
@Override public void onCancel() {
super.onCancel();
mUpdateHandler.obtainMessage(DOWNLOAD_CANCEL).sendToTarget();
}
@Override public void onResume(long resumeLocation) {
super.onResume(resumeLocation);
mUpdateHandler.obtainMessage(DOWNLOAD_RESUME, resumeLocation).sendToTarget();
}
@Override public void onFail() {
super.onFail();
mUpdateHandler.obtainMessage(DOWNLOAD_FAILE).sendToTarget();
}
@Override public void onComplete() {
super.onComplete();
mUpdateHandler.obtainMessage(DOWNLOAD_COMPLETE).sendToTarget();
}
});
} }
private void stop() { private void stop() {

@ -1,21 +1,66 @@
//package com.arialyy.simple.module; package com.arialyy.simple.module;
//
//import android.content.Context; import android.content.Context;
//import com.arialyy.downloadutil.entity.DownloadEntity; import android.content.IntentFilter;
//import com.arialyy.simple.base.BaseModule; import android.os.Environment;
//import java.util.ArrayList;
//import java.util.List; import com.arialyy.downloadutil.core.DownloadManager;
// import com.arialyy.downloadutil.entity.DownloadEntity;
///** import com.arialyy.frame.util.AndroidUtils;
// * Created by Lyy on 2016/9/27. import com.arialyy.frame.util.StringUtil;
// */ import com.arialyy.simple.R;
//public class DownloadModule extends BaseModule{ import com.arialyy.simple.base.BaseModule;
// public DownloadModule(Context context) {
// super(context); import java.util.ArrayList;
// } import java.util.List;
//
// public List<DownloadEntity> getDownloadData(){ /**
// List<DownloadEntity> list = new ArrayList<>(); * Created by Lyy on 2016/9/27.
// DownloadEntity entity */
// } public class DownloadModule extends BaseModule {
//} public DownloadModule(Context context) {
super(context);
}
/**
* 设置下载数据
* @return
*/
public List<DownloadEntity> getDownloadData() {
List<DownloadEntity> list = new ArrayList<>();
String[] urls = getContext().getResources()
.getStringArray(R.array.test_apk_download_url);
for (String url : urls) {
String fileName = StringUtil.keyToHashKey(url) + ".apk";
DownloadEntity entity = new DownloadEntity();
entity.setDownloadUrl(url);
entity.setDownloadPath(getDownloadPath(url));
entity.setFileName(fileName);
list.add(entity);
}
return list;
}
/**
* 下载广播过滤器
* @return
*/
public IntentFilter getDownloadFilter(){
IntentFilter filter = new IntentFilter();
filter.addCategory(getContext().getPackageName());
filter.addAction(DownloadManager.ACTION_PRE);
filter.addAction(DownloadManager.ACTION_RESUME);
filter.addAction(DownloadManager.ACTION_START);
filter.addAction(DownloadManager.ACTION_RUNNING);
filter.addAction(DownloadManager.ACTION_STOP);
filter.addAction(DownloadManager.ACTION_CANCEL);
filter.addAction(DownloadManager.ACTION_COMPLETE);
filter.addAction(DownloadManager.ACTION_FAIL);
return filter;
}
private String getDownloadPath(String url) {
return Environment.getExternalStorageDirectory().getPath() + "/" + AndroidUtils.getAppName(
getContext()) + "downloads/" + StringUtil.keyToHashKey(url) + ".apk";
}
}

@ -32,11 +32,13 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
/** /**
* offset of draw progress * offset of draw progress
*/ */
protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET); protected int mTextOffset = dp2px(
DEFAULT_SIZE_TEXT_OFFSET);
/** /**
* height of reached progress bar * height of reached progress bar
*/ */
protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR); protected int mReachedProgressBarHeight = dp2px(
DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/** /**
* color of reached bar * color of reached bar
*/ */
@ -48,7 +50,8 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
/** /**
* height of unreached progress bar * height of unreached progress bar
*/ */
protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR); protected int mUnReachedProgressBarHeight = dp2px(
DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/** /**
* view width except padding * view width except padding
*/ */
@ -82,7 +85,10 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
result = specSize; result = specSize;
} else { } else {
float textHeight = (mPaint.descent() - mPaint.ascent()); float textHeight = (mPaint.descent() - mPaint.ascent());
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight), Math.abs(textHeight))); result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight),
Math.abs(textHeight))
);
if (specMode == MeasureSpec.AT_MOST) { if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize); result = Math.min(result, specSize);
} }
@ -95,15 +101,28 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
*/ */
private void obtainStyledAttributes(AttributeSet attrs) { private void obtainStyledAttributes(AttributeSet attrs) {
// init values from custom attributes // init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber); final TypedArray attributes = getContext().obtainStyledAttributes(attrs,
mTextColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color, DEFAULT_TEXT_COLOR); R.styleable.HorizontalProgressBarWithNumber);
mTextSize = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_size, mTextSize); mTextColor = attributes.getColor(
mReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color, mTextColor); R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
mUnReachedBarColor = attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color, DEFAULT_COLOR_UNREACHED_COLOR); DEFAULT_TEXT_COLOR);
mReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height, mReachedProgressBarHeight); mTextSize = (int) attributes.getDimension(
mUnReachedProgressBarHeight = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height, mUnReachedProgressBarHeight); R.styleable.HorizontalProgressBarWithNumber_progress_text_size, mTextSize);
mTextOffset = (int) attributes.getDimension(R.styleable.HorizontalProgressBarWithNumber_progress_text_offset, mTextOffset); mReachedBarColor = attributes.getColor(
int textVisible = attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility, VISIBLE); R.styleable.HorizontalProgressBarWithNumber_progress_reached_color, mTextColor);
mUnReachedBarColor = attributes.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mReachedProgressBarHeight);
mUnReachedProgressBarHeight = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset, mTextOffset);
int textVisible = attributes.getInt(
R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility, VISIBLE);
if (textVisible != VISIBLE) { if (textVisible != VISIBLE) {
mIfDrawText = false; mIfDrawText = false;
} }
@ -151,13 +170,15 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
* dp 2 px * dp 2 px
*/ */
protected int dp2px(int dpVal) { protected int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics()); return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
getResources().getDisplayMetrics());
} }
/** /**
* sp 2 px * sp 2 px
*/ */
protected int sp2px(int spVal) { protected int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, getResources().getDisplayMetrics()); return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
getResources().getDisplayMetrics());
} }
} }

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
/> android:orientation="vertical"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout> </LinearLayout>
</layout> </layout>

@ -1,42 +1,42 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <layout xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.design.widget.CoordinatorLayout <android.support.design.widget.CoordinatorLayout
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.arialyy.simple.activity.SimpleTestActivity"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:theme="@style/AppTheme.AppBarOverlay" android:fitsSystemWindows="true"
tools:context="com.arialyy.simple.activity.SimpleTestActivity"
> >
<android.support.v7.widget.Toolbar <android.support.design.widget.AppBarLayout
android:id="@+id/toolbar" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="?attr/actionBarSize" android:theme="@style/AppTheme.AppBarOverlay"
android:background="?attr/colorPrimary" >
app:popupTheme="@style/AppTheme.PopupOverlay"
/> <android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
</android.support.design.widget.AppBarLayout> android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
<include layout="@layout/content_simple"/> android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
<android.support.design.widget.FloatingActionButton />
android:id="@+id/fab"
android:layout_width="wrap_content" </android.support.design.widget.AppBarLayout>
android:layout_height="wrap_content"
android:layout_gravity="bottom|end" <include layout="@layout/content_simple"/>
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" <android.support.design.widget.FloatingActionButton
/> android:id="@+id/fab"
android:layout_width="wrap_content"
</android.support.design.widget.CoordinatorLayout> android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email"
/>
</android.support.design.widget.CoordinatorLayout>
</layout> </layout>

@ -1,72 +1,72 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.arialyy.simple.activity.SimpleTestActivity" tools:context="com.arialyy.simple.activity.SimpleTestActivity"
tools:showIn="@layout/activity_simple" tools:showIn="@layout/activity_simple"
> >
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal" style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_alignParentLeft="true" android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_margin="16dp" android:layout_margin="16dp"
android:layout_toLeftOf="@+id/size" android:layout_toLeftOf="@+id/size"
/>
<TextView
android:id="@+id/size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/progressBar"
android:layout_marginRight="16dp"
android:text="ssss"
android:textSize="16sp"
/>
<LinearLayout
android:layout_below="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:text="开始"
android:id="@+id/start"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
/> />
<Button <TextView
android:onClick="onClick" android:id="@+id/size"
android:text="暂停" android:layout_width="wrap_content"
android:id="@+id/stop"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_alignParentRight="true"
android:layout_alignTop="@+id/progressBar"
android:layout_marginRight="16dp"
android:text="ssss"
android:textSize="16sp"
/> />
<Button <LinearLayout
android:onClick="onClick" android:layout_below="@+id/progressBar"
android:text="取消" android:layout_width="match_parent"
android:id="@+id/cancel"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:orientation="horizontal"
/> >
</LinearLayout>
<Button
android:text="开始"
android:id="@+id/start"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
/>
<Button
android:onClick="onClick"
android:text="暂停"
android:id="@+id/stop"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:onClick="onClick"
android:text="取消"
android:id="@+id/cancel"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

@ -1,27 +1,27 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="16dp" android:padding="16dp"
> >
<com.arialyy.simple.widget.HorizontalProgressBarWithNumber <com.arialyy.simple.widget.HorizontalProgressBarWithNumber
android:id="@+id/progressBar" android:id="@+id/progressBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_toLeftOf="@+id/bt" android:layout_toLeftOf="@+id/bt"
android:max="100" android:max="100"
/> />
<Button <Button
android:id="@+id/bt" android:id="@+id/bt"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:text="开始" android:text="开始"
style="?buttonBarButtonStyle" style="?buttonBarButtonStyle"
/> />
</RelativeLayout> </RelativeLayout>

@ -1,10 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.arial.downloaddemo.com.arialyy.simple.MainActivity"> tools:context="com.example.arial.downloaddemo.com.arialyy.simple.MainActivity">
<item <item
android:id="@+id/action_settings" android:id="@+id/action_settings"
android:title="@string/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" android:orderInCategory="100"
app:showAsAction="never"/> app:showAsAction="never"/>
</menu> </menu>

@ -1,9 +1,9 @@
<resources> <resources>
<style name="AppTheme.NoActionBar"> <style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item> <item name="android:statusBarColor">@android:color/transparent</item>
</style> </style>
</resources> </resources>

@ -1,6 +1,6 @@
<resources> <resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml <!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This (such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen> <dimen name="activity_horizontal_margin">64dp</dimen>
</resources> </resources>

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<declare-styleable name="HorizontalProgressBarWithNumber"> <declare-styleable name="HorizontalProgressBarWithNumber">
<attr name="progress_unreached_color" format="color" /> <attr name="progress_unreached_color" format="color"/>
<attr name="progress_reached_color" format="color" /> <attr name="progress_reached_color" format="color"/>
<attr name="progress_reached_bar_height" format="dimension" /> <attr name="progress_reached_bar_height" format="dimension"/>
<attr name="progress_unreached_bar_height" format="dimension" /> <attr name="progress_unreached_bar_height" format="dimension"/>
<attr name="progress_text_size" format="dimension" /> <attr name="progress_text_size" format="dimension"/>
<attr name="progress_text_color" format="color" /> <attr name="progress_text_color" format="color"/>
<attr name="progress_text_offset" format="dimension" /> <attr name="progress_text_offset" format="dimension"/>
<attr name="progress_text_visibility" format="enum"> <attr name="progress_text_visibility" format="enum">
<enum name="visible" value="0" /> <enum name="visible" value="0"/>
<enum name="invisible" value="1" /> <enum name="invisible" value="1"/>
</attr> </attr>
</declare-styleable> </declare-styleable>
</resources> </resources>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#3F51B5</color> <color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color> <color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color> <color name="colorAccent">#FF4081</color>
</resources> </resources>

@ -1,6 +1,6 @@
<resources> <resources>
<!-- Default screen margins, per the Android Design guidelines. --> <!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="fab_margin">16dp</dimen> <dimen name="fab_margin">16dp</dimen>
</resources> </resources>

@ -1,4 +1,18 @@
<resources> <resources>
<string name="app_name">DownloadDemo</string> <string name="app_name">DownloadDemo</string>
<string name="action_settings">Settings</string> <string name="action_settings">Settings</string>
<string-array name="test_apk_download_url">
<item>http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk</item> <!--300M的文件-->
<item>http://static.gaoshouyou.com/d/21/e8/61218d78d0e8b79df68dbc18dd484c97.apk</item>
<item>http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk</item>
<item>http://static.gaoshouyou.com/d/d4/4f/d6d48db3794fb9ecf47e83c346570881.apk</item>
<!--<item>http://static.gaoshouyou.com/d/18/cf/ba18113bc6cf56c1c5863e761e717003.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/60/17/2460921367173ea7145f11194a6f2587.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/32/e0/1a32123ecbe0ee010d35479df248f90f.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/e6/f5/4de6329f9cf5dc3a1d1e6bbcca0d003c.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/6e/e5/ff6ecaaf45e532e6d07747af82357472.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk</item>-->
</string-array>
</resources> </resources>

@ -1,20 +1,20 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
</style> </style>
<style name="AppTheme.NoActionBar"> <style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item> <item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item> <item name="windowNoTitle">true</item>
</style> </style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/> <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/> <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
</resources> </resources>

@ -8,7 +8,7 @@ import static org.junit.Assert.assertEquals;
* To work on unit tests, switch the Test Artifact in the Build Variants view. * To work on unit tests, switch the Test Artifact in the Build Variants view.
*/ */
public class ExampleUnitTest { public class ExampleUnitTest {
@Test public void addition_isCorrect() throws Exception { @Test public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2); assertEquals(4, 2 + 2);
} }
} }

@ -7,7 +7,7 @@ import android.test.ApplicationTestCase;
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/ */
public class ApplicationTest extends ApplicationTestCase<Application> { public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() { public ApplicationTest() {
super(Application.class); super(Application.class);
} }
} }

@ -1,11 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.arialyy.downloadutil"> package="com.arialyy.downloadutil">
<application <application
android:allowBackup="true" android:allowBackup="true"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true"> android:supportsRtl="true">
</application> </application>
</manifest> </manifest>

@ -1,7 +1,9 @@
package com.arialyy.downloadutil.core; package com.arialyy.downloadutil.core;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.core.command.IDownloadCommand; import com.arialyy.downloadutil.core.command.IDownloadCommand;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -10,102 +12,103 @@ import java.util.List;
* 下载管理器通过命令的方式控制下载 * 下载管理器通过命令的方式控制下载
*/ */
public class DownloadManager { public class DownloadManager {
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private static volatile DownloadManager INSTANCE = null; private static volatile DownloadManager INSTANCE = null;
/** /**
* 下载开始前事件 * 下载开始前事件
*/ */
public static final String ACTION_PRE = "ACTION_PRE"; public static final String ACTION_PRE = "ACTION_PRE";
/** /**
* 开始下载事件 * 开始下载事件
*/ */
public static final String ACTION_START = "ACTION_START"; public static final String ACTION_START = "ACTION_START";
/** /**
* 恢复下载事件 * 恢复下载事件
*/ */
public static final String ACTION_RESUME = "ACTION_RESUME"; public static final String ACTION_RESUME = "ACTION_RESUME";
/** /**
* 正在下载事件 * 正在下载事件
*/ */
public static final String ACTION_RUNNING = "ACTION_RUNNING"; public static final String ACTION_RUNNING = "ACTION_RUNNING";
/** /**
* 停止下载事件 * 停止下载事件
*/ */
public static final String ACTION_STOP = "ACTION_STOP"; public static final String ACTION_STOP = "ACTION_STOP";
/** /**
* 取消下载事件 * 取消下载事件
*/ */
public static final String ACTION_CANCEL = "ACTION_CANCEL"; public static final String ACTION_CANCEL = "ACTION_CANCEL";
/** /**
* 下载完成事件 * 下载完成事件
*/ */
public static final String ACTION_COMPLETE = "ACTION_COMPLETE"; public static final String ACTION_COMPLETE = "ACTION_COMPLETE";
/** /**
* 下载失败事件 * 下载失败事件
*/ */
public static final String ACTION_FAIL = "ACTION_FAIL"; public static final String ACTION_FAIL = "ACTION_FAIL";
/** /**
* 下载实体 * 下载实体
*/ */
public static final String DATA = "DOWNLOAD_ENTITY"; public static final String DATA = "DOWNLOAD_ENTITY";
/** /**
* 位置 * 位置
*/ */
public static final String CURRENT_LOCATION = "CURRENT_LOCATION"; public static final String CURRENT_LOCATION = "CURRENT_LOCATION";
private List<IDownloadCommand> mCommands = new ArrayList<>(); private List<IDownloadCommand> mCommands = new ArrayList<>();
private DownloadManager() { private DownloadManager() {
} }
private Context mContext; private Context mContext;
private DownloadManager(Context context) { private DownloadManager(Context context) {
mContext = context; mContext = context;
}
public static DownloadManager getInstance(Context context) {
if (INSTANCE == null) {
synchronized (LOCK) {
INSTANCE = new DownloadManager(context.getApplicationContext());
}
} }
return INSTANCE;
} public static DownloadManager getInstance(Context context) {
if (INSTANCE == null) {
/** synchronized (LOCK) {
* 设置命令 INSTANCE = new DownloadManager(context.getApplicationContext());
*/ }
public void setCommant(IDownloadCommand command) { }
mCommands.add(command); return INSTANCE;
} }
/** /**
* 设置一组命令 * 设置命令
*/ */
public void setCommands(List<IDownloadCommand> commands) { public void setCommant(IDownloadCommand command) {
if (commands != null && commands.size() > 0) { mCommands.add(command);
mCommands.addAll(commands);
} }
}
/**
/** * 设置一组命令
* 执行所有设置的命令 */
*/ public DownloadManager setCommands(List<IDownloadCommand> commands) {
public synchronized void exe() { if (commands != null && commands.size() > 0) {
for (IDownloadCommand command : mCommands) { mCommands.addAll(commands);
command.executeComment(); }
return this;
}
/**
* 执行所有设置的命令
*/
public synchronized void exe() {
for (IDownloadCommand command : mCommands) {
command.executeComment();
}
mCommands.clear();
} }
mCommands.clear();
}
} }

@ -2,6 +2,7 @@ package com.arialyy.downloadutil.core;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,96 +10,102 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
* 下载任务调度类 * 下载任务调度类
*/ */
public class DownloadTarget extends IDownloadTarget { public class DownloadTarget extends IDownloadTarget {
private static final String TAG = "DownloadTarget"; private static final String TAG = "DownloadTarget";
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private static volatile DownloadTarget INSTANCE = null; private static volatile DownloadTarget INSTANCE = null;
private Context mContext; private Context mContext;
public static DownloadTarget getInstance(Context context) { public static DownloadTarget getInstance(Context context) {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (LOCK) { synchronized (LOCK) {
INSTANCE = new DownloadTarget(context.getApplicationContext()); INSTANCE = new DownloadTarget(context.getApplicationContext());
} }
}
return INSTANCE;
} }
return INSTANCE;
}
private DownloadTarget() {
super();
}
private DownloadTarget(Context context) { private DownloadTarget() {
super(); super();
mContext = context;
}
@Override public void startTask(Task task) {
if (mExecutePool.putTask(task)) {
task.start();
} }
}
@Override public void stopTask(Task task) { private DownloadTarget(Context context) {
if (mExecutePool.removeTask(task)) { super();
task.stop(); mContext = context;
} }
}
@Override public void cancelTask(Task task) { @Override public void startTask(Task task) {
if (mExecutePool.removeTask(task)) { if (mExecutePool.putTask(task)) {
task.cancel(); task.start();
}
} }
}
@Override public void reTryStart(Task task) { @Override public void stopTask(Task task) {
if (!task.getDownloadUtil().isDownloading()) { if (mExecutePool.removeTask(task)) {
task.start(); task.stop();
} else { }
Log.w(TAG, "任务没有完全停止,重试下载失败");
} }
}
@Override public Task createTask(DownloadEntity entity) { @Override public void cancelTask(Task task) {
Task task = TaskFactory.getInstance().createTask(mContext, entity, mTaskHandler); if (mExecutePool.removeTask(task)) {
mCachePool.putTask(task); task.cancel();
return task; }
} }
@Override public Task getTask(DownloadEntity entity) { @Override public void reTryStart(Task task) {
Task task = mExecutePool.getTask(entity.getDownloadUrl()); if (!task.getDownloadUtil().isDownloading()) {
if (task == null) { task.start();
task = mCachePool.getTask(entity.getDownloadUrl()); } else {
Log.w(TAG, "任务没有完全停止,重试下载失败");
}
} }
if (task == null) {
task = createTask(entity); @Override public Task createTask(DownloadEntity entity) {
Task task = TaskFactory.getInstance().createTask(mContext, entity, mTaskHandler);
mCachePool.putTask(task);
return task;
} }
return task;
}
@Override public int getTaskState(DownloadEntity entity) { @Override public Task getTask(DownloadEntity entity) {
Task task = getTask(entity); Task task = mExecutePool.getTask(entity.getDownloadUrl());
if (task == null) { if (task == null) {
Log.e(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的下载任务"); task = mCachePool.getTask(entity.getDownloadUrl());
return -1; }
if (task == null) {
task = createTask(entity);
}
return task;
} }
return task.getDownloadEntity().getState();
}
@Override public void removeTask(DownloadEntity entity) { @Override public int getTaskState(DownloadEntity entity) {
Task task = mCachePool.getTask(entity.getDownloadUrl()); Task task = getTask(entity);
if (task != null) { if (task == null) {
Log.d(TAG, "任务删除" + (mCachePool.removeTask(task) ? "成功" : "失败")); Log.e(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的下载任务");
} else { return -1;
task = mExecutePool.getTask(entity.getDownloadUrl()); }
return task.getDownloadEntity().getState();
} }
if (task != null) {
Log.d(TAG, "任务删除" + (mCachePool.removeTask(task) ? "成功" : "失败")); @Override public void removeTask(DownloadEntity entity) {
} else { Task task = mCachePool.getTask(entity.getDownloadUrl());
Log.w(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的任务"); if (task != null) {
Log.d(TAG, "任务删除" + (mCachePool.removeTask(task) ?
"成功" :
"失败"
));
} else {
task = mExecutePool.getTask(entity.getDownloadUrl());
}
if (task != null) {
Log.d(TAG, "任务删除" + (mCachePool.removeTask(task) ?
"成功" :
"失败"
));
} else {
Log.w(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的任务");
}
} }
}
@Override public Task getNextTask() { @Override public Task getNextTask() {
return mCachePool.pollTask(); return mCachePool.pollTask();
} }
} }

@ -3,6 +3,7 @@ package com.arialyy.downloadutil.core;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.core.inf.IDownloader; import com.arialyy.downloadutil.core.inf.IDownloader;
import com.arialyy.downloadutil.core.inf.ITask; import com.arialyy.downloadutil.core.inf.ITask;
import com.arialyy.downloadutil.core.pool.CachePool; import com.arialyy.downloadutil.core.pool.CachePool;
@ -14,205 +15,205 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
* 任务下载器提供抽象的方法供具体的实现类操作 * 任务下载器提供抽象的方法供具体的实现类操作
*/ */
public abstract class IDownloadTarget implements IDownloader, ITask { public abstract class IDownloadTarget implements IDownloader, ITask {
/**
* 任务开始
*/
public static final int START = 1;
/**
* 任务停止
*/
public static final int STOP = 2;
/**
* 任务失败
*/
public static final int FAIL = 3;
/**
* 任务取消
*/
public static final int CANCEL = 4;
/**
* 任务完成
*/
public static final int COMPLETE = 5;
protected CachePool mCachePool = CachePool.getInstance();
protected ExecutePool mExecutePool = ExecutePool.getInstance();
protected AutoTaskHandler mTaskHandler;
/**
* 下载失败次数
*/
protected int mFailNum = 10;
/**
* 超时时间
*/
protected long mTimeOut = 10000;
/**
* 下载器任务监听
*/
protected OnTargetListener mTargetListener;
/**
* Target处理任务监听
*/
public interface OnTargetListener {
/** /**
* 任务开始 * 任务开始
*/ */
public void onTaskStart(Task task); public static final int START = 1;
/** /**
* 任务停止 * 任务停止
*/ */
public void onTaskStop(Task task); public static final int STOP = 2;
/**
* 任务失败
*/
public static final int FAIL = 3;
/** /**
* 任务取消 * 任务取消
*/ */
public void onTaskCancel(Task task); public static final int CANCEL = 4;
/**
* 任务完成
*/
public static final int COMPLETE = 5;
protected CachePool mCachePool = CachePool.getInstance();
protected ExecutePool mExecutePool = ExecutePool.getInstance();
protected AutoTaskHandler mTaskHandler;
/** /**
* 任务下载失败 * 下载失败次数
*/ */
public void onTaskFail(Task task); protected int mFailNum = 10;
/** /**
* 任务完成 * 超时时间
*/ */
public void onTaskComplete(Task task); protected long mTimeOut = 10000;
}
/**
protected IDownloadTarget() { * 下载器任务监听
mTaskHandler = new AutoTaskHandler(this); */
} protected OnTargetListener mTargetListener;
/** /**
* 设置下载器监听 * Target处理任务监听
* */
* @param targetListener {@link OnTargetListener} public interface OnTargetListener {
*/ /**
public void setOnTargetListener(OnTargetListener targetListener) { * 任务开始
this.mTargetListener = targetListener; */
} public void onTaskStart(Task task);
/** /**
* 获取当前运行的任务数 * 任务停止
* */
* @return 当前正在执行的任务数 public void onTaskStop(Task task);
*/
public int getCurrentTaskNum() { /**
return mExecutePool.size(); * 任务取消
} */
public void onTaskCancel(Task task);
/**
* 获取缓存任务数 /**
* * 任务下载失败
* @return 获取缓存的任务数 */
*/ public void onTaskFail(Task task);
public int getCacheTaskNum() {
return mCachePool.size(); /**
} * 任务完成
*/
public void setFailNum(int mFailNum) { public void onTaskComplete(Task task);
this.mFailNum = mFailNum;
}
public void setTimeOut(long timeOut) {
this.mTimeOut = timeOut;
}
/**
* 自动处理任务停止下载失败取消下载自动下载下一个任务的操作
*/
private static class AutoTaskHandler extends Handler {
private static final String TAG = "AutoTaskHandler";
IDownloadTarget target;
public AutoTaskHandler(IDownloadTarget target) {
this.target = target;
} }
@Override public void handleMessage(Message msg) { protected IDownloadTarget() {
super.handleMessage(msg); mTaskHandler = new AutoTaskHandler(this);
DownloadEntity entity = (DownloadEntity) msg.obj;
if (entity == null) {
Log.e(TAG, "请传入下载实体DownloadEntity");
return;
}
switch (msg.what) {
case STOP:
startNextTask(entity);
break;
case CANCEL:
startNextTask(entity);
break;
case COMPLETE:
startNextTask(entity);
break;
case FAIL:
handleFailTask(entity);
break;
}
callback(msg.what, entity);
} }
/** /**
* 回调 * 设置下载器监听
* *
* @param state 状态 * @param targetListener {@link OnTargetListener}
* @param entity 下载实体
*/ */
private void callback(int state, DownloadEntity entity) { public void setOnTargetListener(OnTargetListener targetListener) {
if (target.mTargetListener != null) { this.mTargetListener = targetListener;
Task task = target.getTask(entity);
switch (state) {
case START:
target.mTargetListener.onTaskStart(task);
break;
case STOP:
target.mTargetListener.onTaskStop(task);
break;
case CANCEL:
target.mTargetListener.onTaskCancel(task);
break;
case COMPLETE:
target.mTargetListener.onTaskCancel(task);
break;
case FAIL:
target.mTargetListener.onTaskFail(task);
break;
}
}
} }
/** /**
* 处理下载任务下载失败的情形 * 获取当前运行的任务数
* *
* @param entity 失败实体 * @return 当前正在执行的任务数
*/ */
private void handleFailTask(DownloadEntity entity) { public int getCurrentTaskNum() {
if (entity.getFailNum() <= target.mFailNum) { return mExecutePool.size();
Task task = target.getTask(entity);
target.reTryStart(task);
} else {
startNextTask(entity);
}
} }
/** /**
* 启动下一个任务条件任务停止取消下载任务完成 * 获取缓存任务数
* *
* @param entity 通过Handler传递的下载实体 * @return 获取缓存的任务数
*/
public int getCacheTaskNum() {
return mCachePool.size();
}
public void setFailNum(int mFailNum) {
this.mFailNum = mFailNum;
}
public void setTimeOut(long timeOut) {
this.mTimeOut = timeOut;
}
/**
* 自动处理任务停止下载失败取消下载自动下载下一个任务的操作
*/ */
private void startNextTask(DownloadEntity entity) { private static class AutoTaskHandler extends Handler {
target.removeTask(entity); private static final String TAG = "AutoTaskHandler";
Task newTask = target.getNextTask(); IDownloadTarget target;
if (newTask == null) {
Log.e(TAG, "没有下一任务"); public AutoTaskHandler(IDownloadTarget target) {
return; this.target = target;
} }
target.startTask(newTask);
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
DownloadEntity entity = (DownloadEntity) msg.obj;
if (entity == null) {
Log.e(TAG, "请传入下载实体DownloadEntity");
return;
}
switch (msg.what) {
case STOP:
startNextTask(entity);
break;
case CANCEL:
startNextTask(entity);
break;
case COMPLETE:
startNextTask(entity);
break;
case FAIL:
handleFailTask(entity);
break;
}
callback(msg.what, entity);
}
/**
* 回调
*
* @param state 状态
* @param entity 下载实体
*/
private void callback(int state, DownloadEntity entity) {
if (target.mTargetListener != null) {
Task task = target.getTask(entity);
switch (state) {
case START:
target.mTargetListener.onTaskStart(task);
break;
case STOP:
target.mTargetListener.onTaskStop(task);
break;
case CANCEL:
target.mTargetListener.onTaskCancel(task);
break;
case COMPLETE:
target.mTargetListener.onTaskCancel(task);
break;
case FAIL:
target.mTargetListener.onTaskFail(task);
break;
}
}
}
/**
* 处理下载任务下载失败的情形
*
* @param entity 失败实体
*/
private void handleFailTask(DownloadEntity entity) {
if (entity.getFailNum() <= target.mFailNum) {
Task task = target.getTask(entity);
target.reTryStart(task);
} else {
startNextTask(entity);
}
}
/**
* 启动下一个任务条件任务停止取消下载任务完成
*
* @param entity 通过Handler传递的下载实体
*/
private void startNextTask(DownloadEntity entity) {
target.removeTask(entity);
Task newTask = target.getNextTask();
if (newTask == null) {
Log.e(TAG, "没有下一任务");
return;
}
target.startTask(newTask);
}
} }
}
} }

@ -4,9 +4,11 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.DownLoadUtil; import com.arialyy.downloadutil.util.DownLoadUtil;
import com.arialyy.downloadutil.util.IDownloadListener; import com.arialyy.downloadutil.util.IDownloadListener;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
/** /**
@ -14,189 +16,190 @@ import java.net.HttpURLConnection;
* 下载任务类 * 下载任务类
*/ */
public class Task { public class Task {
public static final String TAG = "Task"; public static final String TAG = "Task";
private DownloadEntity downloadEntity;
private IDownloadListener listener;
private Handler outHandler;
private Context context;
private DownLoadUtil util;
private Task() {
util = new DownLoadUtil();
}
/**
* 开始下载
*/
public void start() {
if (util.isDownloading()) {
Log.d(TAG, "任务正在下载");
} else {
if (listener == null) {
listener = new DownloadListener(context, downloadEntity, outHandler);
}
util.download(context, downloadEntity.getDownloadUrl(), downloadEntity.getDownloadPath(),
listener);
}
}
public DownloadEntity getDownloadEntity() {
return downloadEntity;
}
/**
* 停止下载
*/
public void stop() {
if (util.isDownloading()) {
util.stopDownload();
}
}
/**
* 获取下载工具
*/
public DownLoadUtil getDownloadUtil() {
return util;
}
/**
* 取消下载
*/
public void cancel() {
util.cancelDownload();
}
/**
* 下载监听类
*/
private static class DownloadListener extends DownLoadUtil.DownloadListener {
Handler outHandler;
Context context;
Intent sendIntent;
long INTERVAL = 1024 * 10; //10k大小的间隔
long lastLen = 0; //上一次发送长度
DownloadEntity downloadEntity;
public DownloadListener(Context context, DownloadEntity downloadEntity, Handler outHandler) {
this.context = context;
this.outHandler = outHandler;
this.downloadEntity = downloadEntity;
sendIntent = new Intent();
sendIntent.addCategory(context.getPackageName());
}
@Override public void onPreDownload(HttpURLConnection connection) {
super.onPreDownload(connection);
long len = connection.getContentLength();
downloadEntity.setFileSize(len);
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
sendIntent(DownloadManager.ACTION_PRE, -1);
}
@Override public void onResume(long resumeLocation) { private DownloadEntity downloadEntity;
super.onResume(resumeLocation); private IDownloadListener listener;
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING); private Handler outHandler;
sendIntent(DownloadManager.ACTION_RESUME, resumeLocation); private Context context;
} private DownLoadUtil util;
@Override public void onStart(long startLocation) {
super.onStart(startLocation);
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
sendInState2Target(IDownloadTarget.START);
sendIntent(DownloadManager.ACTION_START, startLocation);
}
@Override public void onProgress(long currentLocation) {
super.onProgress(currentLocation);
if (currentLocation - lastLen > INTERVAL) { //不要太过于频繁发送广播
sendIntent.putExtra(DownloadManager.ACTION_RUNNING, currentLocation);
lastLen = currentLocation;
}
}
@Override public void onStop(long stopLocation) {
super.onStop(stopLocation);
downloadEntity.setState(DownloadEntity.STATE_STOP);
sendInState2Target(IDownloadTarget.STOP);
sendIntent(DownloadManager.ACTION_STOP, stopLocation);
}
@Override public void onCancel() { private Task() {
super.onCancel(); util = new DownLoadUtil();
downloadEntity.setState(DownloadEntity.STATE_CANCEL);
sendInState2Target(IDownloadTarget.CANCEL);
sendIntent(DownloadManager.ACTION_CANCEL, -1);
downloadEntity.deleteData();
}
@Override public void onComplete() {
super.onComplete();
downloadEntity.setState(DownloadEntity.STATE_COMPLETE);
downloadEntity.setDownloadComplete(true);
sendInState2Target(IDownloadTarget.COMPLETE);
sendIntent(DownloadManager.ACTION_COMPLETE, -1);
}
@Override public void onFail() {
super.onFail();
downloadEntity.setState(DownloadEntity.STATE_FAIL);
sendInState2Target(IDownloadTarget.FAIL);
sendIntent(DownloadManager.ACTION_FAIL, -1);
} }
/** /**
* 将任务状态发送给下载器 * 开始下载
*
* @param state {@link IDownloadTarget#START}
*/ */
private void sendInState2Target(int state) { public void start() {
if (outHandler != null) { if (util.isDownloading()) {
outHandler.obtainMessage(state, downloadEntity).sendToTarget(); Log.d(TAG, "任务正在下载");
} } else {
if (listener == null) {
listener = new DownloadListener(context, downloadEntity, outHandler);
}
util.download(context, downloadEntity.getDownloadUrl(),
downloadEntity.getDownloadPath(), listener);
}
} }
private void sendIntent(String action, long location) { public DownloadEntity getDownloadEntity() {
downloadEntity.save(); return downloadEntity;
Intent intent = new Intent();
intent.addCategory(context.getPackageName());
intent.putExtra(action, downloadEntity);
if (location != -1) {
intent.putExtra(DownloadManager.CURRENT_LOCATION, location);
}
context.sendBroadcast(intent);
} }
}
public static class Builder { /**
DownloadEntity downloadEntity; * 停止下载
IDownloadListener listener; */
Handler outHandler; public void stop() {
Context context; if (util.isDownloading()) {
util.stopDownload();
public Builder(Context context, DownloadEntity downloadEntity) { }
this.context = context;
this.downloadEntity = downloadEntity;
} }
public Builder setDownloadListener(IDownloadListener listener) { /**
this.listener = listener; * 获取下载工具
return this; */
public DownLoadUtil getDownloadUtil() {
return util;
} }
public Builder setOutHandler(Handler outHandler) { /**
this.outHandler = outHandler; * 取消下载
return this; */
public void cancel() {
util.cancelDownload();
} }
public Task builder() { /**
Task task = new Task(); * 下载监听类
task.context = context; */
task.downloadEntity = downloadEntity; private static class DownloadListener extends DownLoadUtil.DownloadListener {
task.listener = listener; Handler outHandler;
task.outHandler = outHandler; Context context;
return task; Intent sendIntent;
long INTERVAL = 1024 * 10; //10k大小的间隔
long lastLen = 0; //上一次发送长度
DownloadEntity downloadEntity;
public DownloadListener(Context context, DownloadEntity downloadEntity,
Handler outHandler) {
this.context = context;
this.outHandler = outHandler;
this.downloadEntity = downloadEntity;
sendIntent = new Intent();
sendIntent.addCategory(context.getPackageName());
}
@Override public void onPreDownload(HttpURLConnection connection) {
super.onPreDownload(connection);
long len = connection.getContentLength();
downloadEntity.setFileSize(len);
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
sendIntent(DownloadManager.ACTION_PRE, -1);
}
@Override public void onResume(long resumeLocation) {
super.onResume(resumeLocation);
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
sendIntent(DownloadManager.ACTION_RESUME, resumeLocation);
}
@Override public void onStart(long startLocation) {
super.onStart(startLocation);
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
sendInState2Target(IDownloadTarget.START);
sendIntent(DownloadManager.ACTION_START, startLocation);
}
@Override public void onProgress(long currentLocation) {
super.onProgress(currentLocation);
if (currentLocation - lastLen > INTERVAL) { //不要太过于频繁发送广播
sendIntent.putExtra(DownloadManager.ACTION_RUNNING, currentLocation);
lastLen = currentLocation;
}
}
@Override public void onStop(long stopLocation) {
super.onStop(stopLocation);
downloadEntity.setState(DownloadEntity.STATE_STOP);
sendInState2Target(IDownloadTarget.STOP);
sendIntent(DownloadManager.ACTION_STOP, stopLocation);
}
@Override public void onCancel() {
super.onCancel();
downloadEntity.setState(DownloadEntity.STATE_CANCEL);
sendInState2Target(IDownloadTarget.CANCEL);
sendIntent(DownloadManager.ACTION_CANCEL, -1);
downloadEntity.deleteData();
}
@Override public void onComplete() {
super.onComplete();
downloadEntity.setState(DownloadEntity.STATE_COMPLETE);
downloadEntity.setDownloadComplete(true);
sendInState2Target(IDownloadTarget.COMPLETE);
sendIntent(DownloadManager.ACTION_COMPLETE, -1);
}
@Override public void onFail() {
super.onFail();
downloadEntity.setState(DownloadEntity.STATE_FAIL);
sendInState2Target(IDownloadTarget.FAIL);
sendIntent(DownloadManager.ACTION_FAIL, -1);
}
/**
* 将任务状态发送给下载器
*
* @param state {@link IDownloadTarget#START}
*/
private void sendInState2Target(int state) {
if (outHandler != null) {
outHandler.obtainMessage(state, downloadEntity).sendToTarget();
}
}
private void sendIntent(String action, long location) {
downloadEntity.save();
Intent intent = new Intent();
intent.addCategory(context.getPackageName());
intent.putExtra(action, downloadEntity);
if (location != -1) {
intent.putExtra(DownloadManager.CURRENT_LOCATION, location);
}
context.sendBroadcast(intent);
}
}
public static class Builder {
DownloadEntity downloadEntity;
IDownloadListener listener;
Handler outHandler;
Context context;
public Builder(Context context, DownloadEntity downloadEntity) {
this.context = context;
this.downloadEntity = downloadEntity;
}
public Builder setDownloadListener(IDownloadListener listener) {
this.listener = listener;
return this;
}
public Builder setOutHandler(Handler outHandler) {
this.outHandler = outHandler;
return this;
}
public Task builder() {
Task task = new Task();
task.context = context;
task.downloadEntity = downloadEntity;
task.listener = listener;
task.outHandler = outHandler;
return task;
}
} }
}
} }

@ -5,5 +5,5 @@ package com.arialyy.downloadutil.core;
* 创建任务类型 * 创建任务类型
*/ */
public enum TaskEnum { public enum TaskEnum {
ORDINARY, NO_USR_CALLBACK ORDINARY, NO_USR_CALLBACK
} }

@ -2,6 +2,7 @@ package com.arialyy.downloadutil.core;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,33 +10,33 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
* 任务工厂 * 任务工厂
*/ */
public class TaskFactory { public class TaskFactory {
private static final String TAG = "TaskFactory"; private static final String TAG = "TaskFactory";
private static final Object LOCK = new Object();
private static volatile TaskFactory INSTANCE = null;
private static final Object LOCK = new Object(); private TaskFactory() {
private static volatile TaskFactory INSTANCE = null;
private TaskFactory() { }
} public static TaskFactory getInstance() {
if (INSTANCE == null) {
synchronized (LOCK) {
INSTANCE = new TaskFactory();
}
}
return INSTANCE;
}
public static TaskFactory getInstance() { /**
if (INSTANCE == null) { * 创建普通下载任务
synchronized (LOCK) { *
INSTANCE = new TaskFactory(); * @param entity 下载实体
} * @param handler {@link com.arialyy.downloadutil.core.IDownloadTarget.AutoTaskHandler}
*/
public Task createTask(Context context, DownloadEntity entity, Handler handler) {
Task.Builder builder = new Task.Builder(context, entity);
builder.setOutHandler(handler);
return builder.builder();
} }
return INSTANCE;
}
/**
* 创建普通下载任务
*
* @param entity 下载实体
* @param handler {@link com.arialyy.downloadutil.core.IDownloadTarget.AutoTaskHandler}
*/
public Task createTask(Context context, DownloadEntity entity, Handler handler) {
Task.Builder builder = new Task.Builder(context, entity);
builder.setOutHandler(handler);
return builder.builder();
}
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,11 +10,11 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
class AddCommand extends IDownloadCommand { class AddCommand extends IDownloadCommand {
AddCommand(Context context, DownloadEntity entity) { AddCommand(Context context, DownloadEntity entity) {
super(context, entity); super(context, entity);
} }
@Override public void executeComment() { @Override public void executeComment() {
target.createTask(mEntity); target.createTask(mEntity);
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,11 +10,11 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
class CancelCommand extends IDownloadCommand { class CancelCommand extends IDownloadCommand {
CancelCommand(Context context, DownloadEntity entity) { CancelCommand(Context context, DownloadEntity entity) {
super(context, entity); super(context, entity);
} }
@Override public void executeComment() { @Override public void executeComment() {
target.cancelTask(target.getTask(mEntity)); target.cancelTask(target.getTask(mEntity));
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -8,108 +9,108 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
* 命令工厂 * 命令工厂
*/ */
public class CommandFactory { public class CommandFactory {
/** /**
* 创建任务 * 创建任务
*/ */
public static final int TASK_CREATE = 0x122; public static final int TASK_CREATE = 0x122;
/** /**
* 启动任务 * 启动任务
*/ */
public static final int TASK_START = 0x123; public static final int TASK_START = 0x123;
/** /**
* 取消任务 * 取消任务
*/ */
public static final int TASK_CANCEL = 0x124; public static final int TASK_CANCEL = 0x124;
/** /**
* 停止任务 * 停止任务
*/ */
public static final int TASK_STOP = 0x125; public static final int TASK_STOP = 0x125;
/** /**
* 获取任务状态 * 获取任务状态
*/ */
public static final int TASK_STATE = 0x126; public static final int TASK_STATE = 0x126;
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private static volatile CommandFactory INSTANCE = null; private static volatile CommandFactory INSTANCE = null;
private CommandFactory() { private CommandFactory() {
} }
public static CommandFactory getInstance() { public static CommandFactory getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (LOCK) { synchronized (LOCK) {
INSTANCE = new CommandFactory(); INSTANCE = new CommandFactory();
} }
}
return INSTANCE;
} }
return INSTANCE;
}
/** /**
* @param context context * @param context context
* @param entity 下载实体 * @param entity 下载实体
* @param type 命令类型{@link #TASK_CREATE}{@link #TASK_START}{@link #TASK_CANCEL}{@link * @param type 命令类型{@link #TASK_CREATE}{@link #TASK_START}{@link #TASK_CANCEL}{@link
* #TASK_STOP}{@link #TASK_STATE} * #TASK_STOP}{@link #TASK_STATE}
*/ */
public IDownloadCommand createCommand(Context context, DownloadEntity entity, int type) { public IDownloadCommand createCommand(Context context, DownloadEntity entity, int type) {
switch (type) { switch (type) {
case TASK_CREATE: case TASK_CREATE:
return createAddCommand(context, entity); return createAddCommand(context, entity);
case TASK_START: case TASK_START:
return createStartCommand(context, entity); return createStartCommand(context, entity);
case TASK_CANCEL: case TASK_CANCEL:
return createCancelCommand(context, entity); return createCancelCommand(context, entity);
case TASK_STOP: case TASK_STOP:
return createStopCommand(context, entity); return createStopCommand(context, entity);
case TASK_STATE: case TASK_STATE:
return createStateCommand(context, entity); return createStateCommand(context, entity);
default: default:
return null; return null;
}
} }
}
/** /**
* 创建获取任务状态的命令 * 创建获取任务状态的命令
* *
* @return {@link StateCommand} * @return {@link StateCommand}
*/ */
private StateCommand createStateCommand(Context context, DownloadEntity entity) { private StateCommand createStateCommand(Context context, DownloadEntity entity) {
return new StateCommand(context, entity); return new StateCommand(context, entity);
} }
/** /**
* 创建停止命令 * 创建停止命令
* *
* @return {@link StopCommand} * @return {@link StopCommand}
*/ */
private StopCommand createStopCommand(Context context, DownloadEntity entity) { private StopCommand createStopCommand(Context context, DownloadEntity entity) {
return new StopCommand(context, entity); return new StopCommand(context, entity);
} }
/** /**
* 创建下载任务命令 * 创建下载任务命令
* *
* @return {@link AddCommand} * @return {@link AddCommand}
*/ */
private AddCommand createAddCommand(Context context, DownloadEntity entity) { private AddCommand createAddCommand(Context context, DownloadEntity entity) {
return new AddCommand(context, entity); return new AddCommand(context, entity);
} }
/** /**
* 创建启动下载命令 * 创建启动下载命令
* *
* @return {@link StartCommand} * @return {@link StartCommand}
*/ */
private StartCommand createStartCommand(Context context, DownloadEntity entity) { private StartCommand createStartCommand(Context context, DownloadEntity entity) {
return new StartCommand(context, entity); return new StartCommand(context, entity);
} }
/** /**
* 创建 取消下载的命令 * 创建 取消下载的命令
* *
* @return {@link CancelCommand} * @return {@link CancelCommand}
*/ */
private CancelCommand createCancelCommand(Context context, DownloadEntity entity) { private CancelCommand createCancelCommand(Context context, DownloadEntity entity) {
return new CancelCommand(context, entity); return new CancelCommand(context, entity);
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.core.DownloadTarget; import com.arialyy.downloadutil.core.DownloadTarget;
import com.arialyy.downloadutil.core.IDownloadTarget; import com.arialyy.downloadutil.core.IDownloadTarget;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
@ -11,38 +12,38 @@ import com.arialyy.downloadutil.help.CheckHelp;
* 下载命令 * 下载命令
*/ */
public abstract class IDownloadCommand { public abstract class IDownloadCommand {
protected IDownloadTarget target; protected IDownloadTarget target;
protected Context mContext; protected Context mContext;
protected DownloadEntity mEntity; protected DownloadEntity mEntity;
/** /**
* @param context context * @param context context
* @param entity 下载实体 * @param entity 下载实体
*/ */
protected IDownloadCommand(Context context, DownloadEntity entity) { protected IDownloadCommand(Context context, DownloadEntity entity) {
if (!CheckHelp.checkDownloadEntity(entity)) { if (!CheckHelp.checkDownloadEntity(entity)) {
return; return;
}
target = DownloadTarget.getInstance(context);
mContext = context;
mEntity = entity;
} }
target = DownloadTarget.getInstance(context);
mContext = context;
mEntity = entity;
}
public Context getContext() { public Context getContext() {
return mContext; return mContext;
} }
/** /**
* 执行命令 * 执行命令
*/ */
public abstract void executeComment(); public abstract void executeComment();
/** /**
* 设置下载器 * 设置下载器
* *
* @param downloadTarget {@link IDownloadTarget} * @param downloadTarget {@link IDownloadTarget}
*/ */
public void setDownloadTarget(IDownloadTarget downloadTarget) { public void setDownloadTarget(IDownloadTarget downloadTarget) {
target = downloadTarget; target = downloadTarget;
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,11 +10,11 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
class StartCommand extends IDownloadCommand { class StartCommand extends IDownloadCommand {
StartCommand(Context context, DownloadEntity entity) { StartCommand(Context context, DownloadEntity entity) {
super(context, entity); super(context, entity);
} }
@Override public void executeComment() { @Override public void executeComment() {
target.startTask(target.getTask(mEntity)); target.startTask(target.getTask(mEntity));
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,15 +10,15 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
class StateCommand extends IDownloadCommand { class StateCommand extends IDownloadCommand {
/** /**
* @param context context * @param context context
* @param entity 下载实体 * @param entity 下载实体
*/ */
StateCommand(Context context, DownloadEntity entity) { StateCommand(Context context, DownloadEntity entity) {
super(context, entity); super(context, entity);
} }
@Override public void executeComment() { @Override public void executeComment() {
target.getTaskState(mEntity); target.getTaskState(mEntity);
} }
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
/** /**
@ -9,15 +10,15 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
class StopCommand extends IDownloadCommand { class StopCommand extends IDownloadCommand {
/** /**
* @param context context * @param context context
* @param entity 下载实体 * @param entity 下载实体
*/ */
StopCommand(Context context, DownloadEntity entity) { StopCommand(Context context, DownloadEntity entity) {
super(context, entity); super(context, entity);
} }
@Override public void executeComment() { @Override public void executeComment() {
target.stopTask(target.getTask(mEntity)); target.stopTask(target.getTask(mEntity));
} }
} }

@ -7,31 +7,31 @@ import com.arialyy.downloadutil.core.Task;
* 下载功能接口 * 下载功能接口
*/ */
public interface IDownloader { public interface IDownloader {
/** /**
* 开始任务 * 开始任务
* *
* @param task {@link Task} * @param task {@link Task}
*/ */
public void startTask(Task task); public void startTask(Task task);
/** /**
* 停止任务 * 停止任务
* *
* @param task {@link Task} * @param task {@link Task}
*/ */
public void stopTask(Task task); public void stopTask(Task task);
/** /**
* 取消任务 * 取消任务
* *
* @param task {@link Task} * @param task {@link Task}
*/ */
public void cancelTask(Task task); public void cancelTask(Task task);
/** /**
* 重试下载 * 重试下载
* *
* @param task {@link Task} * @param task {@link Task}
*/ */
public void reTryStart(Task task); public void reTryStart(Task task);
} }

@ -7,46 +7,46 @@ import com.arialyy.downloadutil.core.Task;
* 任务池 * 任务池
*/ */
public interface IPool { public interface IPool {
/** /**
* 将下载任务添加到任务池中 * 将下载任务添加到任务池中
*/ */
public boolean putTask(Task task); public boolean putTask(Task task);
/** /**
* 按照队列原则取出下载任务 * 按照队列原则取出下载任务
* *
* @return 返回null或者下载任务 * @return 返回null或者下载任务
*/ */
public Task pollTask(); public Task pollTask();
/** /**
* 通过下载链接获取下载任务当任务不为空时队列将删除该下载任务 * 通过下载链接获取下载任务当任务不为空时队列将删除该下载任务
* *
* @param downloadUrl 下载链接 * @param downloadUrl 下载链接
* @return 返回null或者下载任务 * @return 返回null或者下载任务
*/ */
public Task getTask(String downloadUrl); public Task getTask(String downloadUrl);
/** /**
* 删除任务池中的下载任务 * 删除任务池中的下载任务
* *
* @param task 下载任务 * @param task 下载任务
* @return true:移除成功 * @return true:移除成功
*/ */
public boolean removeTask(Task task); public boolean removeTask(Task task);
/** /**
* 通过下载链接移除下载任务 * 通过下载链接移除下载任务
* *
* @param downloadUrl 下载链接 * @param downloadUrl 下载链接
* @return true:移除成功 * @return true:移除成功
*/ */
public boolean removeTask(String downloadUrl); public boolean removeTask(String downloadUrl);
/** /**
* 池子大小 * 池子大小
* *
* @return 返回缓存池或者当前任务池大小 * @return 返回缓存池或者当前任务池大小
*/ */
public int size(); public int size();
} }

@ -9,41 +9,41 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
*/ */
public interface ITask { public interface ITask {
/** /**
* 创建一个新的下载任务创建时只是将新任务存储到缓存池 * 创建一个新的下载任务创建时只是将新任务存储到缓存池
* *
* @param entity 下载实体{@link DownloadEntity} * @param entity 下载实体{@link DownloadEntity}
* @return {@link Task} * @return {@link Task}
*/ */
public Task createTask(DownloadEntity entity); public Task createTask(DownloadEntity entity);
/** /**
* 通过下载链接从缓存池或任务池搜索下载任务如果缓存池或任务池都没有任务则创建新任务 * 通过下载链接从缓存池或任务池搜索下载任务如果缓存池或任务池都没有任务则创建新任务
* *
* @param entity 下载实体{@link DownloadEntity} * @param entity 下载实体{@link DownloadEntity}
* @return {@link Task} * @return {@link Task}
*/ */
public Task getTask(DownloadEntity entity); public Task getTask(DownloadEntity entity);
/** /**
* 通过下载链接搜索下载任务 * 通过下载链接搜索下载任务
* *
* @param entity 下载实体{@link DownloadEntity} * @param entity 下载实体{@link DownloadEntity}
* @return {@code -1 ==> 错误}{@link com.arialyy.downloadutil.entity.DownloadEntity#STATE_FAIL} * @return {@code -1 ==> 错误}{@link com.arialyy.downloadutil.entity.DownloadEntity#STATE_FAIL}
*/ */
public int getTaskState(DownloadEntity entity); public int getTaskState(DownloadEntity entity);
/** /**
* 通过下载链接删除任务 * 通过下载链接删除任务
* *
* @param entity 下载实体{@link DownloadEntity} * @param entity 下载实体{@link DownloadEntity}
*/ */
public void removeTask(DownloadEntity entity); public void removeTask(DownloadEntity entity);
/** /**
* 获取缓存池的下一个任务 * 获取缓存池的下一个任务
* *
* @return 下载任务 or null * @return 下载任务 or null
*/ */
public Task getNextTask(); public Task getNextTask();
} }

@ -2,9 +2,11 @@ package com.arialyy.downloadutil.core.pool;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.core.Task; import com.arialyy.downloadutil.core.Task;
import com.arialyy.downloadutil.core.inf.IPool; import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Util; import com.arialyy.downloadutil.util.Util;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.PriorityQueue; import java.util.PriorityQueue;
@ -15,96 +17,99 @@ import java.util.Queue;
* 任务缓存池所有下载任务最先缓存在这个池中 * 任务缓存池所有下载任务最先缓存在这个池中
*/ */
public class CachePool implements IPool { public class CachePool implements IPool {
private static final String TAG = "CachePool"; private static final String TAG = "CachePool";
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private static volatile CachePool INSTANCE = null; private static volatile CachePool INSTANCE = null;
private Map<String, Task> mCacheArray; private Map<String, Task> mCacheArray;
private Queue<Task> mCacheQueue; private Queue<Task> mCacheQueue;
public static CachePool getInstance() { public static CachePool getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (LOCK) { synchronized (LOCK) {
INSTANCE = new CachePool(); INSTANCE = new CachePool();
} }
}
return INSTANCE;
} }
return INSTANCE;
}
private CachePool() { private CachePool() {
mCacheQueue = new PriorityQueue<>(); mCacheQueue = new PriorityQueue<>();
mCacheArray = new HashMap<>(); mCacheArray = new HashMap<>();
} }
@Override public boolean putTask(Task task) { @Override public boolean putTask(Task task) {
synchronized (LOCK) { synchronized (LOCK) {
if (task == null) { if (task == null) {
Log.e(TAG, "下载任务不能为空!!"); Log.e(TAG, "下载任务不能为空!!");
return false; return false;
} }
String url = task.getDownloadEntity().getDownloadUrl(); String url = task.getDownloadEntity().getDownloadUrl();
if (mCacheQueue.contains(task)) { if (mCacheQueue.contains(task)) {
Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】"); Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
return false; return false;
} else { } else {
boolean s = mCacheQueue.offer(task); boolean s = mCacheQueue.offer(task);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); Log.w(TAG, "任务添加" + (s ?
if (s) { "成功" :
mCacheArray.put(Util.keyToHashKey(url), task); "失败,【" + url + "】"
));
if (s) {
mCacheArray.put(Util.keyToHashKey(url), task);
}
return s;
}
} }
return s;
}
} }
}
@Override public Task pollTask() { @Override public Task pollTask() {
synchronized (LOCK) { synchronized (LOCK) {
Task task = mCacheQueue.poll(); Task task = mCacheQueue.poll();
if (task != null) { if (task != null) {
String url = task.getDownloadEntity().getDownloadUrl(); String url = task.getDownloadEntity().getDownloadUrl();
mCacheArray.remove(Util.keyToHashKey(url)); mCacheArray.remove(Util.keyToHashKey(url));
} }
return task; return task;
}
} }
}
@Override public Task getTask(String downloadUrl) { @Override public Task getTask(String downloadUrl) {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "请传入有效的下载链接"); Log.e(TAG, "请传入有效的下载链接");
return null; return null;
} }
String key = Util.keyToHashKey(downloadUrl); String key = Util.keyToHashKey(downloadUrl);
return mCacheArray.get(key); return mCacheArray.get(key);
}
} }
}
@Override public boolean removeTask(Task task) { @Override public boolean removeTask(Task task) {
synchronized (LOCK) { synchronized (LOCK) {
if (task == null) { if (task == null) {
Log.e(TAG, "任务不能为空"); Log.e(TAG, "任务不能为空");
return false; return false;
} else { } else {
String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl()); String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl());
mCacheArray.remove(key); mCacheArray.remove(key);
return mCacheQueue.remove(task); return mCacheQueue.remove(task);
} }
}
} }
}
@Override public boolean removeTask(String downloadUrl) { @Override public boolean removeTask(String downloadUrl) {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "请传入有效的下载链接"); Log.e(TAG, "请传入有效的下载链接");
return false; return false;
} }
String key = Util.keyToHashKey(downloadUrl); String key = Util.keyToHashKey(downloadUrl);
Task task = mCacheArray.get(key); Task task = mCacheArray.get(key);
mCacheArray.remove(key); mCacheArray.remove(key);
return mCacheQueue.remove(task); return mCacheQueue.remove(task);
}
} }
}
@Override public int size() { @Override public int size() {
return mCacheQueue.size(); return mCacheQueue.size();
} }
} }

@ -2,9 +2,11 @@ package com.arialyy.downloadutil.core.pool;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.core.Task; import com.arialyy.downloadutil.core.Task;
import com.arialyy.downloadutil.core.inf.IPool; import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Util; import com.arialyy.downloadutil.util.Util;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
@ -15,137 +17,140 @@ import java.util.concurrent.TimeUnit;
* 任务执行池所有当前下载任务都该任务池中默认下载大小为2 * 任务执行池所有当前下载任务都该任务池中默认下载大小为2
*/ */
public class ExecutePool implements IPool { public class ExecutePool implements IPool {
private static final String TAG = "ExecutePool"; private static final String TAG = "ExecutePool";
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private static final long TIME_OUT = 1000; private static final long TIME_OUT = 1000;
private static volatile ExecutePool INSTANCE = null; private static volatile ExecutePool INSTANCE = null;
private static int SIZE = 2; private static int SIZE = 2;
private ArrayBlockingQueue<Task> mExecuteQueue; private ArrayBlockingQueue<Task> mExecuteQueue;
private Map<String, Task> mExecuteArray; private Map<String, Task> mExecuteArray;
public static ExecutePool getInstance() { public static ExecutePool getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (LOCK) { synchronized (LOCK) {
INSTANCE = new ExecutePool(); INSTANCE = new ExecutePool();
} }
}
return INSTANCE;
} }
return INSTANCE;
}
private ExecutePool() { private ExecutePool() {
mExecuteQueue = new ArrayBlockingQueue<>(SIZE); mExecuteQueue = new ArrayBlockingQueue<>(SIZE);
mExecuteArray = new HashMap<>(); mExecuteArray = new HashMap<>();
} }
@Override public boolean putTask(Task task) { @Override public boolean putTask(Task task) {
synchronized (LOCK) { synchronized (LOCK) {
if (task == null) { if (task == null) {
Log.e(TAG, "下载任务不能为空!!"); Log.e(TAG, "下载任务不能为空!!");
return false; return false;
} }
String url = task.getDownloadEntity().getDownloadUrl(); String url = task.getDownloadEntity().getDownloadUrl();
if (mExecuteQueue.contains(task)) { if (mExecuteQueue.contains(task)) {
Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】"); Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
return false; return false;
} else { } else {
if (mExecuteQueue.size() >= SIZE) { if (mExecuteQueue.size() >= SIZE) {
if (pollFirstTask()) { if (pollFirstTask()) {
return putNewTask(task); return putNewTask(task);
} }
} else { } else {
return putNewTask(task); return putNewTask(task);
}
}
} }
} return false;
} }
return false;
}
/** /**
* 添加新任务 * 添加新任务
* *
* @param newTask 新下载任务 * @param newTask 新下载任务
*/ */
private boolean putNewTask(Task newTask) { private boolean putNewTask(Task newTask) {
String url = newTask.getDownloadEntity().getDownloadUrl(); String url = newTask.getDownloadEntity().getDownloadUrl();
boolean s = mExecuteQueue.offer(newTask); boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); Log.w(TAG, "任务添加" + (s ?
if (s) { "成功" :
newTask.start(); "失败,【" + url + "】"
mExecuteArray.put(Util.keyToHashKey(url), newTask); ));
if (s) {
newTask.start();
mExecuteArray.put(Util.keyToHashKey(url), newTask);
}
return s;
} }
return s;
}
/** /**
* 队列满时将移除下载队列中的第一个任务 * 队列满时将移除下载队列中的第一个任务
*/ */
private boolean pollFirstTask() { private boolean pollFirstTask() {
try { try {
Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) { if (oldTask == null) {
Log.e(TAG, "移除任务失败"); Log.e(TAG, "移除任务失败");
return false; return false;
} }
oldTask.stop(); oldTask.stop();
wait(200); wait(200);
String key = Util.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl()); String key = Util.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl());
mExecuteArray.remove(key); mExecuteArray.remove(key);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
return false; return false;
}
return true;
} }
return true;
}
@Override public Task pollTask() { @Override public Task pollTask() {
synchronized (LOCK) { synchronized (LOCK) {
Task task = mExecuteQueue.poll(); Task task = mExecuteQueue.poll();
if (task != null) { if (task != null) {
String url = task.getDownloadEntity().getDownloadUrl(); String url = task.getDownloadEntity().getDownloadUrl();
mExecuteArray.remove(Util.keyToHashKey(url)); mExecuteArray.remove(Util.keyToHashKey(url));
} }
return task; return task;
}
} }
}
@Override public Task getTask(String downloadUrl) { @Override public Task getTask(String downloadUrl) {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "请传入有效的下载链接"); Log.e(TAG, "请传入有效的下载链接");
return null; return null;
} }
String key = Util.keyToHashKey(downloadUrl); String key = Util.keyToHashKey(downloadUrl);
return mExecuteArray.get(key); return mExecuteArray.get(key);
}
} }
}
@Override public boolean removeTask(Task task) { @Override public boolean removeTask(Task task) {
synchronized (LOCK) { synchronized (LOCK) {
if (task == null) { if (task == null) {
Log.e(TAG, "任务不能为空"); Log.e(TAG, "任务不能为空");
return false; return false;
} else { } else {
String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl()); String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl());
mExecuteArray.remove(key); mExecuteArray.remove(key);
return mExecuteQueue.remove(task); return mExecuteQueue.remove(task);
} }
}
} }
}
@Override public boolean removeTask(String downloadUrl) { @Override public boolean removeTask(String downloadUrl) {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "请传入有效的下载链接"); Log.e(TAG, "请传入有效的下载链接");
return false; return false;
} }
String key = Util.keyToHashKey(downloadUrl); String key = Util.keyToHashKey(downloadUrl);
Task task = mExecuteArray.get(key); Task task = mExecuteArray.get(key);
mExecuteArray.remove(key); mExecuteArray.remove(key);
return mExecuteQueue.remove(task); return mExecuteQueue.remove(task);
}
} }
}
@Override public int size() { @Override public int size() {
return mExecuteQueue.size(); return mExecuteQueue.size();
} }
} }

@ -2,6 +2,7 @@ package com.arialyy.downloadutil.entity;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.downloadutil.orm.DbEntity; import com.arialyy.downloadutil.orm.DbEntity;
/** /**
@ -9,179 +10,181 @@ import com.arialyy.downloadutil.orm.DbEntity;
* 下载实体 * 下载实体
*/ */
public class DownloadEntity extends DbEntity implements Parcelable, Cloneable { public class DownloadEntity extends DbEntity implements Parcelable, Cloneable {
/** /**
* 其它状态 * 其它状态
*/ */
public static final int STATE_OTHER = -1; public static final int STATE_OTHER = -1;
/** /**
* 失败状态 * 失败状态
*/ */
public static final int STATE_FAIL = 0; public static final int STATE_FAIL = 0;
/** /**
* 完成状态 * 完成状态
*/ */
public static final int STATE_COMPLETE = 1; public static final int STATE_COMPLETE = 1;
/** /**
* 停止状态 * 停止状态
*/ */
public static final int STATE_STOP = 2; public static final int STATE_STOP = 2;
/** /**
* 未开始状态 * 未开始状态
*/ */
public static final int STATE_WAIT = 3; public static final int STATE_WAIT = 3;
/** /**
* 下载中 * 下载中
*/ */
public static final int STATE_DOWNLOAD_ING = 4; public static final int STATE_DOWNLOAD_ING = 4;
/** /**
* 取消下载 * 取消下载
*/ */
public static final int STATE_CANCEL = 5; public static final int STATE_CANCEL = 5;
private String downloadUrl; //下载路径 private String downloadUrl; //下载路径
private String downloadPath; //保存路径 private String downloadPath; //保存路径
private String fileName; //文件名 private String fileName; //文件名
private String str; //其它字段 private String str; //其它字段
private long completeTime; //完成时间 private long completeTime; //完成时间
private long fileSize = 1; private long fileSize = 1;
private int state = STATE_WAIT; private int state = STATE_WAIT;
private boolean isDownloadComplete = false; //是否下载完成 private boolean isDownloadComplete = false; //是否下载完成
private long currentProgress = 0; //当前下载进度 private long currentProgress = 0; //当前下载进度
private int failNum = 0; private int failNum = 0;
public String getStr() { public String getStr() {
return str; return str;
} }
public void setStr(String str) { public void setStr(String str) {
this.str = str; this.str = str;
} }
public String getFileName() { public String getFileName() {
return fileName; return fileName;
} }
public void setFileName(String fileName) { public void setFileName(String fileName) {
this.fileName = fileName; this.fileName = fileName;
} }
public int getFailNum() { public int getFailNum() {
return failNum; return failNum;
} }
public void setFailNum(int failNum) { public void setFailNum(int failNum) {
this.failNum = failNum; this.failNum = failNum;
} }
public String getDownloadUrl() { public String getDownloadUrl() {
return downloadUrl; return downloadUrl;
} }
public long getCompleteTime() { public long getCompleteTime() {
return completeTime; return completeTime;
} }
public void setCompleteTime(long completeTime) { public void setCompleteTime(long completeTime) {
this.completeTime = completeTime; this.completeTime = completeTime;
} }
public void setDownloadUrl(String downloadUrl) { public void setDownloadUrl(String downloadUrl) {
this.downloadUrl = downloadUrl; this.downloadUrl = downloadUrl;
} }
public String getDownloadPath() { public String getDownloadPath() {
return downloadPath; return downloadPath;
} }
public void setDownloadPath(String downloadPath) { public void setDownloadPath(String downloadPath) {
this.downloadPath = downloadPath; this.downloadPath = downloadPath;
} }
public long getFileSize() { public long getFileSize() {
return fileSize; return fileSize;
} }
public void setFileSize(long fileSize) { public void setFileSize(long fileSize) {
this.fileSize = fileSize; this.fileSize = fileSize;
} }
public int getState() { public int getState() {
return state; return state;
} }
public void setState(int state) { public void setState(int state) {
this.state = state; this.state = state;
} }
public boolean isDownloadComplete() { public boolean isDownloadComplete() {
return isDownloadComplete; return isDownloadComplete;
} }
public void setDownloadComplete(boolean downloadComplete) { public void setDownloadComplete(boolean downloadComplete) {
isDownloadComplete = downloadComplete; isDownloadComplete = downloadComplete;
} }
public long getCurrentProgress() { public long getCurrentProgress() {
return currentProgress; return currentProgress;
} }
public void setCurrentProgress(long currentProgress) { public void setCurrentProgress(long currentProgress) {
this.currentProgress = currentProgress; this.currentProgress = currentProgress;
} }
@Override public DownloadEntity clone() throws CloneNotSupportedException { @Override public DownloadEntity clone() throws CloneNotSupportedException {
return (DownloadEntity) super.clone(); return (DownloadEntity) super.clone();
} }
public DownloadEntity() { public DownloadEntity() {
} }
@Override public int describeContents() { @Override public int describeContents() {
return 0; return 0;
} }
@Override public void writeToParcel(Parcel dest, int flags) { @Override public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.downloadUrl); dest.writeString(this.downloadUrl);
dest.writeString(this.downloadPath); dest.writeString(this.downloadPath);
dest.writeLong(this.completeTime); dest.writeLong(this.completeTime);
dest.writeLong(this.fileSize); dest.writeLong(this.fileSize);
dest.writeInt(this.state); dest.writeInt(this.state);
dest.writeByte(this.isDownloadComplete ? (byte) 1 : (byte) 0); dest.writeByte(this.isDownloadComplete ?
dest.writeLong(this.currentProgress); (byte) 1 :
dest.writeInt(this.failNum); (byte) 0);
} dest.writeLong(this.currentProgress);
dest.writeInt(this.failNum);
protected DownloadEntity(Parcel in) { }
this.downloadUrl = in.readString();
this.downloadPath = in.readString(); protected DownloadEntity(Parcel in) {
this.completeTime = in.readLong(); this.downloadUrl = in.readString();
this.fileSize = in.readLong(); this.downloadPath = in.readString();
this.state = in.readInt(); this.completeTime = in.readLong();
this.isDownloadComplete = in.readByte() != 0; this.fileSize = in.readLong();
this.currentProgress = in.readLong(); this.state = in.readInt();
this.failNum = in.readInt(); this.isDownloadComplete = in.readByte() != 0;
} this.currentProgress = in.readLong();
this.failNum = in.readInt();
public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() { }
@Override public DownloadEntity createFromParcel(Parcel source) {
return new DownloadEntity(source); public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() {
} @Override public DownloadEntity createFromParcel(Parcel source) {
return new DownloadEntity(source);
@Override public DownloadEntity[] newArray(int size) { }
return new DownloadEntity[size];
} @Override public DownloadEntity[] newArray(int size) {
}; return new DownloadEntity[size];
}
@Override public String toString() { };
return "DownloadEntity{" +
"downloadUrl='" + downloadUrl + '\'' + @Override public String toString() {
", downloadPath='" + downloadPath + '\'' + return "DownloadEntity{" +
", completeTime=" + completeTime + "downloadUrl='" + downloadUrl + '\'' +
", fileSize=" + fileSize + ", downloadPath='" + downloadPath + '\'' +
", state=" + state + ", completeTime=" + completeTime +
", isDownloadComplete=" + isDownloadComplete + ", fileSize=" + fileSize +
", currentProgress=" + currentProgress + ", state=" + state +
", failNum=" + failNum + ", isDownloadComplete=" + isDownloadComplete +
'}'; ", currentProgress=" + currentProgress +
} ", failNum=" + failNum +
'}';
}
} }

@ -3,8 +3,10 @@ package com.arialyy.downloadutil.help;
import android.content.res.Resources; import android.content.res.Resources;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.R; import com.arialyy.downloadutil.R;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import java.io.File; import java.io.File;
/** /**
@ -12,38 +14,38 @@ import java.io.File;
* 检查帮助类 * 检查帮助类
*/ */
public class CheckHelp { public class CheckHelp {
private static final String TAG = "CheckHelp"; private static final String TAG = "CheckHelp";
/** /**
* 检测下载实体是否合法 * 检测下载实体是否合法
* *
* @param entity 下载实体 * @param entity 下载实体
* @return 合法(true) * @return 合法(true)
*/ */
public static boolean checkDownloadEntity(DownloadEntity entity) { public static boolean checkDownloadEntity(DownloadEntity entity) {
if (entity == null) { if (entity == null) {
Log.w(TAG, Resources.getSystem().getString(R.string.error_entity_null)); Log.w(TAG, Resources.getSystem().getString(R.string.error_entity_null));
return false; return false;
} else if (TextUtils.isEmpty(entity.getDownloadUrl())) { } else if (TextUtils.isEmpty(entity.getDownloadUrl())) {
Log.w(TAG, Resources.getSystem().getString(R.string.error_download_url_null)); Log.w(TAG, Resources.getSystem().getString(R.string.error_download_url_null));
return false; return false;
} else if (TextUtils.isEmpty(entity.getFileName())) { } else if (TextUtils.isEmpty(entity.getFileName())) {
Log.w(TAG, Resources.getSystem().getString(R.string.error_file_name_null)); Log.w(TAG, Resources.getSystem().getString(R.string.error_file_name_null));
return false; return false;
} else if (TextUtils.isEmpty(entity.getDownloadPath())) { } else if (TextUtils.isEmpty(entity.getDownloadPath())) {
Log.w(TAG, Resources.getSystem().getString(R.string.error_file_name_null)); Log.w(TAG, Resources.getSystem().getString(R.string.error_download_path_null));
return false; return false;
} }
String fileName = entity.getFileName(); String fileName = entity.getFileName();
if (fileName.contains(" ")) { if (fileName.contains(" ")) {
fileName = fileName.replace(" ", "_"); fileName = fileName.replace(" ", "_");
} }
String dPath = entity.getDownloadPath(); String dPath = entity.getDownloadPath();
File file = new File(dPath); File file = new File(dPath);
if (file.isDirectory()) { if (file.isDirectory()) {
dPath += fileName; dPath += fileName;
entity.setDownloadPath(dPath); entity.setDownloadPath(dPath);
}
return true;
} }
return true;
}
} }

@ -0,0 +1,63 @@
package com.arialyy.downloadutil.help;
import android.os.Environment;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by lyy on 2016/9/27.
* 下载路径帮助类
*/
public class PathHelp {
/**
* 下载链接转换保存路径
*
* @param downloadUrl 下载链接
* @return 保存路径
*/
public static String urlconvertPath(String downloadUrl) {
return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey(
downloadUrl);
}
/**
* 字符串转换为hash码
*
* @param str
* @return
*/
public static String StringToHashKey(String str) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(str.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(str.hashCode());
}
return cacheKey;
}
/**
* 将普通字符串转换为16位进制字符串
*
* @param src
* @return
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (byte aSrc : src) {
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
}

@ -4,7 +4,9 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.downloadutil.util.Util; import com.arialyy.downloadutil.util.Util;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -17,176 +19,185 @@ import java.util.List;
* 所有数据库实体父类 * 所有数据库实体父类
*/ */
public class DbEntity { public class DbEntity {
private static final String TAG = "DbEntity"; private static final String TAG = "DbEntity";
private volatile static SQLiteDatabase mDb = null; private volatile static SQLiteDatabase mDb = null;
private volatile static DbUtil mUtil; private volatile static DbUtil mUtil;
private Context mContext; private Context mContext;
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
protected int rowID = -1; protected int rowID = -1;
protected DbEntity() { protected DbEntity() {
} }
public DbEntity(Context context) { public DbEntity(Context context) {
this(context, true); this(context, true);
} }
public DbEntity(Context context, boolean newTable) { public DbEntity(Context context, boolean newTable) {
mContext = context; mContext = context;
init(newTable); init(newTable);
} }
private void init(boolean newTable) { private void init(boolean newTable) {
if (mDb == null) {
synchronized (LOCK) {
if (mDb == null) { if (mDb == null) {
SqlHelper mHelper = new SqlHelper(mContext); synchronized (LOCK) {
mDb = mHelper.getWritableDatabase(); if (mDb == null) {
mUtil = DbUtil.getInstance(mDb); SqlHelper mHelper = new SqlHelper(mContext);
mDb = mHelper.getWritableDatabase();
mUtil = DbUtil.getInstance(mDb);
}
}
}
if (newTable && !mUtil.tableExists(this)) {
mUtil.createTable(this);
} }
}
} }
if (newTable && !mUtil.tableExists(this)) {
mUtil.createTable(this); /**
* 获取所有行的rowid
*/
public int[] getRowId() {
Cursor cursor = mUtil.getRowId(this);
int[] ids = new int[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
i++;
}
return ids;
} }
}
/**
/** * 获取rowid
* 获取所有行的rowid */
*/ public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) {
public int[] getRowId() { return mUtil.getRowId(this, wheres, values);
Cursor cursor = mUtil.getRowId(this);
int[] ids = new int[cursor.getCount()];
int i = 0;
while (cursor.moveToNext()) {
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
i++;
} }
return ids;
} /**
* 删除当前数据
/** */
* 获取rowid public void deleteData() {
*/ mUtil.delData(this, new Object[]{"rowid"}, new Object[]{rowID});
public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) { }
return mUtil.getRowId(this, wheres, values);
} /**
* 根据条件删除数据
/** */
* 删除当前数据 public void deleteData(@NonNull Object[] wheres, @NonNull Object[] values) {
*/ mUtil.delData(this, wheres, values);
public void deleteData() { }
mUtil.delData(this, new Object[] { "rowid" }, new Object[] { rowID });
} /**
* 修改数据
/** */
* 根据条件删除数据 public void update() {
*/ mUtil.modifyData(this);
public void deleteData(@NonNull Object[] wheres, @NonNull Object[] values) { }
mUtil.delData(this, wheres, values);
} /**
* 插入数据
/** */
* 修改数据 public void save() {
*/ mUtil.insertData(this);
public void update() { }
mUtil.modifyData(this);
} /**
* 查询所有数据
/** *
* 插入数据 * @return 没有数据返回null
*/ */
public void save() { public <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
mUtil.insertData(this); Cursor cursor = mUtil.findAllData(this);
} return cursor.getCount() > 0 ?
newInstanceEntity(clazz, cursor) :
/** null;
* 查询所有数据 }
*
* @return 没有数据返回null /**
*/ * 查询一组数据
public <T extends DbEntity> List<T> findAllData(Class<T> clazz) { *
Cursor cursor = mUtil.findAllData(this); * @return 没有数据返回null
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; */
} public <T extends DbEntity> List<T> findDatas(Class<T> clazz, @NonNull Object[] wheres,
@NonNull Object[] values) {
/** Cursor cursor = mUtil.findData(this, wheres, values);
* 查询一组数据 return cursor.getCount() > 0 ?
* newInstanceEntity(clazz, cursor) :
* @return 没有数据返回null null;
*/ }
public <T extends DbEntity> List<T> findDatas(Class<T> clazz, @NonNull Object[] wheres,
@NonNull Object[] values) { /**
Cursor cursor = mUtil.findData(this, wheres, values); * 查询一行数据
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; *
} * @return 没有数据返回null
*/
/** public <T extends DbEntity> T findData(Class<T> clazz, @NonNull Object[] wheres,
* 查询一行数据 @NonNull Object[] values) {
* Cursor cursor = mUtil.findData(this, wheres, values);
* @return 没有数据返回null return cursor.getCount() > 0 ?
*/ newInstanceEntity(clazz, cursor).get(0) :
public <T extends DbEntity> T findData(Class<T> clazz, @NonNull Object[] wheres, null;
@NonNull Object[] values) { }
Cursor cursor = mUtil.findData(this, wheres, values);
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor).get(0) : null; /**
} * 根据数据游标创建一个具体的对象
*/
/** private <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) {
* 根据数据游标创建一个具体的对象 Field[] fields = Util.getFields(clazz);
*/ List<T> entitys = new ArrayList<>();
private <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) { if (fields != null && fields.length > 0) {
Field[] fields = Util.getFields(clazz); try {
List<T> entitys = new ArrayList<>(); while (cursor.moveToNext()) {
if (fields != null && fields.length > 0) { Class[] paramTypes = {Context.class,
try { boolean.class};
while (cursor.moveToNext()) { Object[] params = {mContext,
Class[] paramTypes = { Context.class, boolean.class }; false};
Object[] params = { mContext, false }; Constructor<T> con = clazz.getConstructor(paramTypes);
Constructor<T> con = clazz.getConstructor(paramTypes); T entity = con.newInstance(params);
T entity = con.newInstance(params); for (Field field : fields) {
for (Field field : fields) { field.setAccessible(true);
field.setAccessible(true); Ignore ignore = field.getAnnotation(Ignore.class);
Ignore ignore = field.getAnnotation(Ignore.class); if (ignore != null && ignore.value()) {
if (ignore != null && ignore.value()) { continue;
continue; }
} Class<?> type = field.getType();
Class<?> type = field.getType(); int column = cursor.getColumnIndex(field.getName());
int column = cursor.getColumnIndex(field.getName()); if (type == String.class) {
if (type == String.class) { field.set(entity, cursor.getString(column));
field.set(entity, cursor.getString(column)); } else if (type == int.class || type == Integer.class) {
} else if (type == int.class || type == Integer.class) { field.setInt(entity, cursor.getInt(column));
field.setInt(entity, cursor.getInt(column)); } else if (type == float.class || type == Float.class) {
} else if (type == float.class || type == Float.class) { field.setFloat(entity, cursor.getFloat(column));
field.setFloat(entity, cursor.getFloat(column)); } else if (type == double.class || type == Double.class) {
} else if (type == double.class || type == Double.class) { field.setDouble(entity, cursor.getDouble(column));
field.setDouble(entity, cursor.getDouble(column)); } else if (type == long.class || type == Long.class) {
} else if (type == long.class || type == Long.class) { field.setLong(entity, cursor.getLong(column));
field.setLong(entity, cursor.getLong(column)); } else if (type == boolean.class || type == Boolean.class) {
} else if (type == boolean.class || type == Boolean.class) { field.setBoolean(entity,
field.setBoolean(entity, !cursor.getString(column).equalsIgnoreCase("false")); !cursor.getString(column).equalsIgnoreCase("false"));
} else if (type == java.util.Date.class || type == java.sql.Date.class) { } else if (type == java.util.Date.class || type == java.sql.Date.class) {
field.set(entity, new Date(cursor.getString(column))); field.set(entity, new Date(cursor.getString(column)));
} else if (type == byte[].class) { } else if (type == byte[].class) {
field.set(entity, cursor.getBlob(column)); field.set(entity, cursor.getBlob(column));
}
// field.set(entity, cursor.getColumnIndex("entity_id"));
}
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
entitys.add(entity);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} }
// field.set(entity, cursor.getColumnIndex("entity_id"));
}
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
entitys.add(entity);
} }
} catch (InstantiationException e) { cursor.close();
e.printStackTrace(); return entitys;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} }
cursor.close();
return entitys;
}
} }

@ -4,7 +4,9 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.util.Util; import com.arialyy.downloadutil.util.Util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
/** /**
@ -12,311 +14,326 @@ import java.lang.reflect.Field;
* 数据库操作工具 * 数据库操作工具
*/ */
public class DbUtil { public class DbUtil {
private static final String TAG = "DbUtil"; private static final String TAG = "DbUtil";
private volatile static DbUtil mDbUtil = null; private volatile static DbUtil mDbUtil = null;
private int CREATE_TABLE = 0; private int CREATE_TABLE = 0;
private int TABLE_EXISTS = 1; private int TABLE_EXISTS = 1;
private int INSERT_DATA = 2; private int INSERT_DATA = 2;
private int MODIFY_DATA = 3; private int MODIFY_DATA = 3;
private int FIND_DATA = 4; private int FIND_DATA = 4;
private int FIND_ALL_DATA = 5; private int FIND_ALL_DATA = 5;
private int DEL_DATA = 6; private int DEL_DATA = 6;
private int ROW_ID = 7; private int ROW_ID = 7;
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
private SQLiteDatabase mDb; private SQLiteDatabase mDb;
private DbUtil() { private DbUtil() {
} }
private DbUtil(SQLiteDatabase db) { private DbUtil(SQLiteDatabase db) {
mDb = db; mDb = db;
} }
protected static DbUtil getInstance(SQLiteDatabase db) { protected static DbUtil getInstance(SQLiteDatabase db) {
if (mDbUtil == null) {
synchronized (LOCK) {
if (mDbUtil == null) { if (mDbUtil == null) {
mDbUtil = new DbUtil(db); synchronized (LOCK) {
if (mDbUtil == null) {
mDbUtil = new DbUtil(db);
}
}
} }
} return mDbUtil;
} }
return mDbUtil;
}
/** /**
* 删除某条数据 * 删除某条数据
*/ */
protected void delData(DbEntity dbEntity, @NonNull Object[] wheres, @NonNull Object[] values) { protected void delData(DbEntity dbEntity, @NonNull Object[] wheres, @NonNull Object[] values) {
if (wheres.length <= 0 || values.length <= 0) { if (wheres.length <= 0 || values.length <= 0) {
Log.e(TAG, "输入删除条件"); Log.e(TAG, "输入删除条件");
return; return;
} else if (wheres.length != values.length) { } else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等"); Log.e(TAG, "key 和 vaule 长度不相等");
return; return;
}
StringBuilder sb = new StringBuilder();
sb.append("DELETE FROM ").append(Util.getClassName(dbEntity)).append(" WHERE ");
int i = 0;
for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ? "" : ",");
i++;
}
print(DEL_DATA, sb.toString());
mDb.execSQL(sb.toString());
}
/**
* 修改某行数据
*/
protected void modifyData(DbEntity dbEntity) {
Class<?> clazz = dbEntity.getClass();
Field[] fields = Util.getFields(clazz);
if (fields != null && fields.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("UPDATE ").append(Util.getClassName(dbEntity)).append(" SET ");
int i = 0;
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
sb.append(i > 0 ? ", " : ""); StringBuilder sb = new StringBuilder();
try { sb.append("DELETE FROM ").append(Util.getClassName(dbEntity)).append(" WHERE ");
sb.append(field.getName()) int i = 0;
.append(" = '") for (Object where : wheres) {
.append(field.get(dbEntity).toString()) sb.append(where).append("=").append("'").append(values[i]).append("'");
.append("'"); sb.append(i >= wheres.length - 1 ?
} catch (IllegalAccessException e) { "" :
e.printStackTrace(); ",");
i++;
} }
i++; print(DEL_DATA, sb.toString());
} mDb.execSQL(sb.toString());
print(MODIFY_DATA, sb.toString());
mDb.execSQL(sb.toString());
} }
}
/**
* 遍历所有数据
*/
protected Cursor findAllData(DbEntity dbEntity) {
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity));
print(FIND_ALL_DATA, sb.toString());
return mDb.rawQuery(sb.toString(), null);
}
/** /**
* 条件查寻数据 * 修改某行数据
*/ */
protected Cursor findData(DbEntity dbEntity, @NonNull Object[] wheres, @NonNull Object[] values) { protected void modifyData(DbEntity dbEntity) {
if (wheres.length <= 0 || values.length <= 0) { Class<?> clazz = dbEntity.getClass();
Log.e(TAG, "请输入查询条件"); Field[] fields = Util.getFields(clazz);
return null; if (fields != null && fields.length > 0) {
} else if (wheres.length != values.length) { StringBuilder sb = new StringBuilder();
Log.e(TAG, "key 和 vaule 长度不相等"); sb.append("UPDATE ").append(Util.getClassName(dbEntity)).append(" SET ");
return null; int i = 0;
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
}
sb.append(i > 0 ?
", " :
"");
try {
sb.append(field.getName())
.append(" = '")
.append(field.get(dbEntity).toString())
.append("'");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
i++;
}
print(MODIFY_DATA, sb.toString());
mDb.execSQL(sb.toString());
}
} }
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity)).append(" where "); /**
int i = 0; * 遍历所有数据
for (Object where : wheres) { */
sb.append(where).append("=").append("'").append(values[i]).append("'"); protected Cursor findAllData(DbEntity dbEntity) {
sb.append(i >= wheres.length - 1 ? "" : ", "); StringBuilder sb = new StringBuilder();
i++; sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity));
print(FIND_ALL_DATA, sb.toString());
return mDb.rawQuery(sb.toString(), null);
} }
print(FIND_DATA, sb.toString());
return mDb.rawQuery(sb.toString(), null);
}
/** /**
* 插入数据 * 条件查寻数据
*/ */
protected void insertData(DbEntity dbEntity) { protected Cursor findData(DbEntity dbEntity, @NonNull Object[] wheres,
Class<?> clazz = dbEntity.getClass(); @NonNull Object[] values) {
Field[] fields = Util.getFields(clazz); if (wheres.length <= 0 || values.length <= 0) {
if (fields != null && fields.length > 0) { Log.e(TAG, "请输入查询条件");
StringBuilder sb = new StringBuilder(); return null;
sb.append("INSERT INTO ").append(Util.getClassName(dbEntity)).append("("); } else if (wheres.length != values.length) {
int i = 0; Log.e(TAG, "key 和 vaule 长度不相等");
for (Field field : fields) { return null;
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
sb.append(i > 0 ? ", " : ""); StringBuilder sb = new StringBuilder();
sb.append(field.getName()); sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity)).append(" where ");
i++; int i = 0;
} for (Object where : wheres) {
sb.append(") VALUES ("); sb.append(where).append("=").append("'").append(values[i]).append("'");
i = 0; sb.append(i >= wheres.length - 1 ?
for (Field field : fields) { "" :
field.setAccessible(true); ", ");
Ignore ignore = field.getAnnotation(Ignore.class); i++;
if (ignore != null && ignore.value()) {
continue;
} }
sb.append(i > 0 ? ", " : ""); print(FIND_DATA, sb.toString());
sb.append("'"); return mDb.rawQuery(sb.toString(), null);
try {
sb.append(field.get(dbEntity)).append("'");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
i++;
}
sb.append(")");
print(INSERT_DATA, sb.toString());
mDb.execSQL(sb.toString());
} }
}
/** /**
* 查找某张表是否存在 * 插入数据
*/ */
protected boolean tableExists(DbEntity dbEntity) { protected void insertData(DbEntity dbEntity) {
Cursor cursor = null; Class<?> clazz = dbEntity.getClass();
try { Field[] fields = Util.getFields(clazz);
StringBuilder sb = new StringBuilder(); if (fields != null && fields.length > 0) {
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='"); StringBuilder sb = new StringBuilder();
sb.append(Util.getClassName(dbEntity)); sb.append("INSERT INTO ").append(Util.getClassName(dbEntity)).append("(");
sb.append("'"); int i = 0;
print(TABLE_EXISTS, sb.toString()); for (Field field : fields) {
cursor = mDb.rawQuery(sb.toString(), null); field.setAccessible(true);
if (cursor != null && cursor.moveToNext()) { Ignore ignore = field.getAnnotation(Ignore.class);
int count = cursor.getInt(0); if (ignore != null && ignore.value()) {
if (count > 0) { continue;
return true; }
sb.append(i > 0 ?
", " :
"");
sb.append(field.getName());
i++;
}
sb.append(") VALUES (");
i = 0;
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
}
sb.append(i > 0 ?
", " :
"");
sb.append("'");
try {
sb.append(field.get(dbEntity)).append("'");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
i++;
}
sb.append(")");
print(INSERT_DATA, sb.toString());
mDb.execSQL(sb.toString());
} }
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) cursor.close();
} }
return false;
}
/** /**
* 创建表 * 查找某张表是否存在
*/ */
protected void createTable(DbEntity dbEntity) { protected boolean tableExists(DbEntity dbEntity) {
Field[] fields = Util.getFields(dbEntity.getClass()); Cursor cursor = null;
if (fields != null && fields.length > 0) { try {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("create table ").append(Util.getClassName(dbEntity)).append("("); sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='");
int i = 0; sb.append(Util.getClassName(dbEntity));
int ignoreNum = 0; sb.append("'");
for (Field field : fields) { print(TABLE_EXISTS, sb.toString());
i++; cursor = mDb.rawQuery(sb.toString(), null);
field.setAccessible(true); if (cursor != null && cursor.moveToNext()) {
Ignore ignore = field.getAnnotation(Ignore.class); int count = cursor.getInt(0);
if (ignore != null && ignore.value()) { if (count > 0) {
ignoreNum++; return true;
continue; }
} }
sb.append(field.getName()); } catch (Exception e) {
Class<?> type = field.getType(); e.printStackTrace();
if (type == String.class) { } finally {
sb.append(" varchar"); if (cursor != null) cursor.close();
} else if (type == int.class || type == Integer.class) {
sb.append(" interger");
} else if (type == float.class || type == Float.class) {
sb.append(" float");
} else if (type == double.class || type == Double.class) {
sb.append(" double");
} else if (type == long.class || type == Long.class) {
sb.append(" bigint");
} else if (type == boolean.class || type == Boolean.class) {
sb.append(" boolean");
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" data");
} else {
sb.append(" blob");
} }
sb.append(i >= fields.length - ignoreNum - 1 ? "" : ", "); return false;
}
sb.append(");");
print(CREATE_TABLE, sb.toString());
mDb.execSQL(sb.toString());
} }
}
/** /**
* 打印数据库日志 * 创建表
* */
* @param type {@link DbUtil} protected void createTable(DbEntity dbEntity) {
*/ Field[] fields = Util.getFields(dbEntity.getClass());
private void print(int type, String sql) { if (fields != null && fields.length > 0) {
String str = ""; StringBuilder sb = new StringBuilder();
switch (type) { sb.append("create table ").append(Util.getClassName(dbEntity)).append("(");
case 0: int i = 0;
str = "创建表 >>>> "; int ignoreNum = 0;
break; for (Field field : fields) {
case 1: i++;
str = "表是否存在 >>>> "; field.setAccessible(true);
break; Ignore ignore = field.getAnnotation(Ignore.class);
case 2: if (ignore != null && ignore.value()) {
str = "插入数据 >>>> "; ignoreNum++;
break; continue;
case 3: }
str = "修改数据 >>>> "; sb.append(field.getName());
break; Class<?> type = field.getType();
case 4: if (type == String.class) {
str = "查询一行数据 >>>> "; sb.append(" varchar");
break; } else if (type == int.class || type == Integer.class) {
case 5: sb.append(" interger");
str = "遍历整个数据库 >>>> "; } else if (type == float.class || type == Float.class) {
break; sb.append(" float");
} else if (type == double.class || type == Double.class) {
sb.append(" double");
} else if (type == long.class || type == Long.class) {
sb.append(" bigint");
} else if (type == boolean.class || type == Boolean.class) {
sb.append(" boolean");
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" data");
} else {
sb.append(" blob");
}
sb.append(i >= fields.length - ignoreNum - 1 ?
"" :
", ");
}
sb.append(");");
print(CREATE_TABLE, sb.toString());
mDb.execSQL(sb.toString());
}
} }
Log.v(TAG, str + sql);
}
/** /**
* 关闭数据库 * 打印数据库日志
*/ *
protected void close() { * @param type {@link DbUtil}
if (mDb != null) { */
mDb.close(); private void print(int type, String sql) {
String str = "";
switch (type) {
case 0:
str = "创建表 >>>> ";
break;
case 1:
str = "表是否存在 >>>> ";
break;
case 2:
str = "插入数据 >>>> ";
break;
case 3:
str = "修改数据 >>>> ";
break;
case 4:
str = "查询一行数据 >>>> ";
break;
case 5:
str = "遍历整个数据库 >>>> ";
break;
}
Log.v(TAG, str + sql);
} }
}
/** /**
* 获取所有行Id * 关闭数据库
*/ */
protected Cursor getRowId(DbEntity dbEntity) { protected void close() {
StringBuilder sb = new StringBuilder(); if (mDb != null) {
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity)); mDb.close();
return mDb.rawQuery(sb.toString(), null); }
} }
/** /**
* 获取行Id * 获取所有行Id
*/ */
protected int getRowId(DbEntity dbEntity, Object[] wheres, Object[] values) { protected Cursor getRowId(DbEntity dbEntity) {
if (wheres.length <= 0 || values.length <= 0) { StringBuilder sb = new StringBuilder();
Log.e(TAG, "请输入删除条件"); sb.append("SELECT rowid, * FROM ").append(Util.getClassName(dbEntity));
return -1; return mDb.rawQuery(sb.toString(), null);
} else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等");
return -1;
} }
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid FROM ").append(Util.getClassName(dbEntity)).append(" WHERE "); /**
int i = 0; * 获取行Id
for (Object where : wheres) { */
sb.append(where).append("=").append("'").append(values[i]).append("'"); protected int getRowId(DbEntity dbEntity, Object[] wheres, Object[] values) {
sb.append(i >= wheres.length - 1 ? "" : ","); if (wheres.length <= 0 || values.length <= 0) {
i++; Log.e(TAG, "请输入删除条件");
return -1;
} else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等");
return -1;
}
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid FROM ").append(Util.getClassName(dbEntity)).append(" WHERE ");
int i = 0;
for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ?
"" :
",");
i++;
}
print(ROW_ID, sb.toString());
Cursor c = mDb.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
return id;
} }
print(ROW_ID, sb.toString());
Cursor c = mDb.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
return id;
}
} }

@ -10,5 +10,5 @@ import java.lang.annotation.Target;
* 表ID字段指定 * 表ID字段指定
*/ */
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id { @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id {
int value() default -1; int value() default -1;
} }

@ -10,5 +10,5 @@ import java.lang.annotation.Target;
* 忽略某个字段 * 忽略某个字段
*/ */
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Ignore { @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Ignore {
boolean value() default false; boolean value() default false;
} }

@ -10,27 +10,27 @@ import android.text.TextUtils;
* sql帮助类 * sql帮助类
*/ */
public class SqlHelper extends SQLiteOpenHelper { public class SqlHelper extends SQLiteOpenHelper {
protected static String DB_NAME; protected static String DB_NAME;
protected static int VERSION = -1; protected static int VERSION = -1;
static { static {
if (TextUtils.isEmpty(DB_NAME)) { if (TextUtils.isEmpty(DB_NAME)) {
DB_NAME = "AriaLyyDb"; DB_NAME = "AriaLyyDb";
} }
if (VERSION == -1) { if (VERSION == -1) {
VERSION = 1; VERSION = 1;
}
} }
}
public SqlHelper(Context context) { public SqlHelper(Context context) {
super(context, DB_NAME, null, VERSION); super(context, DB_NAME, null, VERSION);
} }
@Override public void onCreate(SQLiteDatabase db) { @Override public void onCreate(SQLiteDatabase db) {
} }
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
} }
} }

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -18,450 +19,444 @@ import java.util.Properties;
* 下载工具类 * 下载工具类
*/ */
public class DownLoadUtil { public class DownLoadUtil {
private static final String TAG = "DownLoadUtil"; private static final String TAG = "DownLoadUtil";
//下载监听 //下载监听
private IDownloadListener mListener; private IDownloadListener mListener;
/** /**
* 线程数 * 线程数
*/ */
private static final int THREAD_NUM = 3; private static final int THREAD_NUM = 3;
/** /**
* 已经完成下载任务的线程数量 * 已经完成下载任务的线程数量
*/ */
private int mCompleteThreadNum = 0; private int mCompleteThreadNum = 0;
private long mCurrentLocation; private long mCurrentLocation;
private boolean isDownloading = false; private boolean isDownloading = false;
private boolean isStop = false; private boolean isStop = false;
private boolean isCancel = false; private boolean isCancel = false;
private static final int TIME_OUT = 5000; //超时时间 private static final int TIME_OUT = 5000; //超时时间
boolean isNewTask = true; boolean isNewTask = true;
private int mCancelNum = 0; private int mCancelNum = 0;
private int mStopNum = 0; private int mStopNum = 0;
public DownLoadUtil() { public DownLoadUtil() {
} }
public IDownloadListener getListener() { public IDownloadListener getListener() {
return mListener; return mListener;
} }
/** /**
* 获取当前下载位置 * 获取当前下载位置
*/ */
public long getCurrentLocation() { public long getCurrentLocation() {
return mCurrentLocation; return mCurrentLocation;
} }
public boolean isDownloading() { public boolean isDownloading() {
return isDownloading; return isDownloading;
} }
/** /**
* 取消下载 * 取消下载
*/ */
public void cancelDownload() { public void cancelDownload() {
isCancel = true; isCancel = true;
} }
/** /**
* 停止下载 * 停止下载
*/ */
public void stopDownload() { public void stopDownload() {
isStop = true; isStop = true;
}
/**
* 多线程断点续传下载文件暂停和继续
*
* @param context 必须添加该参数不能使用全局变量的context
* @param downloadUrl 下载路径
* @param filePath 保存路径
* @param downloadListener 下载进度监听 {@link DownloadListener}
*/
public void download(final Context context, @NonNull final String downloadUrl,
@NonNull final String filePath, @NonNull final IDownloadListener downloadListener) {
isDownloading = true;
mCurrentLocation = 0;
isStop = false;
isCancel = false;
mCancelNum = 0;
mStopNum = 0;
final File dFile = new File(filePath);
//读取已完成的线程数
final File configFile =
new File(context.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
try {
if (!configFile.exists()) { //记录文件被删除,则重新下载
isNewTask = true;
Util.createFile(configFile.getPath());
} else {
isNewTask = !dFile.exists();
}
} catch (Exception e) {
e.printStackTrace();
failDownload("下载失败,记录文件被删除");
return;
} }
new Thread(new Runnable() {
@Override public void run() { /**
* 多线程断点续传下载文件暂停和继续
*
* @param context 必须添加该参数不能使用全局变量的context
* @param downloadUrl 下载路径
* @param filePath 保存路径
* @param downloadListener 下载进度监听 {@link DownloadListener}
*/
public void download(final Context context, @NonNull final String downloadUrl,
@NonNull final String filePath,
@NonNull final IDownloadListener downloadListener) {
isDownloading = true;
mCurrentLocation = 0;
isStop = false;
isCancel = false;
mCancelNum = 0;
mStopNum = 0;
final File dFile = new File(filePath);
//读取已完成的线程数
final File configFile = new File(
context.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
try { try {
mListener = downloadListener; if (!configFile.exists()) { //记录文件被删除,则重新下载
URL url = new URL(downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8");
conn.setConnectTimeout(TIME_OUT * 4);
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)");
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, */*");
conn.connect();
int len = conn.getContentLength();
if (len < 0) { //网络被劫持时会出现这个问题
failDownload("下载失败,网络被劫持");
return;
}
int code = conn.getResponseCode();
if (code == 200) {
int fileLength = conn.getContentLength();
//必须建一个文件
Util.createFile(filePath);
RandomAccessFile file = new RandomAccessFile(filePath, "rwd");
//设置文件长度
file.setLength(fileLength);
mListener.onPreDownload(conn);
//分配每条线程的下载区间
Properties pro = null;
pro = Util.loadConfig(configFile);
if (pro.isEmpty()) {
isNewTask = true;
} else {
for (int i = 0; i < THREAD_NUM; i++) {
if (pro.getProperty(dFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
continue;
}
isNewTask = true;
break;
}
}
}
int blockSize = fileLength / THREAD_NUM;
SparseArray<Thread> tasks = new SparseArray<>();
int[] recordL = new int[THREAD_NUM];
int rl = 0;
for (int i = 0; i < THREAD_NUM; i++) {
recordL[i] = -1;
}
for (int i = 0; i < THREAD_NUM; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
mCurrentLocation += endL - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
mCompleteThreadNum++;
mStopNum++;
mCancelNum++;
if (mCompleteThreadNum == THREAD_NUM) {
if (configFile.exists()) {
configFile.delete();
}
mListener.onComplete();
isDownloading = false;
return;
}
continue;
}
//分配下载位置
Object record = pro.getProperty(dFile.getName() + "_record_" + i);
if (!isNewTask
&& record != null
&& Long.parseLong(record + "") > 0) { //如果有记录,则恢复下载
Long r = Long.parseLong(record + "");
mCurrentLocation += r - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
mListener.onChildResume(r);
startL = r;
recordL[rl] = i;
rl++;
} else {
isNewTask = true; isNewTask = true;
} Util.createFile(configFile.getPath());
if (isNewTask) {
recordL[rl] = i;
rl++;
}
if (i == (THREAD_NUM - 1)) {
endL = fileLength;//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
}
DownloadEntity entity =
new DownloadEntity(context, fileLength, downloadUrl, dFile, i, startL, endL);
DownLoadTask task = new DownLoadTask(entity);
tasks.put(i, new Thread(task));
}
if (mCurrentLocation > 0) {
mListener.onResume(mCurrentLocation);
} else { } else {
mListener.onStart(mCurrentLocation); isNewTask = !dFile.exists();
} }
for (int l : recordL) { } catch (Exception e) {
if (l == -1) continue; e.printStackTrace();
Thread task = tasks.get(l); failDownload("下载失败,记录文件被删除");
if (task != null) { return;
task.start();
}
}
} else {
failDownload("下载失败,返回码:" + code);
}
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ downloadUrl
+ "】\n【filePath:"
+ filePath
+ "】"
+ Util.getPrintException(e));
} }
} new Thread(new Runnable() {
}).start(); @Override public void run() {
} try {
mListener = downloadListener;
private void failDownload(String msg) { URL url = new URL(downloadUrl);
Log.e(TAG, msg); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
isDownloading = false; conn.setRequestMethod("GET");
stopDownload(); conn.setRequestProperty("Charset", "UTF-8");
mListener.onFail(); conn.setConnectTimeout(TIME_OUT * 4);
System.gc(); 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)");
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, */*");
* 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了 conn.connect();
*/ int len = conn.getContentLength();
private class DownLoadTask implements Runnable { if (len < 0) { //网络被劫持时会出现这个问题
private static final String TAG = "DownLoadTask"; failDownload("下载失败,网络被劫持");
private DownloadEntity dEntity; return;
private String configFPath; }
int code = conn.getResponseCode();
public DownLoadTask(DownloadEntity downloadInfo) { if (code == 200) {
this.dEntity = downloadInfo; int fileLength = conn.getContentLength();
configFPath = dEntity.context.getFilesDir().getPath() //必须建一个文件
+ "/temp/" Util.createFile(filePath);
+ dEntity.tempFile.getName() RandomAccessFile file = new RandomAccessFile(filePath, "rwd");
+ ".properties"; //设置文件长度
file.setLength(fileLength);
mListener.onPreDownload(conn);
//分配每条线程的下载区间
Properties pro = null;
pro = Util.loadConfig(configFile);
if (pro.isEmpty()) {
isNewTask = true;
} else {
for (int i = 0; i < THREAD_NUM; i++) {
if (pro.getProperty(dFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
continue;
}
isNewTask = true;
break;
}
}
}
int blockSize = fileLength / THREAD_NUM;
SparseArray<Thread> tasks = new SparseArray<>();
int[] recordL = new int[THREAD_NUM];
int rl = 0;
for (int i = 0; i < THREAD_NUM; i++) {
recordL[i] = -1;
}
for (int i = 0; i < THREAD_NUM; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
mCurrentLocation += endL - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
mCompleteThreadNum++;
mStopNum++;
mCancelNum++;
if (mCompleteThreadNum == THREAD_NUM) {
if (configFile.exists()) {
configFile.delete();
}
mListener.onComplete();
isDownloading = false;
return;
}
continue;
}
//分配下载位置
Object record = pro.getProperty(dFile.getName() + "_record_" + i);
if (!isNewTask && record != null && Long.parseLong(
record + "") > 0) { //如果有记录,则恢复下载
Long r = Long.parseLong(record + "");
mCurrentLocation += r - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
mListener.onChildResume(r);
startL = r;
recordL[rl] = i;
rl++;
} else {
isNewTask = true;
}
if (isNewTask) {
recordL[rl] = i;
rl++;
}
if (i == (THREAD_NUM - 1)) {
endL = fileLength;//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
}
DownloadEntity entity = new DownloadEntity(context, fileLength,
downloadUrl, dFile, i, startL, endL);
DownLoadTask task = new DownLoadTask(entity);
tasks.put(i, new Thread(task));
}
if (mCurrentLocation > 0) {
mListener.onResume(mCurrentLocation);
} else {
mListener.onStart(mCurrentLocation);
}
for (int l : recordL) {
if (l == -1) continue;
Thread task = tasks.get(l);
if (task != null) {
task.start();
}
}
} else {
failDownload("下载失败,返回码:" + code);
}
} catch (IOException e) {
failDownload(
"下载失败【downloadUrl:" + downloadUrl + "】\n【filePath:" + filePath + "】" + Util
.getPrintException(e));
}
}
}).start();
} }
@Override public void run() { private void failDownload(String msg) {
long currentLocation = 0; Log.e(TAG, msg);
try {
Log.d(TAG, "线程_"
+ dEntity.threadId
+ "_正在下载【"
+ "开始位置 : "
+ dEntity.startLocation
+ ",结束位置:"
+ dEntity.endLocation
+ "】");
URL url = new URL(dEntity.downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//在头里面请求下载开始位置和结束位置
conn.setRequestProperty("Range",
"bytes=" + dEntity.startLocation + "-" + dEntity.endLocation);
conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8");
conn.setConnectTimeout(TIME_OUT * 4);
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)");
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, */*");
conn.setReadTimeout(TIME_OUT * 24); //设置读取流的等待时间,必须设置该参数
InputStream is = conn.getInputStream();
//创建可设置位置的文件
RandomAccessFile file = new RandomAccessFile(dEntity.tempFile, "rwd");
//设置每条线程写入文件的位置
file.seek(dEntity.startLocation);
byte[] buffer = new byte[1024];
int len;
//当前子线程的下载位置
currentLocation = dEntity.startLocation;
while ((len = is.read(buffer)) != -1) {
if (isCancel) {
Log.d(TAG, "++++++++++ thread_" + dEntity.threadId + "_cancel ++++++++++");
break;
}
if (isStop) {
break;
}
//把下载数据数据写入文件
file.write(buffer, 0, len);
synchronized (DownLoadUtil.this) {
mCurrentLocation += len;
mListener.onProgress(mCurrentLocation);
}
currentLocation += len;
}
file.close();
is.close();
if (isCancel) {
synchronized (DownLoadUtil.this) {
mCancelNum++;
if (mCancelNum == THREAD_NUM) {
File configFile = new File(configFPath);
if (configFile.exists()) {
configFile.delete();
}
if (dEntity.tempFile.exists()) {
dEntity.tempFile.delete();
}
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
isDownloading = false;
mListener.onCancel();
System.gc();
}
}
return;
}
//停止状态不需要删除记录文件
if (isStop) {
synchronized (DownLoadUtil.this) {
mStopNum++;
String location = String.valueOf(currentLocation);
Log.i(TAG,
"thread_" + dEntity.threadId + "_stop, stop location ==> " + currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
if (mStopNum == THREAD_NUM) {
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
isDownloading = false;
mListener.onStop(mCurrentLocation);
System.gc();
}
}
return;
}
Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕");
writeConfig(dEntity.tempFile.getName() + "_state_" + dEntity.threadId, 1 + "");
mListener.onChildComplete(dEntity.endLocation);
mCompleteThreadNum++;
if (mCompleteThreadNum == THREAD_NUM) {
File configFile = new File(configFPath);
if (configFile.exists()) {
configFile.delete();
}
isDownloading = false;
mListener.onComplete();
System.gc();
}
} catch (MalformedURLException e) {
e.printStackTrace();
isDownloading = false; isDownloading = false;
synchronized (DownLoadUtil.this) { stopDownload();
try { mListener.onFail();
String location = String.valueOf(currentLocation); System.gc();
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location); }
failDownload("下载链接异常");
} catch (IOException e1) { /**
e1.printStackTrace(); * 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了
} */
private class DownLoadTask implements Runnable {
private static final String TAG = "DownLoadTask";
private DownloadEntity dEntity;
private String configFPath;
public DownLoadTask(DownloadEntity downloadInfo) {
this.dEntity = downloadInfo;
configFPath = dEntity.context.getFilesDir()
.getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties";
} }
} catch (IOException e) {
synchronized (DownLoadUtil.this) { @Override public void run() {
try { long currentLocation = 0;
String location = String.valueOf(currentLocation); try {
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location); Log.d(TAG,
failDownload("下载失败【" + dEntity.downloadUrl + "】" + Util.getPrintException(e)); "线程_" + dEntity.threadId + "_正在下载【" + "开始位置 : " + dEntity.startLocation + ",结束位置:" + dEntity.endLocation + "】");
} catch (IOException e1) { URL url = new URL(dEntity.downloadUrl);
e1.printStackTrace(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
} //在头里面请求下载开始位置和结束位置
conn.setRequestProperty("Range",
"bytes=" + dEntity.startLocation + "-" + dEntity.endLocation);
conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8");
conn.setConnectTimeout(TIME_OUT * 4);
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)");
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, */*");
conn.setReadTimeout(TIME_OUT * 24); //设置读取流的等待时间,必须设置该参数
InputStream is = conn.getInputStream();
//创建可设置位置的文件
RandomAccessFile file = new RandomAccessFile(dEntity.tempFile, "rwd");
//设置每条线程写入文件的位置
file.seek(dEntity.startLocation);
byte[] buffer = new byte[1024];
int len;
//当前子线程的下载位置
currentLocation = dEntity.startLocation;
while ((len = is.read(buffer)) != -1) {
if (isCancel) {
Log.d(TAG, "++++++++++ thread_" + dEntity.threadId + "_cancel ++++++++++");
break;
}
if (isStop) {
break;
}
//把下载数据数据写入文件
file.write(buffer, 0, len);
synchronized (DownLoadUtil.this) {
mCurrentLocation += len;
mListener.onProgress(mCurrentLocation);
}
currentLocation += len;
}
file.close();
is.close();
if (isCancel) {
synchronized (DownLoadUtil.this) {
mCancelNum++;
if (mCancelNum == THREAD_NUM) {
File configFile = new File(configFPath);
if (configFile.exists()) {
configFile.delete();
}
if (dEntity.tempFile.exists()) {
dEntity.tempFile.delete();
}
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
isDownloading = false;
mListener.onCancel();
System.gc();
}
}
return;
}
//停止状态不需要删除记录文件
if (isStop) {
synchronized (DownLoadUtil.this) {
mStopNum++;
String location = String.valueOf(currentLocation);
Log.i(TAG,
"thread_" + dEntity.threadId + "_stop, stop location ==> " + currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId,
location);
if (mStopNum == THREAD_NUM) {
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
isDownloading = false;
mListener.onStop(mCurrentLocation);
System.gc();
}
}
return;
}
Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕");
writeConfig(dEntity.tempFile.getName() + "_state_" + dEntity.threadId, 1 + "");
mListener.onChildComplete(dEntity.endLocation);
mCompleteThreadNum++;
if (mCompleteThreadNum == THREAD_NUM) {
File configFile = new File(configFPath);
if (configFile.exists()) {
configFile.delete();
}
isDownloading = false;
mListener.onComplete();
System.gc();
}
} catch (MalformedURLException e) {
e.printStackTrace();
isDownloading = false;
synchronized (DownLoadUtil.this) {
try {
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId,
location);
failDownload("下载链接异常");
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (IOException e) {
synchronized (DownLoadUtil.this) {
try {
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId,
location);
failDownload(
"下载失败【" + dEntity.downloadUrl + "】" + Util.getPrintException(e));
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (Exception e) {
synchronized (DownLoadUtil.this) {
try {
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId,
location);
failDownload("获取流失败" + Util.getPrintException(e));
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
} }
} catch (Exception e) {
synchronized (DownLoadUtil.this) { /**
try { * 将记录写入到配置文件
String location = String.valueOf(currentLocation); */
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location); private void writeConfig(String key, String record) throws IOException {
failDownload("获取流失败" + Util.getPrintException(e)); File configFile = new File(configFPath);
} catch (IOException e1) { Properties pro = Util.loadConfig(configFile);
e1.printStackTrace(); pro.setProperty(key, record);
} Util.saveConfig(configFile, pro);
} }
}
} }
/** /**
* 将记录写入到配置文件 * 子线程下载信息类
*/ */
private void writeConfig(String key, String record) throws IOException { private class DownloadEntity {
File configFile = new File(configFPath); //文件大小
Properties pro = Util.loadConfig(configFile); long fileSize;
pro.setProperty(key, record); String downloadUrl;
Util.saveConfig(configFile, pro); int threadId;
} long startLocation;
} long endLocation;
File tempFile;
/** Context context;
* 子线程下载信息类
*/ public DownloadEntity(Context context, long fileSize, String downloadUrl, File file,
private class DownloadEntity { int threadId, long startLocation, long endLocation) {
//文件大小 this.fileSize = fileSize;
long fileSize; this.downloadUrl = downloadUrl;
String downloadUrl; this.tempFile = file;
int threadId; this.threadId = threadId;
long startLocation; this.startLocation = startLocation;
long endLocation; this.endLocation = endLocation;
File tempFile; this.context = context;
Context context; }
public DownloadEntity(Context context, long fileSize, String downloadUrl, File file,
int threadId, long startLocation, long endLocation) {
this.fileSize = fileSize;
this.downloadUrl = downloadUrl;
this.tempFile = file;
this.threadId = threadId;
this.startLocation = startLocation;
this.endLocation = endLocation;
this.context = context;
} }
}
public static class DownloadListener implements IDownloadListener { public static class DownloadListener implements IDownloadListener {
@Override public void onResume(long resumeLocation) { @Override public void onResume(long resumeLocation) {
} }
@Override public void onCancel() { @Override public void onCancel() {
} }
@Override public void onFail() { @Override public void onFail() {
} }
@Override public void onPreDownload(HttpURLConnection connection) { @Override public void onPreDownload(HttpURLConnection connection) {
} }
@Override public void onProgress(long currentLocation) { @Override public void onProgress(long currentLocation) {
} }
@Override public void onChildComplete(long finishLocation) { @Override public void onChildComplete(long finishLocation) {
} }
@Override public void onStart(long startLocation) { @Override public void onStart(long startLocation) {
} }
@Override public void onChildResume(long resumeLocation) { @Override public void onChildResume(long resumeLocation) {
} }
@Override public void onStop(long stopLocation) { @Override public void onStop(long stopLocation) {
} }
@Override public void onComplete() { @Override public void onComplete() {
}
} }
}
} }

@ -6,53 +6,53 @@ import java.net.HttpURLConnection;
* 下载监听 * 下载监听
*/ */
public interface IDownloadListener { public interface IDownloadListener {
/** /**
* 取消下载 * 取消下载
*/ */
public void onCancel(); public void onCancel();
/** /**
* 下载失败 * 下载失败
*/ */
public void onFail(); public void onFail();
/** /**
* 下载预处理,可通过HttpURLConnection获取文件长度 * 下载预处理,可通过HttpURLConnection获取文件长度
*/ */
public void onPreDownload(HttpURLConnection connection); public void onPreDownload(HttpURLConnection connection);
/** /**
* 下载监听 * 下载监听
*/ */
public void onProgress(long currentLocation); public void onProgress(long currentLocation);
/** /**
* 单一线程的结束位置 * 单一线程的结束位置
*/ */
public void onChildComplete(long finishLocation); public void onChildComplete(long finishLocation);
/** /**
* 开始 * 开始
*/ */
public void onStart(long startLocation); public void onStart(long startLocation);
/** /**
* 子程恢复下载的位置 * 子程恢复下载的位置
*/ */
public void onChildResume(long resumeLocation); public void onChildResume(long resumeLocation);
/** /**
* 恢复位置 * 恢复位置
*/ */
public void onResume(long resumeLocation); public void onResume(long resumeLocation);
/** /**
* 停止 * 停止
*/ */
public void onStop(long stopLocation); public void onStop(long stopLocation);
/** /**
* 下载完成 * 下载完成
*/ */
public void onComplete(); public void onComplete();
} }

@ -1,6 +1,7 @@
package com.arialyy.downloadutil.util; package com.arialyy.downloadutil.util;
import android.util.Log; import android.util.Log;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@ -15,212 +16,212 @@ import java.util.Properties;
* Created by lyy on 2016/1/22. * Created by lyy on 2016/1/22.
*/ */
public class Util { public class Util {
private static final String TAG = "util"; private static final String TAG = "util";
/** /**
* 将缓存的key转换为hash码 * 将缓存的key转换为hash码
* *
* @param key 缓存的key * @param key 缓存的key
* @return 转换后的key的值, 系统便是通过该key来读写缓存 * @return 转换后的key的值, 系统便是通过该key来读写缓存
*/ */
public static String keyToHashKey(String key) { public static String keyToHashKey(String key) {
String cacheKey; String cacheKey;
try { try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5"); final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes()); mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest()); cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode()); cacheKey = String.valueOf(key.hashCode());
} }
return cacheKey; return cacheKey;
}
/**
* 将普通字符串转换为16位进制字符串
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (byte aSrc : src) {
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
/**
* 获取类里面的所在字段
*/
public static Field[] getFields(Class clazz) {
Field[] fields = null;
fields = clazz.getDeclaredFields();
if (fields == null || fields.length == 0) {
Class superClazz = clazz.getSuperclass();
if (superClazz != null) {
fields = getFields(superClazz);
}
} }
return fields;
} /**
* 将普通字符串转换为16位进制字符串
/** */
* 获取对象名 public static String bytesToHexString(byte[] src) {
* StringBuilder stringBuilder = new StringBuilder("0x");
* @param obj 对象 if (src == null || src.length <= 0) {
* @return 对象名 return null;
*/ }
public static String getClassName(Object obj) { char[] buffer = new char[2];
String arrays[] = obj.getClass().getName().split("\\."); for (byte aSrc : src) {
return arrays[arrays.length - 1]; buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
} buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
stringBuilder.append(buffer);
/** }
* 格式化文件大小 return stringBuilder.toString();
*
* @param size file.length() 获取文件大小
*/
public static String formatFileSize(double size) {
double kiloByte = size / 1024;
if (kiloByte < 1) {
return size + "Byte(s)";
} }
double megaByte = kiloByte / 1024; /**
if (megaByte < 1) { * 获取类里面的所在字段
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); */
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; public static Field[] getFields(Class clazz) {
Field[] fields = null;
fields = clazz.getDeclaredFields();
if (fields == null || fields.length == 0) {
Class superClazz = clazz.getSuperclass();
if (superClazz != null) {
fields = getFields(superClazz);
}
}
return fields;
} }
double gigaByte = megaByte / 1024; /**
if (gigaByte < 1) { * 获取对象名
BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); *
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"; * @param obj 对象
* @return 对象名
*/
public static String getClassName(Object obj) {
String arrays[] = obj.getClass().getName().split("\\.");
return arrays[arrays.length - 1];
} }
double teraBytes = gigaByte / 1024; /**
if (teraBytes < 1) { * 格式化文件大小
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); *
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; * @param size file.length() 获取文件大小
*/
public static String formatFileSize(double size) {
double kiloByte = size / 1024;
if (kiloByte < 1) {
return size + "Byte(s)";
}
double megaByte = kiloByte / 1024;
if (megaByte < 1) {
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
}
double gigaByte = megaByte / 1024;
if (gigaByte < 1) {
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
}
double teraBytes = gigaByte / 1024;
if (teraBytes < 1) {
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
}
BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
} }
BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; /**
} * 创建目录 当目录不存在的时候创建文件否则返回false
*/
/** public static boolean createDir(String path) {
* 创建目录 当目录不存在的时候创建文件否则返回false File file = new File(path);
*/ if (!file.exists()) {
public static boolean createDir(String path) { if (!file.mkdirs()) {
File file = new File(path); Log.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
if (!file.exists()) { return false;
if (!file.mkdirs()) { }
Log.d(TAG, "创建失败,请检查路径和是否配置文件权限!"); return true;
}
return false; return false;
}
return true;
}
return false;
}
/**
* 创建文件 当文件不存在的时候就创建一个文件否则直接返回文件
*/
public static File createFile(String path) {
File file = new File(path);
if (!file.getParentFile().exists()) {
Log.d(TAG, "目标文件所在路径不存在,准备创建……");
if (!createDir(file.getParent())) {
Log.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】");
}
} }
// 创建目标文件
try { /**
if (!file.exists()) { * 创建文件 当文件不存在的时候就创建一个文件否则直接返回文件
if (file.createNewFile()) { */
Log.d(TAG, "创建文件成功:" + file.getAbsolutePath()); public static File createFile(String path) {
File file = new File(path);
if (!file.getParentFile().exists()) {
Log.d(TAG, "目标文件所在路径不存在,准备创建……");
if (!createDir(file.getParent())) {
Log.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】");
}
} }
return file; // 创建目标文件
} else { try {
return file; if (!file.exists()) {
} if (file.createNewFile()) {
} catch (IOException e) { Log.d(TAG, "创建文件成功:" + file.getAbsolutePath());
e.printStackTrace(); }
} return file;
return null; } else {
} return file;
}
/** } catch (IOException e) {
* 设置打印的异常格式 e.printStackTrace();
*/ }
public static String getPrintException(Throwable ex) { return null;
StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n");
err.append(ex.toString());
err.append("\n");
StackTraceElement[] stack = ex.getStackTrace();
for (StackTraceElement stackTraceElement : stack) {
err.append(stackTraceElement.toString()).append("\n");
} }
Throwable cause = ex.getCause();
if (cause != null) { /**
err.append("【Caused by】: "); * 设置打印的异常格式
err.append(cause.toString()); */
err.append("\n"); public static String getPrintException(Throwable ex) {
StackTraceElement[] stackTrace = cause.getStackTrace(); StringBuilder err = new StringBuilder();
for (StackTraceElement stackTraceElement : stackTrace) { err.append("ExceptionDetailed:\n");
err.append(stackTraceElement.toString()).append("\n"); err.append("====================Exception Info====================\n");
} err.append(ex.toString());
err.append("\n");
StackTraceElement[] stack = ex.getStackTrace();
for (StackTraceElement stackTraceElement : stack) {
err.append(stackTraceElement.toString()).append("\n");
}
Throwable cause = ex.getCause();
if (cause != null) {
err.append("【Caused by】: ");
err.append(cause.toString());
err.append("\n");
StackTraceElement[] stackTrace = cause.getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
err.append(stackTraceElement.toString()).append("\n");
}
}
err.append("===================================================");
return err.toString();
} }
err.append("===================================================");
return err.toString(); /**
} * 读取下载配置文件
*/
/** public static Properties loadConfig(File file) {
* 读取下载配置文件 Properties properties = new Properties();
*/ FileInputStream fis = null;
public static Properties loadConfig(File file) { try {
Properties properties = new Properties(); fis = new FileInputStream(file);
FileInputStream fis = null; properties.load(fis);
try { } catch (Exception e) {
fis = new FileInputStream(file); e.printStackTrace();
properties.load(fis); } finally {
} catch (Exception e) { try {
e.printStackTrace(); if (fis != null) {
} finally { fis.close();
try { }
if (fis != null) { } catch (IOException e) {
fis.close(); e.printStackTrace();
}
} }
} catch (IOException e) { return properties;
e.printStackTrace();
}
} }
return properties;
} /**
* 保存配置文件
/** */
* 保存配置文件 public static void saveConfig(File file, Properties properties) {
*/ FileOutputStream fos = null;
public static void saveConfig(File file, Properties properties) { try {
FileOutputStream fos = null; fos = new FileOutputStream(file, false);
try { properties.store(fos, null);
fos = new FileOutputStream(file, false); } catch (Exception e) {
properties.store(fos, null); e.printStackTrace();
} catch (Exception e) { } finally {
e.printStackTrace(); try {
} finally { if (fos != null) {
try { fos.flush();
if (fos != null) { fos.close();
fos.flush(); }
fos.close(); } catch (IOException e) {
e.printStackTrace();
}
} }
} catch (IOException e) {
e.printStackTrace();
}
} }
}
} }

@ -1,8 +1,8 @@
<resources> <resources>
<string name="app_name">DownloadUtil</string> <string name="app_name">DownloadUtil</string>
<string name="error_entity_null">下载实体不能为空</string> <string name="error_entity_null">下载实体不能为空</string>
<string name="error_download_url_null">下载链接不能为空</string> <string name="error_download_url_null">下载链接不能为空</string>
<string name="error_download_path_null">存储地址不能为空</string> <string name="error_download_path_null">存储地址不能为空</string>
<string name="error_file_name_null">文件名不能为空</string> <string name="error_file_name_null">文件名不能为空</string>
</resources> </resources>

@ -8,7 +8,7 @@ import static org.junit.Assert.assertEquals;
* To work on unit tests, switch the Test Artifact in the Build Variants view. * To work on unit tests, switch the Test Artifact in the Build Variants view.
*/ */
public class ExampleUnitTest { public class ExampleUnitTest {
@Test public void addition_isCorrect() throws Exception { @Test public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2); assertEquals(4, 2 + 2);
} }
} }
Loading…
Cancel
Save