pull/2/head
lyy 9 years ago
commit f810fdbf95
  1. BIN
      .gradle/2.10/taskArtifacts/cache.properties.lock
  2. BIN
      .gradle/2.10/taskArtifacts/fileHashes.bin
  3. BIN
      .gradle/2.10/taskArtifacts/fileSnapshots.bin
  4. BIN
      .gradle/2.10/taskArtifacts/outputFileStates.bin
  5. BIN
      .gradle/2.10/taskArtifacts/taskArtifacts.bin
  6. 6
      .idea/codeStyleSettings.xml
  7. 6
      .idea/encodings.xml
  8. 2
      .idea/modules.xml
  9. 2
      app/build.gradle
  10. 6
      app/src/androidTest/java/com/example/arial/downloaddemo/ApplicationTest.java
  11. 46
      app/src/main/AndroidManifest.xml
  12. 127
      app/src/main/java/com/arialyy/simple/activity/MultiTaskActivity.java
  13. 419
      app/src/main/java/com/arialyy/simple/activity/SingleTaskActivity.java
  14. 265
      app/src/main/java/com/arialyy/simple/adapter/DownloadAdapter.java
  15. 11
      app/src/main/java/com/arialyy/simple/base/BaseActivity.java
  16. 11
      app/src/main/java/com/arialyy/simple/base/BaseApplication.java
  17. 7
      app/src/main/java/com/arialyy/simple/base/BaseModule.java
  18. 9
      app/src/main/java/com/arialyy/simple/module/DownloadModule.java
  19. 319
      app/src/main/java/com/arialyy/simple/widget/HorizontalProgressBarWithNumber.java
  20. 1
      app/src/main/res/layout/activity_multi.xml
  21. 47
      app/src/main/res/layout/activity_single.xml
  22. 122
      app/src/main/res/layout/content_single.xml
  23. 40
      app/src/main/res/layout/item_download.xml
  24. 16
      app/src/main/res/menu/menu_main.xml
  25. 48
      app/src/main/res/values-v21/styles.xml
  26. 8
      app/src/main/res/values-w820dp/dimens.xml
  27. 26
      app/src/main/res/values/attr.xml
  28. 6
      app/src/main/res/values/colors.xml
  29. 8
      app/src/main/res/values/dimens.xml
  30. 30
      app/src/main/res/values/strings.xml
  31. 36
      app/src/main/res/values/styles.xml
  32. 14
      app/src/test/java/com/example/arial/downloaddemo/ExampleUnitTest.java
  33. 6
      downloadutil/src/androidTest/java/com/arialyy/downloadutil/ApplicationTest.java
  34. 12
      downloadutil/src/main/AndroidManifest.xml
  35. 227
      downloadutil/src/main/java/com/arialyy/downloadutil/core/DownloadManager.java
  36. 171
      downloadutil/src/main/java/com/arialyy/downloadutil/core/DownloadTarget.java
  37. 349
      downloadutil/src/main/java/com/arialyy/downloadutil/core/IDownloadTarget.java
  38. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/core/TaskEnum.java
  39. 49
      downloadutil/src/main/java/com/arialyy/downloadutil/core/TaskFactory.java
  40. 23
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/AddCommand.java
  41. 25
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/CancelCommand.java
  42. 195
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/CommandFactory.java
  43. 63
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/IDownloadCommand.java
  44. 25
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StartCommand.java
  45. 21
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StateCommand.java
  46. 39
      downloadutil/src/main/java/com/arialyy/downloadutil/core/command/StopCommand.java
  47. 48
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IDownloader.java
  48. 74
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/IPool.java
  49. 68
      downloadutil/src/main/java/com/arialyy/downloadutil/core/inf/ITask.java
  50. 158
      downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/CachePool.java
  51. 232
      downloadutil/src/main/java/com/arialyy/downloadutil/core/pool/ExecutePool.java
  52. 351
      downloadutil/src/main/java/com/arialyy/downloadutil/entity/DownloadEntity.java
  53. 66
      downloadutil/src/main/java/com/arialyy/downloadutil/help/CheckHelp.java
  54. 83
      downloadutil/src/main/java/com/arialyy/downloadutil/help/PathHelp.java
  55. 245
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/DbEntity.java
  56. 724
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/DbUtil.java
  57. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/Id.java
  58. 2
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/Ignore.java
  59. 34
      downloadutil/src/main/java/com/arialyy/downloadutil/orm/SqlHelper.java
  60. 857
      downloadutil/src/main/java/com/arialyy/downloadutil/util/DownLoadUtil.java
  61. 98
      downloadutil/src/main/java/com/arialyy/downloadutil/util/IDownloadListener.java
  62. 432
      downloadutil/src/main/java/com/arialyy/downloadutil/util/Task.java
  63. 454
      downloadutil/src/main/java/com/arialyy/downloadutil/util/Util.java
  64. 10
      downloadutil/src/main/res/values/strings.xml
  65. 14
      downloadutil/src/test/java/com/arialyy/downloadutil/ExampleUnitTest.java

@ -63,7 +63,9 @@
</extensions> </extensions>
</Objective-C-extensions> </Objective-C-extensions>
<XML> <XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> <option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</XML> </XML>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" /> <option name="FORCE_REARRANGE_MODE" value="1" />
@ -224,6 +226,6 @@
</codeStyleSettings> </codeStyleSettings>
</value> </value>
</option> </option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="aria" /> <option name="PREFERRED_PROJECT_CODE_STYLE" value="SquareAndroid" />
</component> </component>
</project> </project>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>

@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/DownloadUtil.iml" filepath="$PROJECT_DIR$/DownloadUtil.iml" /> <module fileurl="file://$PROJECT_DIR$/DownloadPrj.iml" filepath="$PROJECT_DIR$/DownloadPrj.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/downloadutil/downloadutil.iml" filepath="$PROJECT_DIR$/downloadutil/downloadutil.iml" /> <module fileurl="file://$PROJECT_DIR$/downloadutil/downloadutil.iml" filepath="$PROJECT_DIR$/downloadutil/downloadutil.iml" />
</modules> </modules>

@ -1,7 +1,7 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 'Google Inc.:Google APIs:23' compileSdkVersion 23
buildToolsVersion "23.0.2" buildToolsVersion "23.0.2"
defaultConfig { defaultConfig {

@ -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,32 +1,32 @@
<?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">
<!--android:name=".activity.SingleTaskActivity"-->
<activity
android:name=".activity.MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:theme="@style/AppTheme.NoActionBar">
android:theme="@style/AppTheme"> <intent-filter>
<!--android:name=".activity.SingleTaskActivity"--> <action android:name="android.intent.action.MAIN"/>
<activity
android:name=".activity.MainActivity"
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>
<activity android:name=".activity.SingleTaskActivity"/> <activity android:name=".activity.SingleTaskActivity"/>
<activity android:name=".activity.MultiTaskActivity"/> <activity android:name=".activity.MultiTaskActivity"/>
</application> </application>
</manifest> </manifest>

@ -6,8 +6,8 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import butterknife.Bind;
import com.arialyy.downloadutil.core.DownloadManager; import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.L;
@ -17,78 +17,75 @@ import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMultiBinding; import com.arialyy.simple.databinding.ActivityMultiBinding;
import com.arialyy.simple.module.DownloadModule; import com.arialyy.simple.module.DownloadModule;
import butterknife.Bind;
/** /**
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
*/ */
public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> { public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
@Bind(R.id.list) RecyclerView mList; @Bind(R.id.list) RecyclerView mList;
@Bind(R.id.toolbar) Toolbar mBar; @Bind(R.id.toolbar) Toolbar mBar;
DownloadAdapter mAdapter; DownloadAdapter mAdapter;
@Override protected int setLayoutId() {
return R.layout.activity_multi;
}
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
setSupportActionBar(mBar);
mBar.setTitle("多任务下载");
mAdapter = new DownloadAdapter(this, getModule(DownloadModule.class).getDownloadData());
mList.setLayoutManager(new LinearLayoutManager(this));
mList.setAdapter(mAdapter);
}
@Override protected int setLayoutId() {
return R.layout.activity_multi;
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override protected void init(Bundle savedInstanceState) {
long len = 0; super.init(savedInstanceState);
setSupportActionBar(mBar);
mBar.setTitle("多任务下载");
mAdapter = new DownloadAdapter(this, getModule(DownloadModule.class).getDownloadData());
mList.setLayoutManager(new LinearLayoutManager(this));
mList.setAdapter(mAdapter);
}
@Override public void onReceive(Context context, Intent intent) { private BroadcastReceiver mReceiver = new BroadcastReceiver() {
String action = intent.getAction(); long len = 0;
DownloadEntity entity = intent.getParcelableExtra(DownloadManager.ENTITY);
switch (action) {
case DownloadManager.ACTION_PRE:
len = entity.getFileSize();
L.d(TAG, "download pre");
break;
case DownloadManager.ACTION_START:
L.d(TAG, "download start");
break;
case DownloadManager.ACTION_RESUME:
L.d(TAG, "download resume");
long location = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 1);
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_RUNNING:
long current = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 0);
mAdapter.setProgress(entity.getDownloadUrl(), current);
break;
case DownloadManager.ACTION_STOP:
L.d(TAG, "download stop");
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_COMPLETE:
L.d(TAG, "download complete");
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_CANCEL:
L.d(TAG, "download cancel");
break;
case DownloadManager.ACTION_FAIL:
L.d(TAG, "download fail");
break;
}
}
};
@Override protected void onResume() { @Override public void onReceive(Context context, Intent intent) {
super.onResume(); String action = intent.getAction();
registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter()); DownloadEntity entity = intent.getParcelableExtra(DownloadManager.ENTITY);
switch (action) {
case DownloadManager.ACTION_PRE:
len = entity.getFileSize();
L.d(TAG, "download pre");
break;
case DownloadManager.ACTION_START:
L.d(TAG, "download start");
break;
case DownloadManager.ACTION_RESUME:
L.d(TAG, "download resume");
long location = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 1);
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_RUNNING:
long current = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 0);
mAdapter.setProgress(entity.getDownloadUrl(), current);
break;
case DownloadManager.ACTION_STOP:
L.d(TAG, "download stop");
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_COMPLETE:
L.d(TAG, "download complete");
mAdapter.updateState(entity);
break;
case DownloadManager.ACTION_CANCEL:
L.d(TAG, "download cancel");
break;
case DownloadManager.ACTION_FAIL:
L.d(TAG, "download fail");
break;
}
} }
};
@Override protected void onDestroy() { @Override protected void onResume() {
super.onDestroy(); super.onResume();
unregisterReceiver(mReceiver); registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter());
} }
@Override protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
} }

@ -13,7 +13,7 @@ import android.widget.Button;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import butterknife.Bind;
import com.arialyy.downloadutil.core.DownloadManager; import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.command.CommandFactory; import com.arialyy.downloadutil.core.command.CommandFactory;
import com.arialyy.downloadutil.core.command.IDownloadCommand; import com.arialyy.downloadutil.core.command.IDownloadCommand;
@ -25,224 +25,217 @@ import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivitySingleBinding; import com.arialyy.simple.databinding.ActivitySingleBinding;
import com.arialyy.simple.module.DownloadModule; import com.arialyy.simple.module.DownloadModule;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import butterknife.Bind;
public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> { public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
private static final int DOWNLOAD_PRE = 0x01; private static final int DOWNLOAD_PRE = 0x01;
private static final int DOWNLOAD_STOP = 0x02; private static final int DOWNLOAD_STOP = 0x02;
private static final int DOWNLOAD_FAILE = 0x03; private static final int DOWNLOAD_FAILE = 0x03;
private static final int DOWNLOAD_CANCEL = 0x04; private static final int DOWNLOAD_CANCEL = 0x04;
private static final int DOWNLOAD_RESUME = 0x05; private static final int DOWNLOAD_RESUME = 0x05;
private static final int DOWNLOAD_COMPLETE = 0x06; private static final int DOWNLOAD_COMPLETE = 0x06;
private ProgressBar mPb; private ProgressBar mPb;
private String mDownloadUrl = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk"; private String mDownloadUrl =
private Button mStart, mStop, mCancel; "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk";
private TextView mSize; private Button mStart, mStop, mCancel;
@Bind(R.id.toolbar) Toolbar toolbar; private TextView mSize;
private CommandFactory mFactory; @Bind(R.id.toolbar) Toolbar toolbar;
private DownloadManager mManager; private CommandFactory mFactory;
private DownloadEntity mEntity; private DownloadManager mManager;
private DownloadEntity mEntity;
private Handler mUpdateHandler = new Handler() {
@Override public void handleMessage(Message msg) { private Handler mUpdateHandler = new Handler() {
super.handleMessage(msg); @Override public void handleMessage(Message msg) {
switch (msg.what) { super.handleMessage(msg);
case DOWNLOAD_PRE: switch (msg.what) {
mSize.setText(Util.formatFileSize((Long) msg.obj)); case DOWNLOAD_PRE:
setBtState(false); mSize.setText(Util.formatFileSize((Long) msg.obj));
break; setBtState(false);
case DOWNLOAD_FAILE: break;
Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show(); case DOWNLOAD_FAILE:
setBtState(true); Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
break; setBtState(true);
case DOWNLOAD_STOP: break;
Toast.makeText(SingleTaskActivity.this, "暂停下载", Toast.LENGTH_SHORT).show(); case DOWNLOAD_STOP:
mStart.setText("恢复"); Toast.makeText(SingleTaskActivity.this, "暂停下载", Toast.LENGTH_SHORT).show();
setBtState(true); mStart.setText("恢复");
break; setBtState(true);
case DOWNLOAD_CANCEL: break;
mPb.setProgress(0); case DOWNLOAD_CANCEL:
Toast.makeText(SingleTaskActivity.this, "取消下载", Toast.LENGTH_SHORT).show(); mPb.setProgress(0);
mStart.setText("开始"); Toast.makeText(SingleTaskActivity.this, "取消下载", Toast.LENGTH_SHORT).show();
setBtState(true); mStart.setText("开始");
break; setBtState(true);
case DOWNLOAD_RESUME: break;
Toast.makeText(SingleTaskActivity.this, case DOWNLOAD_RESUME:
"恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj), Toast.makeText(SingleTaskActivity.this,
Toast.LENGTH_SHORT).show(); "恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj), Toast.LENGTH_SHORT).show();
setBtState(false); setBtState(false);
break; break;
case DOWNLOAD_COMPLETE: case DOWNLOAD_COMPLETE:
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show(); Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
mStart.setText("重新开始?"); mStart.setText("重新开始?");
mCancel.setEnabled(false); mCancel.setEnabled(false);
setBtState(true); setBtState(true);
break; break;
} }
}
};
/**
* 设置start stop 按钮状态
*
* @param state
*/
private void setBtState(boolean state) {
mStart.setEnabled(state);
mStop.setEnabled(!state);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
long len = 0;
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case DownloadManager.ACTION_PRE:
DownloadEntity entity = intent.getParcelableExtra(DownloadManager.ENTITY);
len = entity.getFileSize();
L.d(TAG, "download pre");
mUpdateHandler.obtainMessage(DOWNLOAD_PRE, len).sendToTarget();
break;
case DownloadManager.ACTION_START:
L.d(TAG, "download start");
break;
case DownloadManager.ACTION_RESUME:
L.d(TAG, "download resume");
long location = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 1);
mUpdateHandler.obtainMessage(DOWNLOAD_RESUME, location).sendToTarget();
break;
case DownloadManager.ACTION_RUNNING:
long current = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 0);
if (len == 0) {
mPb.setProgress(0);
} else {
mPb.setProgress((int) ((current * 100) / len));
}
break;
case DownloadManager.ACTION_STOP:
L.d(TAG, "download stop");
mUpdateHandler.sendEmptyMessage(DOWNLOAD_STOP);
break;
case DownloadManager.ACTION_COMPLETE:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_COMPLETE);
break;
case DownloadManager.ACTION_CANCEL:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_CANCEL);
break;
case DownloadManager.ACTION_FAIL:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_FAILE);
break;
}
}
};
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
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() {
return R.layout.activity_single; /**
} * 设置start stop 按钮状态
*/
@Override protected void init(Bundle savedInstanceState) { private void setBtState(boolean state) {
super.init(savedInstanceState); mStart.setEnabled(state);
setSupportActionBar(toolbar); mStop.setEnabled(!state);
toolbar.setTitle("单任务下载"); }
init();
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
long len = 0;
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case DownloadManager.ACTION_PRE:
DownloadEntity entity = intent.getParcelableExtra(DownloadManager.ENTITY);
len = entity.getFileSize();
L.d(TAG, "download pre");
mUpdateHandler.obtainMessage(DOWNLOAD_PRE, len).sendToTarget();
break;
case DownloadManager.ACTION_START:
L.d(TAG, "download start");
break;
case DownloadManager.ACTION_RESUME:
L.d(TAG, "download resume");
long location = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 1);
mUpdateHandler.obtainMessage(DOWNLOAD_RESUME, location).sendToTarget();
break;
case DownloadManager.ACTION_RUNNING:
long current = intent.getLongExtra(DownloadManager.CURRENT_LOCATION, 0);
if (len == 0) {
mPb.setProgress(0);
} else {
mPb.setProgress((int) ((current * 100) / len));
}
break;
case DownloadManager.ACTION_STOP:
L.d(TAG, "download stop");
mUpdateHandler.sendEmptyMessage(DOWNLOAD_STOP);
break;
case DownloadManager.ACTION_COMPLETE:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_COMPLETE);
break;
case DownloadManager.ACTION_CANCEL:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_CANCEL);
break;
case DownloadManager.ACTION_FAIL:
mUpdateHandler.sendEmptyMessage(DOWNLOAD_FAILE);
break;
}
} }
};
private void init() {
mPb = (ProgressBar) findViewById(R.id.progressBar); @Override protected void onCreate(Bundle savedInstanceState) {
mStart = (Button) findViewById(R.id.start); super.onCreate(savedInstanceState);
mStop = (Button) findViewById(R.id.stop); init();
mCancel = (Button) findViewById(R.id.cancel); }
mSize = (TextView) findViewById(R.id.size);
mFactory = CommandFactory.getInstance(); @Override protected void onResume() {
mManager = DownloadManager.getInstance(); super.onResume();
mEntity = DbEntity.findData(DownloadEntity.class, new String[]{"downloadUrl"}, registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter());
new String[]{mDownloadUrl}); }
if (mEntity != null) {
mPb.setProgress((int) ((mEntity.getCurrentProgress() * 100) / mEntity.getFileSize())); @Override protected void onDestroy() {
mSize.setText(Util.formatFileSize(mEntity.getFileSize())); super.onDestroy();
if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) { unregisterReceiver(mReceiver);
setBtState(false); }
} else if (mEntity.isDownloadComplete()) {
mStart.setText("重新开始?"); @Override protected int setLayoutId() {
setBtState(true); return R.layout.activity_single;
} }
} else {
mEntity = new DownloadEntity(); @Override protected void init(Bundle savedInstanceState) {
} super.init(savedInstanceState);
} setSupportActionBar(toolbar);
toolbar.setTitle("单任务下载");
public void onClick(View view) { init();
switch (view.getId()) { }
case R.id.start:
start(); private void init() {
// if (PermissionManager.getInstance() mPb = (ProgressBar) findViewById(R.id.progressBar);
// .checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { mStart = (Button) findViewById(R.id.start);
// start(); mStop = (Button) findViewById(R.id.stop);
// } else { mCancel = (Button) findViewById(R.id.cancel);
// PermissionManager.getInstance() mSize = (TextView) findViewById(R.id.size);
// .requestPermission(this, new OnPermissionCallback() { mFactory = CommandFactory.getInstance();
// @Override public void onSuccess(String... permissions) { mManager = DownloadManager.getInstance();
// start(); mEntity = DbEntity.findData(DownloadEntity.class, new String[] { "downloadUrl" },
// } new String[] { mDownloadUrl });
// if (mEntity != null) {
// @Override public void onFail(String... permissions) { mPb.setProgress((int) ((mEntity.getCurrentProgress() * 100) / mEntity.getFileSize()));
// mSize.setText(Util.formatFileSize(mEntity.getFileSize()));
// } if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
// }, Manifest.permission.WRITE_EXTERNAL_STORAGE); setBtState(false);
// } } else if (mEntity.isDownloadComplete()) {
break; mStart.setText("重新开始?");
case R.id.stop: setBtState(true);
stop(); }
break; } else {
case R.id.cancel: mEntity = new DownloadEntity();
cancel();
break;
}
} }
}
private void start() {
mEntity.setFileName("test.apk"); public void onClick(View view) {
mEntity.setDownloadUrl(mDownloadUrl); switch (view.getId()) {
mEntity.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk"); case R.id.start:
List<IDownloadCommand> commands = new ArrayList<>(); start();
IDownloadCommand addCommand = mFactory.createCommand(this, mEntity, // if (PermissionManager.getInstance()
CommandFactory.TASK_CREATE); // .checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
IDownloadCommand startCommand = mFactory.createCommand(this, mEntity, // start();
CommandFactory.TASK_START); // } else {
commands.add(addCommand); // PermissionManager.getInstance()
commands.add(startCommand); // .requestPermission(this, new OnPermissionCallback() {
mManager.setCommands(commands).exe(); // @Override public void onSuccess(String... permissions) {
} // start();
// }
private void stop() { //
IDownloadCommand stopCommand = mFactory.createCommand(this, mEntity, // @Override public void onFail(String... permissions) {
CommandFactory.TASK_STOP); //
mManager.setCommand(stopCommand).exe(); // }
} // }, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// }
private void cancel() { break;
IDownloadCommand cancelCommand = mFactory.createCommand(this, mEntity, case R.id.stop:
CommandFactory.TASK_CANCEL); stop();
mManager.setCommand(cancelCommand).exe(); break;
case R.id.cancel:
cancel();
break;
} }
}
private void start() {
mEntity.setFileName("test.apk");
mEntity.setDownloadUrl(mDownloadUrl);
mEntity.setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk");
List<IDownloadCommand> commands = new ArrayList<>();
IDownloadCommand addCommand = mFactory.createCommand(this, mEntity, CommandFactory.TASK_CREATE);
IDownloadCommand startCommand =
mFactory.createCommand(this, mEntity, CommandFactory.TASK_START);
commands.add(addCommand);
commands.add(startCommand);
mManager.setCommands(commands).exe();
}
private void stop() {
IDownloadCommand stopCommand = mFactory.createCommand(this, mEntity, CommandFactory.TASK_STOP);
mManager.setCommand(stopCommand).exe();
}
private void cancel() {
IDownloadCommand cancelCommand =
mFactory.createCommand(this, mEntity, CommandFactory.TASK_CANCEL);
mManager.setCommand(cancelCommand).exe();
}
} }

@ -4,7 +4,7 @@ import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import butterknife.Bind;
import com.arialyy.absadapter.common.AbsHolder; import com.arialyy.absadapter.common.AbsHolder;
import com.arialyy.absadapter.recycler_view.AbsRVAdapter; import com.arialyy.absadapter.recycler_view.AbsRVAdapter;
import com.arialyy.downloadutil.core.DownloadManager; import com.arialyy.downloadutil.core.DownloadManager;
@ -14,165 +14,162 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.frame.util.show.L; import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R; import com.arialyy.simple.R;
import com.arialyy.simple.widget.HorizontalProgressBarWithNumber; import com.arialyy.simple.widget.HorizontalProgressBarWithNumber;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import butterknife.Bind;
/** /**
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
* 下载列表适配器 * 下载列表适配器
*/ */
public class DownloadAdapter extends AbsRVAdapter<DownloadEntity, DownloadAdapter.MyHolder> { public class DownloadAdapter extends AbsRVAdapter<DownloadEntity, DownloadAdapter.MyHolder> {
private static final String TAG = "DownloadAdapter"; private static final String TAG = "DownloadAdapter";
private DownloadManager mManager; private DownloadManager mManager;
private CommandFactory mFactory; private CommandFactory mFactory;
private Map<String, Long> mProgress = new HashMap<>(); private Map<String, Long> mProgress = new HashMap<>();
private Map<String, Integer> mPositions = new HashMap<>(); private Map<String, Integer> mPositions = new HashMap<>();
public DownloadAdapter(Context context, List<DownloadEntity> data) { public DownloadAdapter(Context context, List<DownloadEntity> data) {
super(context, data); super(context, data);
int i = 0; int i = 0;
for (DownloadEntity entity : data) { for (DownloadEntity entity : data) {
mProgress.put(entity.getDownloadUrl(), entity.getCurrentProgress()); mProgress.put(entity.getDownloadUrl(), entity.getCurrentProgress());
mPositions.put(entity.getDownloadUrl(), i); mPositions.put(entity.getDownloadUrl(), i);
i++; i++;
}
mFactory = CommandFactory.getInstance();
mManager = DownloadManager.getInstance();
} }
mFactory = CommandFactory.getInstance();
@Override protected MyHolder getViewHolder(View convertView, int viewType) { mManager = DownloadManager.getInstance();
return new MyHolder(convertView); }
@Override protected MyHolder getViewHolder(View convertView, int viewType) {
return new MyHolder(convertView);
}
@Override protected int setLayoutId(int type) {
return R.layout.item_download;
}
public synchronized void updateState(DownloadEntity entity) {
notifyItemChanged(indexItem(entity.getDownloadUrl()));
}
public synchronized void setProgress(String url, long currentPosition) {
mProgress.put(url, currentPosition);
// int index = indexItem(url);
// L.d(TAG, "index ==> " + index);
// notifyItemChanged(index);
notifyItemChanged(indexItem(url));
}
private synchronized int indexItem(String url) {
Set set = mPositions.entrySet();
for (Object aSet : set) {
Map.Entry entry = (Map.Entry) aSet;
if (entry.getKey().equals(url)) {
return (int) entry.getValue();
}
} }
return -1;
@Override protected int setLayoutId(int type) { }
return R.layout.item_download;
@Override protected void bindData(MyHolder holder, int position, DownloadEntity item) {
//holder.progress.setProgress(item.getCurrentProgress());
long size = item.getFileSize();
int current = 0;
if (size == 0) {
current = 0;
} }
current = (int) (mProgress.get(item.getDownloadUrl()) * 100 / item.getFileSize());
public synchronized void updateState(DownloadEntity entity) { holder.progress.setProgress(current);
notifyItemChanged(indexItem(entity.getDownloadUrl())); BtClickListener listener = new BtClickListener(position, item);
holder.bt.setOnClickListener(listener);
String str = "";
int color = android.R.color.holo_green_light;
switch (item.getState()) {
case DownloadEntity.STATE_WAIT:
case DownloadEntity.STATE_OTHER:
case DownloadEntity.STATE_FAIL:
str = "开始";
break;
case DownloadEntity.STATE_STOP:
str = "恢复";
color = android.R.color.holo_blue_light;
break;
case DownloadEntity.STATE_DOWNLOAD_ING:
str = "暂停";
color = android.R.color.holo_red_light;
break;
case DownloadEntity.STATE_COMPLETE:
str = "重新开始?";
holder.progress.setProgress(100);
break;
} }
holder.bt.setText(str);
holder.bt.setTextColor(getColor(color));
}
private int getColor(int color) {
return Resources.getSystem().getColor(color);
}
public synchronized void setProgress(String url, long currentPosition) { private class BtClickListener implements View.OnClickListener {
mProgress.put(url, currentPosition); private DownloadEntity entity;
// int index = indexItem(url); private int position;
// L.d(TAG, "index ==> " + index);
// notifyItemChanged(index); BtClickListener(int position, DownloadEntity entity) {
notifyItemChanged(indexItem(url)); this.entity = entity;
this.position = position;
} }
private synchronized int indexItem(String url) { @Override public void onClick(View v) {
Set set = mPositions.entrySet(); L.d(TAG, "position ==> " + position);
for (Object aSet : set) { switch (entity.getState()) {
Map.Entry entry = (Map.Entry) aSet; case DownloadEntity.STATE_WAIT:
if (entry.getKey().equals(url)) { case DownloadEntity.STATE_OTHER:
return (int) entry.getValue(); case DownloadEntity.STATE_FAIL:
} case DownloadEntity.STATE_STOP:
} case DownloadEntity.STATE_COMPLETE:
return -1; start(entity);
break;
case DownloadEntity.STATE_DOWNLOAD_ING:
stop(entity);
break;
}
} }
@Override protected void bindData(MyHolder holder, int position, DownloadEntity item) { private void start(DownloadEntity entity) {
//holder.progress.setProgress(item.getCurrentProgress());
long size = item.getFileSize(); List<IDownloadCommand> commands = new ArrayList<>();
int current = 0; IDownloadCommand addCommand =
if (size == 0) { mFactory.createCommand(getContext(), entity, CommandFactory.TASK_CREATE);
current = 0; IDownloadCommand startCommand =
} mFactory.createCommand(getContext(), entity, CommandFactory.TASK_START);
current = (int) (mProgress.get(item.getDownloadUrl()) * 100 / item.getFileSize()); commands.add(addCommand);
holder.progress.setProgress(current); commands.add(startCommand);
BtClickListener listener = new BtClickListener(position, item); mManager.setCommands(commands).exe();
holder.bt.setOnClickListener(listener);
String str = "";
int color = android.R.color.holo_green_light;
switch (item.getState()) {
case DownloadEntity.STATE_WAIT:
case DownloadEntity.STATE_OTHER:
case DownloadEntity.STATE_FAIL:
str = "开始";
break;
case DownloadEntity.STATE_STOP:
str = "恢复";
color = android.R.color.holo_blue_light;
break;
case DownloadEntity.STATE_DOWNLOAD_ING:
str = "暂停";
color = android.R.color.holo_red_light;
break;
case DownloadEntity.STATE_COMPLETE:
str = "重新开始?";
holder.progress.setProgress(100);
break;
}
holder.bt.setText(str);
holder.bt.setTextColor(getColor(color));
} }
private int getColor(int color) { private void stop(DownloadEntity entity) {
return Resources.getSystem().getColor(color); IDownloadCommand stopCommand =
mFactory.createCommand(getContext(), entity, CommandFactory.TASK_STOP);
mManager.setCommand(stopCommand).exe();
} }
private class BtClickListener implements View.OnClickListener { private void cancel(DownloadEntity entity) {
private DownloadEntity entity; IDownloadCommand cancelCommand =
private int position; mFactory.createCommand(getContext(), entity, CommandFactory.TASK_CANCEL);
mManager.setCommand(cancelCommand).exe();
BtClickListener(int position, DownloadEntity entity) {
this.entity = entity;
this.position = position;
}
@Override public void onClick(View v) {
L.d(TAG, "position ==> " + position);
switch (entity.getState()) {
case DownloadEntity.STATE_WAIT:
case DownloadEntity.STATE_OTHER:
case DownloadEntity.STATE_FAIL:
case DownloadEntity.STATE_STOP:
case DownloadEntity.STATE_COMPLETE:
start(entity);
break;
case DownloadEntity.STATE_DOWNLOAD_ING:
stop(entity);
break;
}
}
private void start(DownloadEntity entity) {
List<IDownloadCommand> commands = new ArrayList<>();
IDownloadCommand addCommand = mFactory.createCommand(getContext(), entity,
CommandFactory.TASK_CREATE);
IDownloadCommand startCommand = mFactory.createCommand(getContext(), entity,
CommandFactory.TASK_START);
commands.add(addCommand);
commands.add(startCommand);
mManager.setCommands(commands).exe();
}
private void stop(DownloadEntity entity) {
IDownloadCommand stopCommand = mFactory.createCommand(getContext(), entity,
CommandFactory.TASK_STOP);
mManager.setCommand(stopCommand).exe();
}
private void cancel(DownloadEntity entity) {
IDownloadCommand cancelCommand = mFactory.createCommand(getContext(), entity,
CommandFactory.TASK_CANCEL);
mManager.setCommand(cancelCommand).exe();
}
} }
}
class MyHolder extends AbsHolder { class MyHolder extends AbsHolder {
@Bind(R.id.progressBar) HorizontalProgressBarWithNumber progress; @Bind(R.id.progressBar) HorizontalProgressBarWithNumber progress;
@Bind(R.id.bt) Button bt; @Bind(R.id.bt) Button bt;
MyHolder(View itemView) { MyHolder(View itemView) {
super(itemView); super(itemView);
}
} }
}
} }

@ -2,18 +2,17 @@ package com.arialyy.simple.base;
import android.databinding.ViewDataBinding; import android.databinding.ViewDataBinding;
import android.os.Bundle; import android.os.Bundle;
import com.arialyy.frame.core.AbsActivity; import com.arialyy.frame.core.AbsActivity;
/** /**
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
*/ */
public abstract class BaseActivity<VB extends ViewDataBinding> extends AbsActivity<VB> { public abstract class BaseActivity<VB extends ViewDataBinding> extends AbsActivity<VB> {
@Override protected void dataCallback(int result, Object data) { @Override protected void dataCallback(int result, Object data) {
} }
@Override protected void init(Bundle savedInstanceState) { @Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState); super.init(savedInstanceState);
} }
} }

@ -1,7 +1,6 @@
package com.arialyy.simple.base; package com.arialyy.simple.base;
import android.app.Application; import android.app.Application;
import com.arialyy.downloadutil.core.DownloadManager; import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.frame.core.AbsFrame; import com.arialyy.frame.core.AbsFrame;
@ -9,9 +8,9 @@ import com.arialyy.frame.core.AbsFrame;
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
*/ */
public class BaseApplication extends Application { public class BaseApplication extends Application {
@Override public void onCreate() { @Override public void onCreate() {
super.onCreate(); super.onCreate();
AbsFrame.init(this); AbsFrame.init(this);
DownloadManager.init(this); DownloadManager.init(this);
} }
} }

@ -1,14 +1,13 @@
package com.arialyy.simple.base; package com.arialyy.simple.base;
import android.content.Context; import android.content.Context;
import com.arialyy.frame.module.AbsModule; import com.arialyy.frame.module.AbsModule;
/** /**
* Created by Lyy on 2016/9/27. * Created by Lyy on 2016/9/27.
*/ */
public class BaseModule extends AbsModule { public class BaseModule extends AbsModule {
public BaseModule(Context context) { public BaseModule(Context context) {
super(context); super(context);
} }
} }

@ -26,7 +26,7 @@ public class DownloadModule extends BaseModule {
* 设置下载数据 * 设置下载数据
*/ */
public List<DownloadEntity> getDownloadData() { public List<DownloadEntity> getDownloadData() {
List<DownloadEntity> list = DownloadEntity.findAllData(DownloadEntity.class); List<DownloadEntity> list = DownloadEntity.findAllData(DownloadEntity.class);
List<DownloadEntity> newDownload = createNewDownload(); List<DownloadEntity> newDownload = createNewDownload();
if (list == null) { if (list == null) {
list = newDownload; list = newDownload;
@ -66,10 +66,11 @@ public class DownloadModule extends BaseModule {
*/ */
private List<DownloadEntity> createNewDownload() { private List<DownloadEntity> createNewDownload() {
List<DownloadEntity> list = new ArrayList<>(); List<DownloadEntity> list = new ArrayList<>();
String[] urls = getContext().getResources().getStringArray(R.array.test_apk_download_url); String[] urls =
getContext().getResources().getStringArray(R.array.test_apk_download_url);
for (String url : urls) { for (String url : urls) {
String fileName = Util.keyToHashCode(url) + ".apk"; String fileName = Util.keyToHashCode(url) + ".apk";
DownloadEntity entity = new DownloadEntity(); DownloadEntity entity = new DownloadEntity();
entity.setDownloadUrl(url); entity.setDownloadUrl(url);
entity.setDownloadPath(getDownloadPath(url)); entity.setDownloadPath(getDownloadPath(url));
entity.setFileName(fileName); entity.setFileName(fileName);

@ -7,178 +7,177 @@ import android.graphics.Paint;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue; import android.util.TypedValue;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import com.arialyy.simple.R; import com.arialyy.simple.R;
public class HorizontalProgressBarWithNumber extends ProgressBar { public class HorizontalProgressBarWithNumber extends ProgressBar {
private static final int DEFAULT_TEXT_SIZE = 10; private static final int DEFAULT_TEXT_SIZE = 10;
private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1; private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;
private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da; private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;
private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2; private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2; private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;
private static final int DEFAULT_SIZE_TEXT_OFFSET = 10; private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;
/** /**
* painter of all drawing things * painter of all drawing things
*/ */
protected Paint mPaint = new Paint(); protected Paint mPaint = new Paint();
/** /**
* color of progress number * color of progress number
*/ */
protected int mTextColor = DEFAULT_TEXT_COLOR; protected int mTextColor = DEFAULT_TEXT_COLOR;
/** /**
* size of text (sp) * size of text (sp)
*/ */
protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE); protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);
/** /**
* offset of draw progress * offset of draw progress
*/ */
protected int mTextOffset = dp2px( protected int mTextOffset =
DEFAULT_SIZE_TEXT_OFFSET); dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/** /**
* height of reached progress bar * height of reached progress bar
*/ */
protected int mReachedProgressBarHeight = dp2px( protected int mReachedProgressBarHeight =
DEFAULT_HEIGHT_REACHED_PROGRESS_BAR); dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/** /**
* color of reached bar * color of reached bar
*/ */
protected int mReachedBarColor = DEFAULT_TEXT_COLOR; protected int mReachedBarColor = DEFAULT_TEXT_COLOR;
/** /**
* color of unreached bar * color of unreached bar
*/ */
protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR; protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;
/** /**
* height of unreached progress bar * height of unreached progress bar
*/ */
protected int mUnReachedProgressBarHeight = dp2px( protected int mUnReachedProgressBarHeight =
DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR); dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/** /**
* view width except padding * view width except padding
*/ */
protected int mRealWidth; protected int mRealWidth;
protected boolean mIfDrawText = true; protected boolean mIfDrawText = true;
protected static final int VISIBLE = 0; protected static final int VISIBLE = 0;
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs) { public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs) {
this(context, attrs, 0); this(context, attrs, 0);
} }
public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs, int defStyle) { public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
obtainStyledAttributes(attrs); obtainStyledAttributes(attrs);
mPaint.setTextSize(mTextSize); mPaint.setTextSize(mTextSize);
mPaint.setColor(mTextColor); mPaint.setColor(mTextColor);
} }
@Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec); int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height); setMeasuredDimension(width, height);
mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft(); mRealWidth = getMeasuredWidth() - getPaddingRight() - getPaddingLeft();
} }
private int measureHeight(int measureSpec) { private int measureHeight(int measureSpec) {
int result = 0; int result = 0;
int specMode = MeasureSpec.getMode(measureSpec); int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) { if (specMode == MeasureSpec.EXACTLY) {
result = specSize; result = specSize;
} else { } else {
float textHeight = (mPaint.descent() - mPaint.ascent()); float textHeight = (mPaint.descent() - mPaint.ascent());
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max( result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight), Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight), Math.abs(textHeight)));
Math.abs(textHeight)) if (specMode == MeasureSpec.AT_MOST) {
); result = Math.min(result, specSize);
if (specMode == MeasureSpec.AT_MOST) { }
result = Math.min(result, specSize);
}
}
return result;
} }
return result;
}
/** /**
* get the styled attributes * get the styled attributes
*/ */
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, final TypedArray attributes =
R.styleable.HorizontalProgressBarWithNumber); getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes.getColor( mTextColor =
R.styleable.HorizontalProgressBarWithNumber_progress_text_color, attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR); DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension( mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size, mTextSize); R.styleable.HorizontalProgressBarWithNumber_progress_text_size, mTextSize);
mReachedBarColor = attributes.getColor( mReachedBarColor =
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color, mTextColor); attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mUnReachedBarColor = attributes.getColor( mTextColor);
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color, mUnReachedBarColor =
DEFAULT_COLOR_UNREACHED_COLOR); attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
mReachedProgressBarHeight = (int) attributes.getDimension( DEFAULT_COLOR_UNREACHED_COLOR);
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height, mReachedProgressBarHeight = (int) attributes.getDimension(
mReachedProgressBarHeight); R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
mUnReachedProgressBarHeight = (int) attributes.getDimension( mReachedProgressBarHeight);
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height, mUnReachedProgressBarHeight = (int) attributes.getDimension(
mUnReachedProgressBarHeight); R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,
mTextOffset = (int) attributes.getDimension( mUnReachedProgressBarHeight);
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset, mTextOffset); mTextOffset = (int) attributes.getDimension(
int textVisible = attributes.getInt( R.styleable.HorizontalProgressBarWithNumber_progress_text_offset, mTextOffset);
R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility, VISIBLE); int textVisible =
if (textVisible != VISIBLE) { attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
mIfDrawText = false; VISIBLE);
} if (textVisible != VISIBLE) {
attributes.recycle(); mIfDrawText = false;
} }
attributes.recycle();
}
@Override protected synchronized void onDraw(Canvas canvas) { @Override protected synchronized void onDraw(Canvas canvas) {
canvas.save(); canvas.save();
canvas.translate(getPaddingLeft(), getHeight() / 2); canvas.translate(getPaddingLeft(), getHeight() / 2);
boolean noNeedBg = false; boolean noNeedBg = false;
float radio = getProgress() * 1.0f / getMax(); float radio = getProgress() * 1.0f / getMax();
float progressPosX = (int) (mRealWidth * radio); float progressPosX = (int) (mRealWidth * radio);
String text = getProgress() + "%"; String text = getProgress() + "%";
// mPaint.getTextBounds(text, 0, text.length(), mTextBound); // mPaint.getTextBounds(text, 0, text.length(), mTextBound);
float textWidth = mPaint.measureText(text); float textWidth = mPaint.measureText(text);
float textHeight = (mPaint.descent() + mPaint.ascent()) / 2; float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;
if (progressPosX + textWidth > mRealWidth) { if (progressPosX + textWidth > mRealWidth) {
progressPosX = mRealWidth - textWidth; progressPosX = mRealWidth - textWidth;
noNeedBg = true; noNeedBg = true;
}
// draw reached bar
float endX = progressPosX - mTextOffset / 2;
if (endX > 0) {
mPaint.setColor(mReachedBarColor);
mPaint.setStrokeWidth(mReachedProgressBarHeight);
canvas.drawLine(0, 0, endX, 0, mPaint);
}
// draw progress bar
// measure text bound
if (mIfDrawText) {
mPaint.setColor(mTextColor);
canvas.drawText(text, progressPosX, -textHeight, mPaint);
}
// draw unreached bar
if (!noNeedBg) {
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
}
canvas.restore();
} }
// draw reached bar
/** float endX = progressPosX - mTextOffset / 2;
* dp 2 px if (endX > 0) {
*/ mPaint.setColor(mReachedBarColor);
protected int dp2px(int dpVal) { mPaint.setStrokeWidth(mReachedProgressBarHeight);
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, canvas.drawLine(0, 0, endX, 0, mPaint);
getResources().getDisplayMetrics());
} }
// draw progress bar
/** // measure text bound
* sp 2 px if (mIfDrawText) {
*/ mPaint.setColor(mTextColor);
protected int sp2px(int spVal) { canvas.drawText(text, progressPosX, -textHeight, mPaint);
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, }
getResources().getDisplayMetrics()); // draw unreached bar
if (!noNeedBg) {
float start = progressPosX + mTextOffset / 2 + textWidth;
mPaint.setColor(mUnReachedBarColor);
mPaint.setStrokeWidth(mUnReachedProgressBarHeight);
canvas.drawLine(start, 0, mRealWidth, 0, mPaint);
} }
canvas.restore();
}
/**
* dp 2 px
*/
protected int dp2px(int dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
getResources().getDisplayMetrics());
}
/**
* sp 2 px
*/
protected int sp2px(int spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
getResources().getDisplayMetrics());
}
} }

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout <layout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
> >
<LinearLayout <LinearLayout

@ -1,35 +1,34 @@
<?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: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.SingleTaskActivity"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:fitsSystemWindows="true" android:theme="@style/AppTheme.AppBarOverlay"
tools:context="com.arialyy.simple.activity.SingleTaskActivity"
> >
<android.support.design.widget.AppBarLayout <include layout="@layout/layout_bar"/>
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
>
<include layout="@layout/layout_bar"/>
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<include layout="@layout/content_single"/> <include layout="@layout/content_single"/>
<android.support.design.widget.FloatingActionButton <android.support.design.widget.FloatingActionButton
android:id="@+id/fab" android:id="@+id/fab"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin" android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email" android:src="@android:drawable/ic_dialog_email"
/> />
</android.support.design.widget.CoordinatorLayout> </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.SingleTaskActivity" tools:context="com.arialyy.simple.activity.SingleTaskActivity"
tools:showIn="@layout/activity_single" tools:showIn="@layout/activity_single"
> >
<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"
/>
<TextView <LinearLayout
android:id="@+id/size" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/progressBar"
android:orientation="horizontal"
>
<Button
android:id="@+id/start"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:layout_weight="1"
android:layout_alignTop="@+id/progressBar" android:onClick="onClick"
android:layout_marginRight="16dp" android:text="开始"
android:text="ssss"
android:textSize="16sp"
/> />
<LinearLayout <Button
android:layout_width="match_parent" android:id="@+id/stop"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@+id/progressBar" android:layout_weight="1"
android:orientation="horizontal" android:onClick="onClick"
> android:text="暂停"
/>
<Button
android:id="@+id/start"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="开始"
/>
<Button
android:id="@+id/stop"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="暂停"
/>
<Button <Button
android:id="@+id/cancel" android:id="@+id/cancel"
style="?buttonBarButtonStyle" style="?buttonBarButtonStyle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:onClick="onClick" android:onClick="onClick"
android:text="删除任务" android:text="删除任务"
/> />
</LinearLayout> </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,28 +1,28 @@
<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>
<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" 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>
<!--设置导航栏内容可用--> <!--设置导航栏内容可用-->
<!--<item name="android:windowTranslucentNavigation">true</item>--> <!--<item name="android:windowTranslucentNavigation">true</item>-->
<!--设置状态栏内容可以--> <!--设置状态栏内容可以-->
<!--<item name="android:windowTranslucentStatus">true</item>--> <!--<item name="android:windowTranslucentStatus">true</item>-->
<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>
<item name="android:windowIsTranslucent">true</item> <item name="android:windowIsTranslucent">true</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,18 +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"> <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/22/94/822260b849944492caadd2983f9bb624.apk</item> <!--300M的文件-->
<item>http://static.gaoshouyou.com/d/21/e8/61218d78d0e8b79df68dbc18dd484c97.apk</item> <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/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk</item>
<item>http://static.gaoshouyou.com/d/d4/4f/d6d48db3794fb9ecf47e83c346570881.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/18/cf/ba18113bc6cf56c1c5863e761e717003.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/60/17/2460921367173ea7145f11194a6f2587.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/32/e0/1a32123ecbe0ee010d35479df248f90f.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.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/e6/f5/4de6329f9cf5dc3a1d1e6bbcca0d003c.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/6e/e5/ff6ecaaf45e532e6d07747af82357472.apk</item>--> <!--<item>http://static.gaoshouyou.com/d/6e/e5/ff6ecaaf45e532e6d07747af82357472.apk</item>-->
<!--<item>http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk</item>--> <!--<item>http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk</item>-->
</string-array> </string-array>
</resources> </resources>

@ -1,25 +1,25 @@
<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>
<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.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="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.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>

@ -1,14 +0,0 @@
package com.example.arial.downloaddemo;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test public void addition_isCorrect() throws Exception {
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>

@ -3,13 +3,10 @@ package com.arialyy.downloadutil.core;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.core.command.IDownloadCommand; import com.arialyy.downloadutil.core.command.IDownloadCommand;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.orm.DbEntity; import com.arialyy.downloadutil.orm.DbEntity;
import com.arialyy.downloadutil.orm.DbUtil; import com.arialyy.downloadutil.orm.DbUtil;
import com.arialyy.downloadutil.util.Task;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -18,122 +15,122 @@ import java.util.List;
* 下载管理器通过命令的方式控制下载 * 下载管理器通过命令的方式控制下载
*/ */
public class DownloadManager { public class DownloadManager {
private static final String TAG = "DownloadManager"; private static final String TAG = "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 ENTITY = "DOWNLOAD_ENTITY"; public static final String ENTITY = "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;
DownloadTarget.init(context); DownloadTarget.init(context);
DbUtil.init(context); DbUtil.init(context);
} }
public static DownloadManager init(Context context) { public static DownloadManager init(Context context) {
if (context instanceof Application) { if (context instanceof Application) {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (LOCK) { synchronized (LOCK) {
INSTANCE = new DownloadManager(context.getApplicationContext()); INSTANCE = new DownloadManager(context.getApplicationContext());
}
}
} else {
Log.e(TAG, "Context 只能为application");
} }
return INSTANCE; }
} else {
Log.e(TAG, "Context 只能为application");
} }
return INSTANCE;
}
public static DownloadManager getInstance() { public static DownloadManager getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
throw new NullPointerException("请在Application中调用init进行下载器注册"); throw new NullPointerException("请在Application中调用init进行下载器注册");
}
return INSTANCE;
} }
return INSTANCE;
public List<DownloadEntity> getAllDownloadEntity(){ }
return DbEntity.findAllData(DownloadEntity.class);
} public List<DownloadEntity> getAllDownloadEntity() {
return DbEntity.findAllData(DownloadEntity.class);
/** }
* 设置命令
*/ /**
public DownloadManager setCommand(IDownloadCommand command) { * 设置命令
mCommands.add(command); */
return this; public DownloadManager setCommand(IDownloadCommand command) {
} mCommands.add(command);
return this;
/** }
* 设置一组命令
*/ /**
public DownloadManager setCommands(List<IDownloadCommand> commands) { * 设置一组命令
if (commands != null && commands.size() > 0) { */
mCommands.addAll(commands); public DownloadManager setCommands(List<IDownloadCommand> commands) {
} if (commands != null && commands.size() > 0) {
return this; mCommands.addAll(commands);
} }
return this;
/** }
* 执行所有设置的命令
*/ /**
public synchronized void exe() { * 执行所有设置的命令
for (IDownloadCommand command : mCommands) { */
command.executeComment(); public synchronized void exe() {
} for (IDownloadCommand command : mCommands) {
mCommands.clear(); command.executeComment();
} }
mCommands.clear();
}
} }

@ -2,7 +2,6 @@ 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;
import com.arialyy.downloadutil.util.Task; import com.arialyy.downloadutil.util.Task;
@ -11,105 +10,105 @@ import com.arialyy.downloadutil.util.Task;
* 下载任务调度类 * 下载任务调度类
*/ */
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() { public static DownloadTarget getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
throw new NullPointerException("请在Application中调用init进行注册"); throw new NullPointerException("请在Application中调用init进行注册");
}
return INSTANCE;
} }
return INSTANCE;
static DownloadTarget init(Context context) { }
if (INSTANCE == null) {
synchronized (LOCK) { static DownloadTarget init(Context context) {
INSTANCE = new DownloadTarget(context.getApplicationContext()); if (INSTANCE == null) {
} synchronized (LOCK) {
} INSTANCE = new DownloadTarget(context.getApplicationContext());
return INSTANCE; }
} }
return INSTANCE;
}
private DownloadTarget() { private DownloadTarget() {
super(); super();
} }
private DownloadTarget(Context context) { private DownloadTarget(Context context) {
super(); super();
mContext = context; mContext = context;
} }
@Override public void startTask(Task task) { @Override public void startTask(Task task) {
if (mExecutePool.putTask(task)) { if (mExecutePool.putTask(task)) {
task.start(); task.start();
}
} }
}
@Override public void stopTask(Task task) {
if (task.isDownloading()) { @Override public void stopTask(Task task) {
if (mExecutePool.removeTask(task)) { if (task.isDownloading()) {
task.stop(); if (mExecutePool.removeTask(task)) {
} task.stop();
}else { }
task.stop(); } else {
Log.w(TAG, "停止任务失败,【任务已经停止】"); task.stop();
} Log.w(TAG, "停止任务失败,【任务已经停止】");
} }
}
@Override public void cancelTask(Task task) { @Override public void cancelTask(Task task) {
if (mExecutePool.removeTask(task) || mCachePool.removeTask(task)) { if (mExecutePool.removeTask(task) || mCachePool.removeTask(task)) {
task.cancel(); task.cancel();
}
} }
}
@Override public void reTryStart(Task task) { @Override public void reTryStart(Task task) {
if (!task.isDownloading()) { if (!task.isDownloading()) {
task.start(); task.start();
} else { } else {
Log.w(TAG, "任务没有完全停止,重试下载失败"); Log.w(TAG, "任务没有完全停止,重试下载失败");
}
} }
}
@Override public Task createTask(DownloadEntity entity) {
Task task = TaskFactory.getInstance().createTask(mContext, entity, mTaskHandler); @Override public Task createTask(DownloadEntity entity) {
mCachePool.putTask(task); Task task = TaskFactory.getInstance().createTask(mContext, entity, mTaskHandler);
return task; mCachePool.putTask(task);
return task;
}
@Override public Task getTask(DownloadEntity entity) {
Task task = mExecutePool.getTask(entity.getDownloadUrl());
if (task == null) {
task = mCachePool.getTask(entity.getDownloadUrl());
} }
return task;
@Override public Task getTask(DownloadEntity entity) { }
Task task = mExecutePool.getTask(entity.getDownloadUrl());
if (task == null) { @Override public int getTaskState(DownloadEntity entity) {
task = mCachePool.getTask(entity.getDownloadUrl()); Task task = getTask(entity);
} if (task == null) {
return task; Log.e(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的下载任务");
return -1;
} }
return task.getDownloadEntity().getState();
@Override public int getTaskState(DownloadEntity entity) { }
Task task = getTask(entity);
if (task == null) { @Override public void removeTask(DownloadEntity entity) {
Log.e(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的下载任务"); Task task = mExecutePool.getTask(entity.getDownloadUrl());
return -1; if (task != null) {
} Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
return task.getDownloadEntity().getState(); } else {
task = mCachePool.getTask(entity.getDownloadUrl());
} }
if (task != null) {
@Override public void removeTask(DownloadEntity entity) { Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
Task task = mExecutePool.getTask(entity.getDownloadUrl()); } else {
if (task != null) { Log.w(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的任务");
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
} else {
task = mCachePool.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,7 +3,6 @@ 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;
@ -16,212 +15,210 @@ import com.arialyy.downloadutil.util.Task;
* 任务下载器提供抽象的方法供具体的实现类操作 * 任务下载器提供抽象的方法供具体的实现类操作
*/ */
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 static final int START = 1; public void onTaskStart(Task task);
/**
* 任务停止
*/
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; public void onTaskStop(Task task);
/** /**
* 超时时间 * 任务取消
*/ */
protected long mTimeOut = 10000; public void onTaskCancel(Task task);
/** /**
* 下载器任务监听 * 任务下载失败
*/ */
protected OnTargetListener mTargetListener; public void onTaskFail(Task task);
/** /**
* Target处理任务监听 * 任务完成
*/ */
public interface OnTargetListener { public void onTaskComplete(Task task);
/** }
* 任务开始
*/ protected IDownloadTarget() {
public void onTaskStart(Task task); mTaskHandler = new AutoTaskHandler(this);
}
/**
* 任务停止 /**
*/ * 设置下载器监听
public void onTaskStop(Task task); *
* @param targetListener {@link OnTargetListener}
/** */
* 任务取消 public void setOnTargetListener(OnTargetListener targetListener) {
*/ this.mTargetListener = targetListener;
public void onTaskCancel(Task task); }
/** /**
* 任务下载失败 * 获取任务执行池
*/ */
public void onTaskFail(Task task); public ExecutePool getExecutePool() {
return mExecutePool;
/** }
* 任务完成
*/ /**
public void onTaskComplete(Task task); * 获取当前运行的任务数
*
* @return 当前正在执行的任务数
*/
public int getCurrentTaskNum() {
return mExecutePool.size();
}
/**
* 获取缓存任务数
*
* @return 获取缓存的任务数
*/
public int getCacheTaskNum() {
return mCachePool.size();
}
public void setFailNum(int mFailNum) {
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;
} }
protected IDownloadTarget() { @Override public void handleMessage(Message msg) {
mTaskHandler = new AutoTaskHandler(this); super.handleMessage(msg);
} DownloadEntity entity = (DownloadEntity) msg.obj;
if (entity == null) {
/** Log.e(TAG, "请传入下载实体DownloadEntity");
* 设置下载器监听 return;
* }
* @param targetListener {@link OnTargetListener} switch (msg.what) {
*/ case STOP:
public void setOnTargetListener(OnTargetListener targetListener) { case CANCEL:
this.mTargetListener = targetListener; case COMPLETE:
startNextTask(entity);
break;
case FAIL:
handleFailTask(entity);
break;
}
callback(msg.what, entity);
} }
/** /**
* 获取任务执行池 * 回调
* *
* @return * @param state 状态
* @param entity 下载实体
*/ */
public ExecutePool getExecutePool() { private void callback(int state, DownloadEntity entity) {
return mExecutePool; 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.onTaskComplete(task);
break;
case FAIL:
target.mTargetListener.onTaskFail(task);
break;
}
}
} }
/** /**
* 获取当前运行的任务数 * 处理下载任务下载失败的情形
* *
* @return 当前正在执行的任务数 * @param entity 失败实体
*/ */
public int getCurrentTaskNum() { private void handleFailTask(DownloadEntity entity) {
return mExecutePool.size(); if (entity.getFailNum() <= target.mFailNum) {
Task task = target.getTask(entity);
target.reTryStart(task);
} else {
startNextTask(entity);
}
} }
/** /**
* 获取缓存任务数 * 启动下一个任务条件任务停止取消下载任务完成
* *
* @return 获取缓存的任务数 * @param entity 通过Handler传递的下载实体
*/
public int getCacheTaskNum() {
return mCachePool.size();
}
public void setFailNum(int mFailNum) {
this.mFailNum = mFailNum;
}
public void setTimeOut(long timeOut) {
this.mTimeOut = timeOut;
}
/**
* 自动处理任务停止下载失败取消下载自动下载下一个任务的操作
*/ */
private static class AutoTaskHandler extends Handler { private void startNextTask(DownloadEntity entity) {
private static final String TAG = "AutoTaskHandler"; target.removeTask(entity);
IDownloadTarget target; Task newTask = target.getNextTask();
if (newTask == null) {
public AutoTaskHandler(IDownloadTarget target) { Log.w(TAG, "没有下一任务");
this.target = target; return;
} }
if (newTask.getDownloadEntity().getState() == DownloadEntity.STATE_WAIT) {
@Override public void handleMessage(Message msg) { target.startTask(newTask);
super.handleMessage(msg); }
DownloadEntity entity = (DownloadEntity) msg.obj;
if (entity == null) {
Log.e(TAG, "请传入下载实体DownloadEntity");
return;
}
switch (msg.what) {
case STOP:
case CANCEL:
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.onTaskComplete(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.w(TAG, "没有下一任务");
return;
}
if (newTask.getDownloadEntity().getState() == DownloadEntity.STATE_WAIT) {
target.startTask(newTask);
}
}
} }
}
} }

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

@ -2,7 +2,6 @@ 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;
import com.arialyy.downloadutil.util.Task; import com.arialyy.downloadutil.util.Task;
@ -11,33 +10,33 @@ import com.arialyy.downloadutil.util.Task;
* 任务工厂 * 任务工厂
*/ */
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 TaskFactory() { private static final Object LOCK = new Object();
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) {
* @param entity 下载实体 INSTANCE = new TaskFactory();
* @param handler "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.build();
} }
return INSTANCE;
}
/**
* 创建普通下载任务
*
* @param entity 下载实体
* @param handler "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.build();
}
} }

@ -2,9 +2,8 @@ package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/** /**
* Created by lyy on 2016/8/22. * Created by lyy on 2016/8/22.
@ -12,16 +11,16 @@ 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() {
Task task = target.getTask(mEntity); Task task = target.getTask(mEntity);
if (task == null) { if (task == null) {
target.createTask(mEntity); target.createTask(mEntity);
}else { } else {
Log.w(TAG, "添加命令执行失败,【该任务已经存在】"); Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
}
} }
}
} }

@ -1,9 +1,8 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/** /**
* Created by lyy on 2016/9/20. * Created by lyy on 2016/9/20.
@ -11,17 +10,17 @@ 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() {
Task task = target.getTask(mEntity); Task task = target.getTask(mEntity);
if (task == null){ if (task == null) {
task = target.createTask(mEntity); task = target.createTask(mEntity);
} }
if (task != null) { if (task != null) {
target.cancelTask(task); target.cancelTask(task);
}
} }
}
} }

@ -1,7 +1,6 @@
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,113 +8,113 @@ 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_RESUME = 0x127; public static final int TASK_RESUME = 0x127;
/** /**
* 取消任务 * 取消任务
*/ */
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_RESUME: case TASK_RESUME:
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,7 +1,6 @@
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;
@ -13,40 +12,40 @@ import com.arialyy.downloadutil.util.Util;
* 下载命令 * 下载命令
*/ */
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;
protected String TAG; protected String TAG;
/** /**
* @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();
mContext = context;
mEntity = entity;
TAG = Util.getClassName(this);
} }
target = DownloadTarget.getInstance();
mContext = context;
mEntity = entity;
TAG = Util.getClassName(this);
}
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,9 +1,8 @@
package com.arialyy.downloadutil.core.command; package com.arialyy.downloadutil.core.command;
import android.content.Context; import android.content.Context;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/** /**
* Created by lyy on 2016/8/22. * Created by lyy on 2016/8/22.
@ -11,17 +10,17 @@ 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() {
Task task = target.getTask(mEntity); Task task = target.getTask(mEntity);
if (task == null) { if (task == null) {
task = target.createTask(mEntity); task = target.createTask(mEntity);
} }
if (task != null) { if (task != null) {
target.startTask(task); target.startTask(task);
}
} }
}
} }

@ -1,7 +1,6 @@
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;
/** /**
@ -10,16 +9,16 @@ 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);
} }
} }

@ -2,7 +2,6 @@ package com.arialyy.downloadutil.core.command;
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;
import com.arialyy.downloadutil.util.Task; import com.arialyy.downloadutil.util.Task;
@ -12,25 +11,25 @@ import com.arialyy.downloadutil.util.Task;
*/ */
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() {
Task task = target.getTask(mEntity); Task task = target.getTask(mEntity);
if (task == null) { if (task == null) {
if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) { if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
task = target.createTask(mEntity); task = target.createTask(mEntity);
target.stopTask(task); target.stopTask(task);
} else { } else {
Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】"); Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
} }
} else { } else {
target.stopTask(task); target.stopTask(task);
}
} }
}
} }

@ -7,31 +7,31 @@ import com.arialyy.downloadutil.util.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.util.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();
} }

@ -1,7 +1,7 @@
package com.arialyy.downloadutil.core.inf; package com.arialyy.downloadutil.core.inf;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/** /**
* Created by lyy on 2016/8/16. * Created by lyy on 2016/8/16.
@ -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,11 +2,9 @@ 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.inf.IPool; import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Task; import com.arialyy.downloadutil.util.Task;
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.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -16,97 +14,97 @@ import java.util.concurrent.LinkedBlockingQueue;
* 任务缓存池所有下载任务最先缓存在这个池中 * 任务缓存池所有下载任务最先缓存在这个池中
*/ */
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 final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数 private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数
private static volatile CachePool INSTANCE = null; private static volatile CachePool INSTANCE = null;
private Map<String, Task> mCacheArray; private Map<String, Task> mCacheArray;
private LinkedBlockingQueue<Task> mCacheQueue; private LinkedBlockingQueue<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 LinkedBlockingQueue<>(MAX_NUM); mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
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.w(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】"); Log.w(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
return false; return false;
} else { } else {
boolean s = mCacheQueue.offer(task); boolean s = mCacheQueue.offer(task);
Log.d(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); Log.d(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
if (s) { if (s) {
mCacheArray.put(Util.keyToHashKey(url), task); 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,11 +2,9 @@ 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.util.Task;
import com.arialyy.downloadutil.core.inf.IPool; import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Task;
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;
@ -17,137 +15,137 @@ 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;
}
String url = task.getDownloadEntity().getDownloadUrl();
if (mExecuteQueue.contains(task)) {
Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
return false;
} else {
if (mExecuteQueue.size() >= SIZE) {
if (pollFirstTask()) {
return putNewTask(task);
}
} else {
return putNewTask(task);
}
}
}
return false; return false;
} }
String url = task.getDownloadEntity().getDownloadUrl();
/** if (mExecuteQueue.contains(task)) {
* 添加新任务 Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
* return false;
* @param newTask 新下载任务 } else {
*/ if (mExecuteQueue.size() >= SIZE) {
private boolean putNewTask(Task newTask) { if (pollFirstTask()) {
String url = newTask.getDownloadEntity().getDownloadUrl(); return putNewTask(task);
boolean s = mExecuteQueue.offer(newTask); }
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); } else {
if (s) { return putNewTask(task);
newTask.start();
mExecuteArray.put(Util.keyToHashKey(url), newTask);
} }
return s; }
} }
return false;
}
/** /**
* 队列满时将移除下载队列中的第一个任务 * 添加新任务
*/ *
private boolean pollFirstTask() { * @param newTask 新下载任务
try { */
Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); private boolean putNewTask(Task newTask) {
if (oldTask == null) { String url = newTask.getDownloadEntity().getDownloadUrl();
Log.e(TAG, "移除任务失败"); boolean s = mExecuteQueue.offer(newTask);
return false; Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
} if (s) {
oldTask.stop(); newTask.start();
// wait(200); mExecuteArray.put(Util.keyToHashKey(url), newTask);
String key = Util.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl());
mExecuteArray.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
return true;
} }
return s;
}
@Override public Task pollTask() { /**
synchronized (LOCK) { * 队列满时将移除下载队列中的第一个任务
Task task = mExecuteQueue.poll(); */
if (task != null) { private boolean pollFirstTask() {
String url = task.getDownloadEntity().getDownloadUrl(); try {
mExecuteArray.remove(Util.keyToHashKey(url)); Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
} if (oldTask == null) {
return task; Log.e(TAG, "移除任务失败");
} return false;
}
oldTask.stop();
// wait(200);
String key = Util.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl());
mExecuteArray.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
} }
return true;
}
@Override public Task getTask(String downloadUrl) { @Override public Task pollTask() {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { Task task = mExecuteQueue.poll();
Log.e(TAG, "请传入有效的下载链接"); if (task != null) {
return null; String url = task.getDownloadEntity().getDownloadUrl();
} mExecuteArray.remove(Util.keyToHashKey(url));
String key = Util.keyToHashKey(downloadUrl); }
return mExecuteArray.get(key); return task;
}
} }
}
@Override public boolean removeTask(Task task) { @Override public Task getTask(String downloadUrl) {
synchronized (LOCK) { synchronized (LOCK) {
if (task == null) { if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "任务不能为空"); Log.e(TAG, "请传入有效的下载链接");
return false; return null;
} else { }
String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl()); String key = Util.keyToHashKey(downloadUrl);
mExecuteArray.remove(key); return mExecuteArray.get(key);
return mExecuteQueue.remove(task);
}
}
} }
}
@Override public boolean removeTask(String downloadUrl) { @Override public boolean removeTask(Task task) {
synchronized (LOCK) { synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (task == null) {
Log.e(TAG, "请传入有效的下载链接"); Log.e(TAG, "任务不能为空");
return false; return false;
} } else {
String key = Util.keyToHashKey(downloadUrl); String key = Util.keyToHashKey(task.getDownloadEntity().getDownloadUrl());
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 boolean removeTask(String downloadUrl) {
return mExecuteQueue.size(); synchronized (LOCK) {
if (TextUtils.isEmpty(downloadUrl)) {
Log.e(TAG, "请传入有效的下载链接");
return false;
}
String key = Util.keyToHashKey(downloadUrl);
Task task = mExecuteArray.get(key);
mExecuteArray.remove(key);
return mExecuteQueue.remove(task);
} }
}
@Override public int size() {
return mExecuteQueue.size();
}
} }

@ -2,7 +2,6 @@ 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;
import com.arialyy.downloadutil.orm.Ignore; import com.arialyy.downloadutil.orm.Ignore;
@ -11,179 +10,179 @@ import com.arialyy.downloadutil.orm.Ignore;
* 下载实体 * 下载实体
*/ */
public class DownloadEntity extends DbEntity implements Parcelable, Cloneable { public class DownloadEntity extends DbEntity implements Parcelable, Cloneable {
/** /**
* 其它状态 * 其它状态
*/ */
@Ignore public static final int STATE_OTHER = -1; @Ignore public static final int STATE_OTHER = -1;
/** /**
* 失败状态 * 失败状态
*/ */
@Ignore public static final int STATE_FAIL = 0; @Ignore public static final int STATE_FAIL = 0;
/** /**
* 完成状态 * 完成状态
*/ */
@Ignore public static final int STATE_COMPLETE = 1; @Ignore public static final int STATE_COMPLETE = 1;
/** /**
* 停止状态 * 停止状态
*/ */
@Ignore public static final int STATE_STOP = 2; @Ignore public static final int STATE_STOP = 2;
/** /**
* 未开始状态 * 未开始状态
*/ */
@Ignore public static final int STATE_WAIT = 3; @Ignore public static final int STATE_WAIT = 3;
/** /**
* 下载中 * 下载中
*/ */
@Ignore public static final int STATE_DOWNLOAD_ING = 4; @Ignore public static final int STATE_DOWNLOAD_ING = 4;
/** /**
* 取消下载 * 取消下载
*/ */
@Ignore public static final int STATE_CANCEL = 5; @Ignore 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 DownloadEntity() { public DownloadEntity() {
} }
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();
} }
@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 ? (byte) 1 : (byte) 0);
dest.writeLong(this.currentProgress); dest.writeLong(this.currentProgress);
dest.writeInt(this.failNum); dest.writeInt(this.failNum);
} }
protected DownloadEntity(Parcel in) { protected DownloadEntity(Parcel in) {
this.downloadUrl = in.readString(); this.downloadUrl = in.readString();
this.downloadPath = in.readString(); this.downloadPath = in.readString();
this.completeTime = in.readLong(); this.completeTime = in.readLong();
this.fileSize = in.readLong(); this.fileSize = in.readLong();
this.state = in.readInt(); this.state = in.readInt();
this.isDownloadComplete = in.readByte() != 0; this.isDownloadComplete = in.readByte() != 0;
this.currentProgress = in.readLong(); this.currentProgress = in.readLong();
this.failNum = in.readInt(); this.failNum = in.readInt();
} }
@Ignore public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() { @Ignore public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() {
@Override public DownloadEntity createFromParcel(Parcel source) { @Override public DownloadEntity createFromParcel(Parcel source) {
return new DownloadEntity(source); return new DownloadEntity(source);
} }
@Override public DownloadEntity[] newArray(int size) { @Override public DownloadEntity[] newArray(int size) {
return new DownloadEntity[size]; return new DownloadEntity[size];
} }
}; };
@Override public String toString() { @Override public String toString() {
return "DownloadEntity{" + return "DownloadEntity{" +
"downloadUrl='" + downloadUrl + '\'' + "downloadUrl='" + downloadUrl + '\'' +
", downloadPath='" + downloadPath + '\'' + ", downloadPath='" + downloadPath + '\'' +
", completeTime=" + completeTime + ", completeTime=" + completeTime +
", fileSize=" + fileSize + ", fileSize=" + fileSize +
", state=" + state + ", state=" + state +
", isDownloadComplete=" + isDownloadComplete + ", isDownloadComplete=" + isDownloadComplete +
", currentProgress=" + currentProgress + ", currentProgress=" + currentProgress +
", failNum=" + failNum + ", failNum=" + failNum +
'}'; '}';
} }
} }

@ -3,10 +3,8 @@ 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;
/** /**
@ -14,38 +12,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_download_path_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;
}
} }

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.help; package com.arialyy.downloadutil.help;
import android.os.Environment; import android.os.Environment;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -11,53 +10,45 @@ import java.security.NoSuchAlgorithmException;
*/ */
public class PathHelp { public class PathHelp {
/** /**
* 下载链接转换保存路径 * 下载链接转换保存路径
* *
* @param downloadUrl 下载链接 * @param downloadUrl 下载链接
* @return 保存路径 * @return 保存路径
*/ */
public static String urlconvertPath(String downloadUrl) { public static String urlconvertPath(String downloadUrl) {
return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey( return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey(downloadUrl);
downloadUrl); }
}
/** /**
* 字符串转换为hash码 * 字符串转换为hash码
* */
* @param str public static String StringToHashKey(String str) {
* @return String cacheKey;
*/ try {
public static String StringToHashKey(String str) { final MessageDigest mDigest = MessageDigest.getInstance("MD5");
String cacheKey; mDigest.update(str.getBytes());
try { cacheKey = bytesToHexString(mDigest.digest());
final MessageDigest mDigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) {
mDigest.update(str.getBytes()); cacheKey = String.valueOf(str.hashCode());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(str.hashCode());
}
return cacheKey;
} }
return cacheKey;
}
/** /**
* 将普通字符串转换为16位进制字符串 * 将普通字符串转换为16位进制字符串
* */
* @param src public static String bytesToHexString(byte[] src) {
* @return StringBuilder stringBuilder = new StringBuilder("0x");
*/ if (src == null || src.length <= 0) {
public static String bytesToHexString(byte[] src) { return null;
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();
} }
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();
}
} }

@ -1,9 +1,7 @@
package com.arialyy.downloadutil.orm; package com.arialyy.downloadutil.orm;
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.Field; import java.lang.reflect.Field;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -13,129 +11,128 @@ import java.util.List;
* 所有数据库实体父类 * 所有数据库实体父类
*/ */
public class DbEntity { public class DbEntity {
protected int rowID = -1; protected int rowID = -1;
private DbUtil mUtil = DbUtil.getInstance(); private DbUtil mUtil = DbUtil.getInstance();
protected DbEntity() { protected DbEntity() {
} }
/** /**
* 获取所有行的rowid * 获取所有行的rowid
*/ */
public int[] getRowIds() { public int[] getRowIds() {
return mUtil.getRowId(getClass()); return mUtil.getRowId(getClass());
} }
/** /**
* 获取rowid * 获取rowid
*/ */
public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) { public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) {
return mUtil.getRowId(getClass(), wheres, values); return mUtil.getRowId(getClass(), wheres, values);
}
/**
* 删除当前数据
*/
public void deleteData() {
mUtil.delData(getClass(), new Object[] { "rowid" }, new Object[] { rowID });
}
/**
* 根据条件删除数据
*/
public void deleteData(@NonNull Object[] wheres, @NonNull Object[] values) {
mUtil.delData(getClass(), wheres, values);
}
/**
* 修改数据
*/
public void update() {
mUtil.modifyData(this);
}
/**
* 保存自身如果表中已经有数据则更新数据否则插入数据
*/
public void save() {
if (mUtil.tableExists(getClass()) && thisIsExist()) {
update();
} else {
insert();
} }
}
/**
* 删除当前数据 /**
*/ * 查找数据在表中是否存在
public void deleteData() { */
mUtil.delData(getClass(), new Object[]{"rowid"}, new Object[]{rowID}); private boolean thisIsExist() {
} return findData(getClass(), new String[] { "rowid" }, new String[] { rowID + "" }) != null;
}
/**
* 根据条件删除数据 /**
*/ * 插入数据
public void deleteData(@NonNull Object[] wheres, @NonNull Object[] values) { */
mUtil.delData(getClass(), wheres, values); public void insert() {
} mUtil.insertData(this);
updateRowID();
/** }
* 修改数据
*/ private void updateRowID() {
public void update() { try {
mUtil.modifyData(this); Field[] fields = Util.getFields(getClass());
} List<String> where = new ArrayList<>();
List<String> values = new ArrayList<>();
for (Field field : fields) {
/** field.setAccessible(true);
* 保存自身如果表中已经有数据则更新数据否则插入数据 Ignore ignore = field.getAnnotation(Ignore.class);
*/ if (ignore != null && ignore.value()) {
public void save() { continue;
if (mUtil.tableExists(getClass()) && thisIsExist()) {
update();
} else {
insert();
}
}
/**
* 查找数据在表中是否存在
*/
private boolean thisIsExist() {
return findData(getClass(), new String[]{"rowid"}, new String[]{rowID + ""}) != null;
}
/**
* 插入数据
*/
public void insert() {
mUtil.insertData(this);
updateRowID();
}
private void updateRowID() {
try {
Field[] fields = Util.getFields(getClass());
List<String> where = new ArrayList<>();
List<String> values = new ArrayList<>();
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
}
where.add(field.getName());
values.add(field.get(this) + "");
}
DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]),
values.toArray(new String[values.size()]));
if (entity != null) {
rowID = entity.rowID;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
where.add(field.getName());
values.add(field.get(this) + "");
}
DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]),
values.toArray(new String[values.size()]));
if (entity != null) {
rowID = entity.rowID;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
}
/**
* 查询所有数据 /**
* * 查询所有数据
* @return 没有数据返回null *
*/ * @return 没有数据返回null
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) { */
DbUtil util = DbUtil.getInstance(); public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
return util.findAllData(clazz); DbUtil util = DbUtil.getInstance();
} return util.findAllData(clazz);
}
/**
* 查询一组数据 /**
* * 查询一组数据
* @return 没有数据返回null *
*/ * @return 没有数据返回null
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, @NonNull String[] wheres, */
@NonNull String[] values) { public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, @NonNull String[] wheres,
DbUtil util = DbUtil.getInstance(); @NonNull String[] values) {
return util.findData(clazz, wheres, values); DbUtil util = DbUtil.getInstance();
} return util.findData(clazz, wheres, values);
}
/**
* 查询一行数据 /**
* * 查询一行数据
* @return 没有数据返回null *
*/ * @return 没有数据返回null
public static <T extends DbEntity> T findData(Class<T> clazz, @NonNull String[] wheres, */
@NonNull String[] values) { public static <T extends DbEntity> T findData(Class<T> clazz, @NonNull String[] wheres,
DbUtil util = DbUtil.getInstance(); @NonNull String[] values) {
List<T> datas = util.findData(clazz, wheres, values); DbUtil util = DbUtil.getInstance();
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; List<T> datas = util.findData(clazz, wheres, values);
} return datas == null ? null : datas.size() > 0 ? datas.get(0) : null;
}
} }

@ -6,9 +6,7 @@ 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;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -19,407 +17,407 @@ import java.util.List;
* 数据库操作工具 * 数据库操作工具
*/ */
public class DbUtil { public class DbUtil {
private static final String TAG = "DbUtil"; private static final String TAG = "DbUtil";
private volatile static DbUtil INSTANCE = null; private volatile static DbUtil INSTANCE = null;
private static final Object LOCK = new Object(); private static final Object LOCK = new Object();
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 SQLiteDatabase mDb; private SQLiteDatabase mDb;
private SqlHelper mHelper; private SqlHelper mHelper;
private DbUtil() { private DbUtil() {
} }
public static DbUtil init(Context context) { public static DbUtil init(Context context) {
if (context instanceof Application) { if (context instanceof Application) {
synchronized (LOCK) { synchronized (LOCK) {
if (INSTANCE == null) { if (INSTANCE == null) {
INSTANCE = new DbUtil(context); INSTANCE = new DbUtil(context);
}
}
} }
return INSTANCE; }
} }
return INSTANCE;
}
private DbUtil(Context context) { private DbUtil(Context context) {
mHelper = new SqlHelper(context.getApplicationContext()); mHelper = new SqlHelper(context.getApplicationContext());
}
protected static DbUtil getInstance() {
if (INSTANCE == null) {
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册");
} }
return INSTANCE;
}
protected static DbUtil getInstance() { /**
if (INSTANCE == null) { * 删除某条数据
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册"); */
} synchronized <T extends DbEntity> void delData(Class<T> clazz, @NonNull Object[] wheres,
return INSTANCE; @NonNull Object[] values) {
mDb = mHelper.getWritableDatabase();
if (wheres.length <= 0 || values.length <= 0) {
Log.e(TAG, "输入删除条件");
return;
} else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等");
return;
}
StringBuilder sb = new StringBuilder();
sb.append("DELETE FROM ").append(Util.getClassName(clazz)).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());
close();
}
/** /**
* 删除某条数据 * 修改某行数据
*/ */
synchronized <T extends DbEntity> void delData(Class<T> clazz, @NonNull Object[] wheres, synchronized void modifyData(DbEntity dbEntity) {
@NonNull Object[] values) { mDb = mHelper.getWritableDatabase();
mDb = mHelper.getWritableDatabase(); Class<?> clazz = dbEntity.getClass();
if (wheres.length <= 0 || values.length <= 0) { Field[] fields = Util.getFields(clazz);
Log.e(TAG, "输入删除条件"); if (fields != null && fields.length > 0) {
return; StringBuilder sb = new StringBuilder();
} else if (wheres.length != values.length) { sb.append("UPDATE ").append(Util.getClassName(dbEntity)).append(" SET ");
Log.e(TAG, "key 和 vaule 长度不相等"); int i = 0;
return; for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
StringBuilder sb = new StringBuilder(); sb.append(i > 0 ? ", " : "");
sb.append("DELETE FROM ").append(Util.getClassName(clazz)).append(" WHERE "); try {
int i = 0; sb.append(field.getName())
for (Object where : wheres) { .append("='")
sb.append(where).append("=").append("'").append(values[i]).append("'"); .append(field.get(dbEntity).toString())
sb.append(i >= wheres.length - 1 ? "" : ","); .append("'");
i++; } catch (IllegalAccessException e) {
e.printStackTrace();
} }
print(DEL_DATA, sb.toString()); i++;
mDb.execSQL(sb.toString()); }
close(); sb.append(" where rowid=").append(dbEntity.rowID);
print(MODIFY_DATA, sb.toString());
mDb.execSQL(sb.toString());
} }
close();
}
/** /**
* 修改某行数据 * 遍历所有数据
*/ */
synchronized void modifyData(DbEntity dbEntity) { synchronized <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
mDb = mHelper.getWritableDatabase(); if (!tableExists(clazz)) {
Class<?> clazz = dbEntity.getClass(); createTable(clazz);
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 ? ", " : "");
try {
sb.append(field.getName())
.append("='")
.append(field.get(dbEntity).toString())
.append("'");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
i++;
}
sb.append(" where rowid=").append(dbEntity.rowID);
print(MODIFY_DATA, sb.toString());
mDb.execSQL(sb.toString());
}
close();
} }
mDb = mHelper.getReadableDatabase();
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(clazz));
print(FIND_ALL_DATA, sb.toString());
Cursor cursor = mDb.rawQuery(sb.toString(), null);
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
}
/** /**
* 遍历所有数据 * 条件查寻数据
*/ */
synchronized <T extends DbEntity> List<T> findAllData(Class<T> clazz) { synchronized <T extends DbEntity> List<T> findData(Class<T> clazz, @NonNull String[] wheres,
if (!tableExists(clazz)) { @NonNull String[] values) {
createTable(clazz); if (!tableExists(clazz)) {
} createTable(clazz);
mDb = mHelper.getReadableDatabase(); }
StringBuilder sb = new StringBuilder(); mDb = mHelper.getReadableDatabase();
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(clazz)); if (wheres.length <= 0 || values.length <= 0) {
print(FIND_ALL_DATA, sb.toString()); Log.e(TAG, "请输入查询条件");
Cursor cursor = mDb.rawQuery(sb.toString(), null); return null;
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; } else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等");
return null;
} }
StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(clazz)).append(" where ");
int i = 0;
for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ? "" : " AND ");
i++;
}
print(FIND_DATA, sb.toString());
Cursor cursor = mDb.rawQuery(sb.toString(), null);
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
}
/** /**
* 条件查寻数据 * 插入数据
*/ */
synchronized <T extends DbEntity> List<T> findData(Class<T> clazz, @NonNull String[] wheres, synchronized void insertData(DbEntity dbEntity) {
@NonNull String[] values) { Class<?> clazz = dbEntity.getClass();
if (!tableExists(clazz)) { if (!tableExists(clazz)) {
createTable(clazz); createTable(clazz);
}
mDb = mHelper.getWritableDatabase();
Field[] fields = Util.getFields(clazz);
if (fields != null && fields.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ").append(Util.getClassName(dbEntity)).append("(");
int i = 0;
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
mDb = mHelper.getReadableDatabase(); sb.append(i > 0 ? ", " : "");
if (wheres.length <= 0 || values.length <= 0) { sb.append(field.getName());
Log.e(TAG, "请输入查询条件"); i++;
return null; }
} else if (wheres.length != values.length) { sb.append(") VALUES (");
Log.e(TAG, "key 和 vaule 长度不相等"); i = 0;
return null; for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
StringBuilder sb = new StringBuilder(); sb.append(i > 0 ? ", " : "");
sb.append("SELECT rowid, * FROM ").append(Util.getClassName(clazz)).append(" where "); sb.append("'");
int i = 0; try {
for (Object where : wheres) { sb.append(field.get(dbEntity)).append("'");
sb.append(where).append("=").append("'").append(values[i]).append("'"); } catch (IllegalAccessException e) {
sb.append(i >= wheres.length - 1 ? "" : " AND "); e.printStackTrace();
i++;
} }
print(FIND_DATA, sb.toString()); i++;
Cursor cursor = mDb.rawQuery(sb.toString(), null); }
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; sb.append(")");
print(INSERT_DATA, sb.toString());
mDb.execSQL(sb.toString());
} }
close();
}
/** /**
* 插入数据 * 查找某张表是否存在
*/ */
synchronized void insertData(DbEntity dbEntity) { synchronized boolean tableExists(Class clazz) {
Class<?> clazz = dbEntity.getClass(); if (mDb == null || !mDb.isOpen()) {
if (!tableExists(clazz)) { mDb = mHelper.getReadableDatabase();
createTable(clazz);
}
mDb = mHelper.getWritableDatabase();
Field[] fields = Util.getFields(clazz);
if (fields != null && fields.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO ").append(Util.getClassName(dbEntity)).append("(");
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 ? ", " : "");
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());
}
close();
} }
Cursor cursor = null;
/** try {
* 查找某张表是否存在 StringBuilder sb = new StringBuilder();
*/ sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='");
synchronized boolean tableExists(Class clazz) { sb.append(Util.getClassName(clazz));
if (mDb == null || !mDb.isOpen()) { sb.append("'");
mDb = mHelper.getReadableDatabase(); print(TABLE_EXISTS, sb.toString());
cursor = mDb.rawQuery(sb.toString(), null);
if (cursor != null && cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
} }
Cursor cursor = null; }
try { } catch (Exception e) {
StringBuilder sb = new StringBuilder(); e.printStackTrace();
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='"); } finally {
sb.append(Util.getClassName(clazz)); if (cursor != null) cursor.close();
sb.append("'"); close();
print(TABLE_EXISTS, sb.toString());
cursor = mDb.rawQuery(sb.toString(), null);
if (cursor != null && cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) cursor.close();
close();
}
return false;
} }
return false;
}
/** /**
* 创建表 * 创建表
*/ */
private synchronized void createTable(Class clazz) { private synchronized void createTable(Class clazz) {
if (mDb == null || !mDb.isOpen()) { if (mDb == null || !mDb.isOpen()) {
mDb = mHelper.getWritableDatabase(); mDb = mHelper.getWritableDatabase();
}
Field[] fields = Util.getFields(clazz);
if (fields != null && fields.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("create table ").append(Util.getClassName(clazz)).append("(");
for (Field field : fields) {
field.setAccessible(true);
Ignore ignore = field.getAnnotation(Ignore.class);
if (ignore != null && ignore.value()) {
continue;
} }
Field[] fields = Util.getFields(clazz); sb.append(field.getName());
if (fields != null && fields.length > 0) { Class<?> type = field.getType();
StringBuilder sb = new StringBuilder(); if (type == String.class) {
sb.append("create table ").append(Util.getClassName(clazz)).append("("); sb.append(" varchar");
for (Field field : fields) { } else if (type == int.class || type == Integer.class) {
field.setAccessible(true); sb.append(" interger");
Ignore ignore = field.getAnnotation(Ignore.class); } else if (type == float.class || type == Float.class) {
if (ignore != null && ignore.value()) { sb.append(" float");
continue; } else if (type == double.class || type == Double.class) {
} sb.append(" double");
sb.append(field.getName()); } else if (type == long.class || type == Long.class) {
Class<?> type = field.getType(); sb.append(" bigint");
if (type == String.class) { } else if (type == boolean.class || type == Boolean.class) {
sb.append(" varchar"); sb.append(" boolean");
} else if (type == int.class || type == Integer.class) { } else if (type == java.util.Date.class || type == java.sql.Date.class) {
sb.append(" interger"); sb.append(" data");
} else if (type == float.class || type == Float.class) { } else {
sb.append(" float"); sb.append(" blob");
} 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(",");
}
String str = sb.toString();
str = str.substring(0, str.length() - 1) + ");";
print(CREATE_TABLE, str);
mDb.execSQL(str);
} }
close(); sb.append(",");
}
String str = sb.toString();
str = str.substring(0, str.length() - 1) + ");";
print(CREATE_TABLE, str);
mDb.execSQL(str);
} }
close();
}
/** /**
* 打印数据库日志 * 打印数据库日志
* *
* @param type {@link DbUtil} * @param type {@link DbUtil}
*/ */
private void print(int type, String sql) { private void print(int type, String sql) {
String str = ""; String str = "";
switch (type) { switch (type) {
case 0: case 0:
str = "创建表 >>>> "; str = "创建表 >>>> ";
break; break;
case 1: case 1:
str = "表是否存在 >>>> "; str = "表是否存在 >>>> ";
break; break;
case 2: case 2:
str = "插入数据 >>>> "; str = "插入数据 >>>> ";
break; break;
case 3: case 3:
str = "修改数据 >>>> "; str = "修改数据 >>>> ";
break; break;
case 4: case 4:
str = "查询一行数据 >>>> "; str = "查询一行数据 >>>> ";
break; break;
case 5: case 5:
str = "遍历整个数据库 >>>> "; str = "遍历整个数据库 >>>> ";
break; break;
}
Log.v(TAG, str + sql);
} }
Log.v(TAG, str + sql);
}
/** /**
* 关闭数据库 * 关闭数据库
*/ */
private synchronized void close() { private synchronized void close() {
if (mDb != null) { if (mDb != null) {
mDb.close(); mDb.close();
}
} }
}
/** /**
* 获取所在行Id * 获取所在行Id
*/ */
synchronized int[] getRowId(Class clazz) { synchronized int[] getRowId(Class clazz) {
mDb = mHelper.getReadableDatabase(); mDb = mHelper.getReadableDatabase();
Cursor cursor = mDb.rawQuery("SELECT rowid, * FROM " + Util.getClassName(clazz), null); Cursor cursor = mDb.rawQuery("SELECT rowid, * FROM " + Util.getClassName(clazz), null);
int[] ids = new int[cursor.getCount()]; int[] ids = new int[cursor.getCount()];
int i = 0; int i = 0;
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid")); ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
i++; i++;
}
cursor.close();
close();
return ids;
} }
cursor.close();
close();
return ids;
}
/** /**
* 获取行Id * 获取行Id
*/ */
synchronized int getRowId(Class clazz, Object[] wheres, Object[] values) { synchronized int getRowId(Class clazz, Object[] wheres, Object[] values) {
mDb = mHelper.getReadableDatabase(); mDb = mHelper.getReadableDatabase();
if (wheres.length <= 0 || values.length <= 0) { if (wheres.length <= 0 || values.length <= 0) {
Log.e(TAG, "请输入删除条件"); Log.e(TAG, "请输入删除条件");
return -1; return -1;
} else if (wheres.length != values.length) { } else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等"); Log.e(TAG, "key 和 vaule 长度不相等");
return -1; return -1;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("SELECT rowid FROM ").append(Util.getClassName(clazz)).append(" WHERE "); sb.append("SELECT rowid FROM ").append(Util.getClassName(clazz)).append(" WHERE ");
int i = 0; int i = 0;
for (Object where : wheres) { for (Object where : wheres) {
sb.append(where).append("=").append("'").append(values[i]).append("'"); sb.append(where).append("=").append("'").append(values[i]).append("'");
sb.append(i >= wheres.length - 1 ? "" : ","); sb.append(i >= wheres.length - 1 ? "" : ",");
i++; i++;
}
print(ROW_ID, sb.toString());
Cursor c = mDb.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
close();
return id;
} }
print(ROW_ID, sb.toString());
Cursor c = mDb.rawQuery(sb.toString(), null);
int id = c.getColumnIndex("rowid");
c.close();
close();
return id;
}
/** /**
* 根据数据游标创建一个具体的对象 * 根据数据游标创建一个具体的对象
*/ */
private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) { private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz,
Field[] fields = Util.getFields(clazz); Cursor cursor) {
List<T> entitys = new ArrayList<>(); Field[] fields = Util.getFields(clazz);
if (fields != null && fields.length > 0) { List<T> entitys = new ArrayList<>();
try { if (fields != null && fields.length > 0) {
while (cursor.moveToNext()) { try {
T entity = clazz.newInstance(); while (cursor.moveToNext()) {
for (Field field : fields) { T entity = clazz.newInstance();
field.setAccessible(true); for (Field field : fields) {
Ignore ignore = field.getAnnotation(Ignore.class); field.setAccessible(true);
if (ignore != null && ignore.value()) { Ignore ignore = field.getAnnotation(Ignore.class);
continue; if (ignore != null && ignore.value()) {
} continue;
Class<?> type = field.getType(); }
int column = cursor.getColumnIndex(field.getName()); Class<?> type = field.getType();
if (type == String.class) { int column = cursor.getColumnIndex(field.getName());
field.set(entity, cursor.getString(column)); if (type == String.class) {
} else if (type == int.class || type == Integer.class) { field.set(entity, cursor.getString(column));
field.setInt(entity, cursor.getInt(column)); } else if (type == int.class || type == Integer.class) {
} else if (type == float.class || type == Float.class) { field.setInt(entity, cursor.getInt(column));
field.setFloat(entity, cursor.getFloat(column)); } else if (type == float.class || type == Float.class) {
} else if (type == double.class || type == Double.class) { field.setFloat(entity, cursor.getFloat(column));
field.setDouble(entity, cursor.getDouble(column)); } else if (type == double.class || type == Double.class) {
} else if (type == long.class || type == Long.class) { field.setDouble(entity, cursor.getDouble(column));
field.setLong(entity, cursor.getLong(column)); } else if (type == long.class || type == Long.class) {
} else if (type == boolean.class || type == Boolean.class) { field.setLong(entity, cursor.getLong(column));
field.setBoolean(entity, } else if (type == boolean.class || type == Boolean.class) {
!cursor.getString(column).equalsIgnoreCase("false")); field.setBoolean(entity, !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));
}
}
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
entitys.add(entity);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} }
}
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
entitys.add(entity);
} }
cursor.close(); } catch (InstantiationException e) {
close(); e.printStackTrace();
return entitys; } catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
cursor.close();
close();
return entitys;
}
} }

@ -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 true; boolean value() default true;
} }

@ -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 {
if (TextUtils.isEmpty(DB_NAME)) {
DB_NAME = "AriaLyyDb";
}
if (VERSION == -1) {
VERSION = 1;
}
}
public SqlHelper(Context context) { static {
super(context, DB_NAME, null, VERSION); if (TextUtils.isEmpty(DB_NAME)) {
DB_NAME = "AriaLyyDb";
}
if (VERSION == -1) {
VERSION = 1;
} }
}
@Override public void onCreate(SQLiteDatabase db) { public SqlHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
} @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,9 +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 com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -21,471 +19,494 @@ import java.util.Properties;
* 下载工具类 * 下载工具类
*/ */
final class DownLoadUtil { final class DownLoadUtil {
private static final String TAG = "DownLoadUtil"; private static final String TAG = "DownLoadUtil";
//下载监听 private static final Object LOCK = new Object();
private IDownloadListener mListener; //下载监听
/** private IDownloadListener mListener;
* 线程数 /**
*/ * 线程数
private static final int THREAD_NUM = 3; */
private static final int TIME_OUT = 5000; //超时时间 private static final int THREAD_NUM = 3;
/** private static final int TIME_OUT = 5000; //超时时间
* 已经完成下载任务的线程数量 /**
*/ * 已经完成下载任务的线程数量
private int mCompleteThreadNum = 0; */
private boolean isDownloading = false; private int mCompleteThreadNum = 0;
private boolean isStop = false; private boolean isDownloading = false;
private boolean isCancel = false; private boolean isStop = false;
private long mCurrentLocation; private boolean isCancel = false;
boolean isNewTask = true; private long mCurrentLocation;
private int mCancelNum = 0; boolean isNewTask = true;
private int mStopNum = 0; private int mCancelNum = 0;
private Context mContext; private int mStopNum = 0;
private DownloadEntity mDownloadEntity; private Context mContext;
private DownloadEntity mDownloadEntity;
public DownLoadUtil(Context context, DownloadEntity entity) { public DownLoadUtil(Context context, DownloadEntity entity) {
mContext = context.getApplicationContext(); mContext = context.getApplicationContext();
mDownloadEntity = entity; mDownloadEntity = entity;
}
public IDownloadListener getListener() {
return mListener;
}
/**
* 获取当前下载位置
*/
public long getCurrentLocation() {
return mCurrentLocation;
}
public boolean isDownloading() {
return isDownloading;
}
/**
* 取消下载
*/
public void cancelDownload() {
isCancel = true;
}
/**
* 停止下载
*/
public void stopDownload() {
isStop = true;
}
/**
* 删除下载记录文件
*/
public void delConfigFile() {
if (mContext != null && mDownloadEntity != null) {
File dFile = new File(mDownloadEntity.getDownloadPath());
File config =
new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
if (config.exists()) {
config.delete();
}
} }
}
public IDownloadListener getListener() {
return mListener; /**
} * 删除temp文件
*/
/** public void delTempFile() {
* 获取当前下载位置 if (mContext != null && mDownloadEntity != null) {
*/ File dFile = new File(mDownloadEntity.getDownloadPath());
public long getCurrentLocation() { if (dFile.exists()) {
return mCurrentLocation; dFile.delete();
}
} }
}
public boolean isDownloading() {
return isDownloading; /**
* 多线程断点续传下载文件暂停和继续
*
* @param downloadListener 下载进度监听 {@link DownloadListener}
*/
public void start(@NonNull final IDownloadListener downloadListener) {
isDownloading = true;
mCurrentLocation = 0;
isStop = false;
isCancel = false;
mCancelNum = 0;
mStopNum = 0;
final String filePath = mDownloadEntity.getDownloadPath();
final String downloadUrl = mDownloadEntity.getDownloadUrl();
final File dFile = new File(filePath);
//读取已完成的线程数
final File configFile =
new File(mContext.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() {
* 取消下载 try {
*/ mListener = downloadListener;
public void cancelDownload() { URL url = new URL(downloadUrl);
isCancel = true; 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;
}
}
}
SparseArray<Thread> tasks = new SparseArray<>();
int blockSize = fileLength / THREAD_NUM;
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;
}
ConfigEntity entity =
new ConfigEntity(mContext, 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();
}
private void failDownload(String msg) {
Log.e(TAG, msg);
isDownloading = false;
stopDownload();
mListener.onFail();
}
/**
* 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了
*/
private class DownLoadTask implements Runnable {
private static final String TAG = "DownLoadTask";
private ConfigEntity dEntity;
private String configFPath;
private DownLoadTask(ConfigEntity downloadInfo) {
this.dEntity = downloadInfo;
configFPath = dEntity.context.getFilesDir().getPath()
+ "/temp/"
+ dEntity.tempFile.getName()
+ ".properties";
} }
/** @Override public void run() {
* 停止下载 long currentLocation = 0;
*/ try {
public void stopDownload() { Log.d(TAG, "线程_"
isStop = true; + 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.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.setConnectTimeout(TIME_OUT * 4);
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);
progress(len);
currentLocation += len;
}
file.close();
is.close();
/** if (isCancel) {
* 删除下载记录文件 cancel();
*/ return;
public void delConfigFile() { }
if (mContext != null && mDownloadEntity != null) { //停止状态不需要删除记录文件
File dFile = new File(mDownloadEntity.getDownloadPath()); if (isStop) {
File config = new File( stop(currentLocation);
mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties"); return;
if (config.exists()) {
config.delete();
}
} }
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();
}
} catch (MalformedURLException e) {
failDownload(dEntity, currentLocation, "下载链接异常", e);
} catch (IOException e) {
failDownload(dEntity, currentLocation, "下载失败【" + dEntity.downloadUrl + "】", e);
} catch (Exception e) {
failDownload(dEntity, currentLocation, "获取流失败", e);
}
} }
/** /**
* 删除temp文件 * 停止下载
*
* @throws IOException
*/ */
public void delTempFile() { private void stop(long currentLocation) throws IOException {
if (mContext != null && mDownloadEntity != null) { synchronized (LOCK) {
File dFile = new File(mDownloadEntity.getDownloadPath()); mStopNum++;
if (dFile.exists()) { String location = String.valueOf(currentLocation);
dFile.delete(); 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);
} }
}
} }
/** /**
* 多线程断点续传下载文件暂停和继续 * 取消下载
*
* @param downloadListener 下载进度监听 {@link DownloadListener}
*/ */
public void start(@NonNull final IDownloadListener downloadListener) { private void cancel() {
isDownloading = true; synchronized (LOCK) {
mCurrentLocation = 0; mCancelNum++;
isStop = false; if (mCancelNum == THREAD_NUM) {
isCancel = false; File configFile = new File(configFPath);
mCancelNum = 0; if (configFile.exists()) {
mStopNum = 0; configFile.delete();
final String filePath = mDownloadEntity.getDownloadPath(); }
final String downloadUrl = mDownloadEntity.getDownloadUrl(); if (dEntity.tempFile.exists()) {
final File dFile = new File(filePath); dEntity.tempFile.delete();
//读取已完成的线程数 }
final File configFile = new File( Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties"); isDownloading = false;
try { mListener.onCancel();
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() {
try {
mListener = downloadListener;
URL url = new URL(downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Charset", "UTF-8");
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.setConnectTimeout(TIME_OUT * 4);
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;
}
}
}
SparseArray<Thread> tasks = new SparseArray<>();
int blockSize = fileLength / THREAD_NUM;
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;
}
ConfigEntity entity = new ConfigEntity(mContext, 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();
} }
private void failDownload(String msg) { private void progress(long len) {
Log.e(TAG, msg); synchronized (LOCK) {
isDownloading = false; mCurrentLocation += len;
stopDownload(); mListener.onProgress(mCurrentLocation);
mListener.onFail(); }
} }
/** /**
* 多线程下载任务类,不能使用AsyncTask来进行多线程下载因为AsyncTask是串行执行的这种方式下载速度太慢了 * 将记录写入到配置文件
*/ */
private class DownLoadTask implements Runnable { private void writeConfig(String key, String record) throws IOException {
private static final String TAG = "DownLoadTask"; File configFile = new File(configFPath);
private ConfigEntity dEntity; Properties pro = Util.loadConfig(configFile);
private String configFPath; pro.setProperty(key, record);
Util.saveConfig(configFile, pro);
public DownLoadTask(ConfigEntity downloadInfo) {
this.dEntity = downloadInfo;
configFPath = dEntity.context.getFilesDir()
.getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties";
}
@Override public void run() {
long currentLocation = 0;
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.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.setConnectTimeout(TIME_OUT * 4);
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();
}
}
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);
}
}
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();
}
} 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();
}
}
}
}
/**
* 将记录写入到配置文件
*/
private void writeConfig(String key, String record) throws IOException {
File configFile = new File(configFPath);
Properties pro = Util.loadConfig(configFile);
pro.setProperty(key, record);
Util.saveConfig(configFile, pro);
}
} }
/** /**
* 子线程下载信息类 * 下载失败
*/ */
private class ConfigEntity { private void failDownload(ConfigEntity dEntity, long currentLocation, String msg,
//文件大小 Exception ex) {
long fileSize; synchronized (LOCK) {
String downloadUrl; try {
int threadId; isDownloading = false;
long startLocation; isStop = true;
long endLocation; Log.e(TAG, msg);
File tempFile; if (ex != null) {
Context context; Log.e(TAG, Util.getPrintException(ex));
}
public ConfigEntity(Context context, long fileSize, String downloadUrl, File file, if (currentLocation != -1) {
int threadId, long startLocation, long endLocation) { String location = String.valueOf(currentLocation);
this.fileSize = fileSize; writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
this.downloadUrl = downloadUrl; }
this.tempFile = file; mListener.onFail();
this.threadId = threadId; } catch (IOException e) {
this.startLocation = startLocation; e.printStackTrace();
this.endLocation = endLocation;
this.context = context;
} }
}
}
}
/**
* 子线程下载信息类
*/
private class ConfigEntity {
//文件大小
long fileSize;
String downloadUrl;
int threadId;
long startLocation;
long endLocation;
File tempFile;
Context context;
public ConfigEntity(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,17 +1,13 @@
package com.arialyy.downloadutil.util; package com.arialyy.downloadutil.util;
import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import com.arialyy.downloadutil.core.DownloadManager; import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.IDownloadTarget; import com.arialyy.downloadutil.core.IDownloadTarget;
import com.arialyy.downloadutil.entity.DownloadEntity; import com.arialyy.downloadutil.entity.DownloadEntity;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
/** /**
@ -19,245 +15,241 @@ import java.net.HttpURLConnection;
* 下载任务类 * 下载任务类
*/ */
public class Task { public class Task {
public static final String TAG = "Task"; public static final String TAG = "Task";
private DownloadEntity mEntity; private DownloadEntity mEntity;
private IDownloadListener mListener; private IDownloadListener mListener;
private Handler mOutHandler; private Handler mOutHandler;
private Context mContext; private Context mContext;
private DownLoadUtil mUtil; private DownLoadUtil mUtil;
private Task(Context context, DownloadEntity entity) { private Task(Context context, DownloadEntity entity) {
mContext = context.getApplicationContext(); mContext = context.getApplicationContext();
mEntity = entity; mEntity = entity;
mUtil = new DownLoadUtil(context, entity); mUtil = new DownLoadUtil(context, entity);
}
/**
* 开始下载
*/
public void start() {
if (mUtil.isDownloading()) {
Log.d(TAG, "任务正在下载");
} else {
if (mListener == null) {
mListener = new DownloadListener(mContext, mEntity, mOutHandler);
}
mUtil.start(mListener);
} }
}
/**
* 开始下载 public DownloadEntity getDownloadEntity() {
*/ return mEntity;
public void start() { }
if (mUtil.isDownloading()) {
Log.d(TAG, "任务正在下载"); /**
} else { * 停止下载
if (mListener == null) { */
mListener = new DownloadListener(mContext, mEntity, mOutHandler); public void stop() {
} if (mUtil.isDownloading()) {
mUtil.start(mListener); mUtil.stopDownload();
} } else {
mEntity.setState(DownloadEntity.STATE_STOP);
mEntity.save();
sendInState2Target(IDownloadTarget.STOP);
// 发送停止下载的广播
Intent intent = createIntent(DownloadManager.ACTION_STOP);
intent.putExtra(DownloadManager.CURRENT_LOCATION, mEntity.getCurrentProgress());
intent.putExtra(DownloadManager.ENTITY, mEntity);
mContext.sendBroadcast(intent);
} }
}
public DownloadEntity getDownloadEntity() {
return mEntity; /**
* 获取下载工具
*/
public DownLoadUtil getDownloadUtil() {
return mUtil;
}
/**
* 任务下载状态
*/
public boolean isDownloading() {
return mUtil.isDownloading();
}
/**
* 取消下载
*/
public void cancel() {
if (mUtil.isDownloading()) {
mUtil.cancelDownload();
} else {
// 如果任务不是下载状态
mUtil.cancelDownload();
mUtil.delConfigFile();
mUtil.delTempFile();
mEntity.deleteData();
sendInState2Target(IDownloadTarget.CANCEL);
//发送取消下载的广播
Intent intent = createIntent(DownloadManager.ACTION_CANCEL);
intent.putExtra(DownloadManager.ENTITY, mEntity);
mContext.sendBroadcast(intent);
} }
}
/**
* 停止下载 /**
*/ * 创建特定的Intent
public void stop() { */
if (mUtil.isDownloading()) { private Intent createIntent(String action) {
mUtil.stopDownload(); Uri.Builder builder = new Uri.Builder();
} else { builder.scheme(mContext.getPackageName());
mEntity.setState(DownloadEntity.STATE_STOP); Uri uri = builder.build();
mEntity.save(); Intent intent = new Intent(action);
sendInState2Target(IDownloadTarget.STOP); intent.setData(uri);
return intent;
// 发送停止下载的广播 }
Intent intent = createIntent(DownloadManager.ACTION_STOP);
intent.putExtra(DownloadManager.CURRENT_LOCATION, mEntity.getCurrentProgress()); /**
intent.putExtra(DownloadManager.ENTITY, mEntity); * 将任务状态发送给下载器
mContext.sendBroadcast(intent); *
} * @param state {@link IDownloadTarget#START}
*/
private void sendInState2Target(int state) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(state, mEntity).sendToTarget();
} }
}
/**
* 获取下载工具 /**
*/ * 下载监听类
public DownLoadUtil getDownloadUtil() { */
return mUtil; private class DownloadListener extends DownLoadUtil.DownloadListener {
Handler outHandler;
Context context;
Intent sendIntent;
long INTERVAL = 1024 * 10; //10k大小的间隔
long lastLen = 0; //上一次发送长度
long lastTime = 0;
long INTERVAL_TIME = 60 * 1000; //10k大小的间隔
DownloadEntity downloadEntity;
DownloadListener(Context context, DownloadEntity downloadEntity, Handler outHandler) {
this.context = context;
this.outHandler = outHandler;
this.downloadEntity = downloadEntity;
sendIntent = createIntent(DownloadManager.ACTION_RUNNING);
sendIntent.putExtra(DownloadManager.ENTITY, downloadEntity);
} }
/** @Override public void onPreDownload(HttpURLConnection connection) {
* 任务下载状态 super.onPreDownload(connection);
*/ long len = connection.getContentLength();
public boolean isDownloading() { downloadEntity.setFileSize(len);
return mUtil.isDownloading(); 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);
public void cancel() { sendIntent(DownloadManager.ACTION_RESUME, resumeLocation);
if (mUtil.isDownloading()) {
mUtil.cancelDownload();
} else {
// 如果任务不是下载状态
mUtil.cancelDownload();
mUtil.delConfigFile();
mUtil.delTempFile();
mEntity.deleteData();
sendInState2Target(IDownloadTarget.CANCEL);
//发送取消下载的广播
Intent intent = createIntent(DownloadManager.ACTION_CANCEL);
intent.putExtra(DownloadManager.ENTITY, mEntity);
mContext.sendBroadcast(intent);
}
} }
/** @Override public void onStart(long startLocation) {
* 创建特定的Intent super.onStart(startLocation);
* downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
* @param action sendInState2Target(IDownloadTarget.START);
* @return sendIntent(DownloadManager.ACTION_START, startLocation);
*/
private Intent createIntent(String action) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(mContext.getPackageName());
Uri uri = builder.build();
Intent intent = new Intent(action);
intent.setData(uri);
return intent;
} }
/** @Override public void onProgress(long currentLocation) {
* 将任务状态发送给下载器 super.onProgress(currentLocation);
* // if (currentLocation - lastLen > INTERVAL) { //不要太过于频繁发送广播
* @param state {@link IDownloadTarget#START} // sendIntent.putExtra(DownloadManager.CURRENT_LOCATION, currentLocation);
*/ // lastLen = currentLocation;
private void sendInState2Target(int state) { // context.sendBroadcast(sendIntent);
if (mOutHandler != null) { // }
mOutHandler.obtainMessage(state, mEntity).sendToTarget(); if (System.currentTimeMillis() - lastLen > INTERVAL_TIME) {
} sendIntent.putExtra(DownloadManager.CURRENT_LOCATION, currentLocation);
lastTime = System.currentTimeMillis();
context.sendBroadcast(sendIntent);
}
} }
/** @Override public void onStop(long stopLocation) {
* 下载监听类 super.onStop(stopLocation);
*/ downloadEntity.setState(DownloadEntity.STATE_STOP);
private class DownloadListener extends DownLoadUtil.DownloadListener { sendInState2Target(IDownloadTarget.STOP);
Handler outHandler; sendIntent(DownloadManager.ACTION_STOP, stopLocation);
Context context; }
Intent sendIntent;
long INTERVAL = 1024 * 10; //10k大小的间隔
long lastLen = 0; //上一次发送长度
long lastTime = 0;
long INTERVAL_TIME = 60 * 1000; //10k大小的间隔
DownloadEntity downloadEntity;
DownloadListener(Context context, DownloadEntity downloadEntity,
Handler outHandler) {
this.context = context;
this.outHandler = outHandler;
this.downloadEntity = downloadEntity;
sendIntent = createIntent(DownloadManager.ACTION_RUNNING);
sendIntent.putExtra(DownloadManager.ENTITY, downloadEntity);
}
@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.CURRENT_LOCATION, currentLocation);
// lastLen = currentLocation;
// context.sendBroadcast(sendIntent);
// }
if (System.currentTimeMillis() - lastLen > INTERVAL_TIME){
sendIntent.putExtra(DownloadManager.CURRENT_LOCATION, currentLocation);
lastTime = System.currentTimeMillis();
context.sendBroadcast(sendIntent);
}
}
@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() { @Override public void onCancel() {
super.onCancel(); super.onCancel();
downloadEntity.setState(DownloadEntity.STATE_CANCEL); downloadEntity.setState(DownloadEntity.STATE_CANCEL);
sendInState2Target(IDownloadTarget.CANCEL); sendInState2Target(IDownloadTarget.CANCEL);
sendIntent(DownloadManager.ACTION_CANCEL, -1); sendIntent(DownloadManager.ACTION_CANCEL, -1);
downloadEntity.deleteData(); downloadEntity.deleteData();
} }
@Override public void onComplete() { @Override public void onComplete() {
super.onComplete(); super.onComplete();
downloadEntity.setState(DownloadEntity.STATE_COMPLETE); downloadEntity.setState(DownloadEntity.STATE_COMPLETE);
downloadEntity.setDownloadComplete(true); downloadEntity.setDownloadComplete(true);
sendInState2Target(IDownloadTarget.COMPLETE); sendInState2Target(IDownloadTarget.COMPLETE);
sendIntent(DownloadManager.ACTION_COMPLETE, -1); sendIntent(DownloadManager.ACTION_COMPLETE, -1);
} }
@Override public void onFail() { @Override public void onFail() {
super.onFail(); super.onFail();
downloadEntity.setState(DownloadEntity.STATE_FAIL); downloadEntity.setState(DownloadEntity.STATE_FAIL);
sendInState2Target(IDownloadTarget.FAIL); sendInState2Target(IDownloadTarget.FAIL);
sendIntent(DownloadManager.ACTION_FAIL, -1); sendIntent(DownloadManager.ACTION_FAIL, -1);
} }
private void sendIntent(String action, long location) { private void sendIntent(String action, long location) {
downloadEntity.setDownloadComplete(action.equals(DownloadManager.ACTION_COMPLETE)); downloadEntity.setDownloadComplete(action.equals(DownloadManager.ACTION_COMPLETE));
downloadEntity.setCurrentProgress(location); downloadEntity.setCurrentProgress(location);
downloadEntity.update(); downloadEntity.update();
Intent intent = createIntent(action); Intent intent = createIntent(action);
intent.putExtra(DownloadManager.ENTITY, downloadEntity); intent.putExtra(DownloadManager.ENTITY, downloadEntity);
if (location != -1) { if (location != -1) {
intent.putExtra(DownloadManager.CURRENT_LOCATION, location); intent.putExtra(DownloadManager.CURRENT_LOCATION, location);
} }
context.sendBroadcast(intent); context.sendBroadcast(intent);
}
} }
}
public static class Builder { public static class Builder {
DownloadEntity downloadEntity; DownloadEntity downloadEntity;
IDownloadListener listener; IDownloadListener listener;
Handler outHandler; Handler outHandler;
Context context; Context context;
public Builder(Context context, DownloadEntity downloadEntity) { public Builder(Context context, DownloadEntity downloadEntity) {
this.context = context; this.context = context;
this.downloadEntity = downloadEntity; this.downloadEntity = downloadEntity;
} }
public Builder setDownloadListener(IDownloadListener listener) { public Builder setDownloadListener(IDownloadListener listener) {
this.listener = listener; this.listener = listener;
return this; return this;
} }
public Builder setOutHandler(Handler outHandler) { public Builder setOutHandler(Handler outHandler) {
this.outHandler = outHandler; this.outHandler = outHandler;
return this; return this;
} }
public Task build() { public Task build() {
Task task = new Task(context, downloadEntity); Task task = new Task(context, downloadEntity);
task.mListener = listener; task.mListener = listener;
task.mOutHandler = outHandler; task.mOutHandler = outHandler;
downloadEntity.save(); downloadEntity.save();
return task; return task;
}
} }
}
} }

@ -1,7 +1,6 @@
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;
@ -16,264 +15,261 @@ 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";
/** /**
* 获取类里面的所在字段 * 获取类里面的所在字段
*/ */
public static Field[] getFields(Class clazz) { public static Field[] getFields(Class clazz) {
Field[] fields = null; Field[] fields = null;
fields = clazz.getDeclaredFields(); fields = clazz.getDeclaredFields();
if (fields == null || fields.length == 0) { if (fields == null || fields.length == 0) {
Class superClazz = clazz.getSuperclass(); Class superClazz = clazz.getSuperclass();
if (superClazz != null) { if (superClazz != null) {
fields = getFields(superClazz); fields = getFields(superClazz);
} }
}
return fields;
} }
return fields;
}
/** /**
* 获取类里面的指定对象如果该类没有则从父类查询 * 获取类里面的指定对象如果该类没有则从父类查询
*/ */
public static Field getField(Class clazz, String name) { public static Field getField(Class clazz, String name) {
Field field = null; Field field = null;
try { try {
field = clazz.getDeclaredField(name); field = clazz.getDeclaredField(name);
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
try { try {
field = clazz.getField(name); field = clazz.getField(name);
} catch (NoSuchFieldException e1) { } catch (NoSuchFieldException e1) {
if (clazz.getSuperclass() == null) { if (clazz.getSuperclass() == null) {
return field; return field;
} else { } else {
field = getField(clazz.getSuperclass(), name); field = getField(clazz.getSuperclass(), name);
}
}
}
if (field != null) {
field.setAccessible(true);
} }
return field; }
} }
if (field != null) {
/** field.setAccessible(true);
* 字符串转hashcode
*
* @param str
* @return
*/
public static int keyToHashCode(String str) {
int total = 0;
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
if (ch == '\'') ch = (char) 29; // nor this
total = (total * 33) + (ch & 0x1F);
}
return total;
} }
return field;
}
/** /**
* 将key转换为16进制码 * 字符串转hashcode
* */
* @param key 缓存的key public static int keyToHashCode(String str) {
* @return 转换后的key的值, 系统便是通过该key来读写缓存 int total = 0;
*/ for (int i = 0; i < str.length(); i++) {
public static String keyToHashKey(String key) { char ch = str.charAt(i);
String cacheKey; if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
try { if (ch == '\'') ch = (char) 29; // nor this
final MessageDigest mDigest = MessageDigest.getInstance("MD5"); total = (total * 33) + (ch & 0x1F);
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
} }
return total;
}
/** /**
* 将普通字符串转换为16位进制字符串 * 将key转换为16进制码
*/ *
public static String bytesToHexString(byte[] src) { * @param key 缓存的key
StringBuilder stringBuilder = new StringBuilder("0x"); * @return 转换后的key的值, 系统便是通过该key来读写缓存
if (src == null || src.length <= 0) { */
return null; public static String keyToHashKey(String key) {
} String cacheKey;
char[] buffer = new char[2]; try {
for (byte aSrc : src) { final MessageDigest mDigest = MessageDigest.getInstance("MD5");
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16); mDigest.update(key.getBytes());
buffer[1] = Character.forDigit(aSrc & 0x0F, 16); cacheKey = bytesToHexString(mDigest.digest());
stringBuilder.append(buffer); } catch (NoSuchAlgorithmException e) {
} cacheKey = String.valueOf(key.hashCode());
return stringBuilder.toString();
} }
return cacheKey;
}
/** /**
* 获取对象名 * 将普通字符串转换为16位进制字符串
* */
* @param obj 对象 public static String bytesToHexString(byte[] src) {
* @return 对象名 StringBuilder stringBuilder = new StringBuilder("0x");
*/ if (src == null || src.length <= 0) {
public static String getClassName(Object obj) { return null;
String arrays[] = obj.getClass().getName().split("\\.");
return arrays[arrays.length - 1];
} }
char[] buffer = new char[2];
/** for (byte aSrc : src) {
* 获取对象名 buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
* buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
* @param clazz clazz stringBuilder.append(buffer);
* @return 对象名
*/
public static String getClassName(Class clazz) {
String arrays[] = clazz.getName().split("\\.");
return arrays[arrays.length - 1];
} }
return stringBuilder.toString();
}
/** /**
* 格式化文件大小 * 获取对象名
* *
* @param size file.length() 获取文件大小 * @param obj 对象
*/ * @return 对象名
public static String formatFileSize(double size) { */
double kiloByte = size / 1024; public static String getClassName(Object obj) {
if (kiloByte < 1) { String arrays[] = obj.getClass().getName().split("\\.");
return size + "Byte(s)"; return arrays[arrays.length - 1];
} }
double megaByte = kiloByte / 1024; /**
if (megaByte < 1) { * 获取对象名
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); *
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; * @param clazz clazz
} * @return 对象名
*/
public static String getClassName(Class clazz) {
String arrays[] = clazz.getName().split("\\.");
return arrays[arrays.length - 1];
}
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 size file.length() 获取文件大小
} */
public static String formatFileSize(double size) {
double kiloByte = size / 1024;
if (kiloByte < 1) {
return size + "Byte(s)";
}
double teraBytes = gigaByte / 1024; double megaByte = kiloByte / 1024;
if (teraBytes < 1) { if (megaByte < 1) {
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
}
BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
} }
/** double gigaByte = megaByte / 1024;
* 创建目录 当目录不存在的时候创建文件否则返回false if (gigaByte < 1) {
*/ BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
public static boolean createDir(String path) { return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
File file = new File(path); }
if (!file.exists()) {
if (!file.mkdirs()) { double teraBytes = gigaByte / 1024;
Log.d(TAG, "创建失败,请检查路径和是否配置文件权限!"); if (teraBytes < 1) {
return false; BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
} return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
return true; }
} BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
}
/**
* 创建目录 当目录不存在的时候创建文件否则返回false
*/
public static boolean createDir(String path) {
File file = new File(path);
if (!file.exists()) {
if (!file.mkdirs()) {
Log.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
return false; return false;
}
return true;
} }
return false;
}
/** /**
* 创建文件 当文件不存在的时候就创建一个文件否则直接返回文件 * 创建文件 当文件不存在的时候就创建一个文件否则直接返回文件
*/ */
public static File createFile(String path) { public static File createFile(String path) {
File file = new File(path); File file = new File(path);
if (!file.getParentFile().exists()) { if (!file.getParentFile().exists()) {
Log.d(TAG, "目标文件所在路径不存在,准备创建……"); Log.d(TAG, "目标文件所在路径不存在,准备创建……");
if (!createDir(file.getParent())) { if (!createDir(file.getParent())) {
Log.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】"); Log.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】");
} }
} }
// 创建目标文件 // 创建目标文件
try { try {
if (!file.exists()) { if (!file.exists()) {
if (file.createNewFile()) { if (file.createNewFile()) {
Log.d(TAG, "创建文件成功:" + file.getAbsolutePath()); Log.d(TAG, "创建文件成功:" + file.getAbsolutePath());
}
return file;
} else {
return file;
}
} catch (IOException e) {
e.printStackTrace();
} }
return null; return file;
} else {
return file;
}
} catch (IOException e) {
e.printStackTrace();
} }
return null;
}
/** /**
* 设置打印的异常格式 * 设置打印的异常格式
*/ */
public static String getPrintException(Throwable ex) { public static String getPrintException(Throwable ex) {
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n"); err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n"); err.append("====================Exception Info====================\n");
err.append(ex.toString()); err.append(ex.toString());
err.append("\n"); err.append("\n");
StackTraceElement[] stack = ex.getStackTrace(); StackTraceElement[] stack = ex.getStackTrace();
for (StackTraceElement stackTraceElement : stack) { for (StackTraceElement stackTraceElement : stack) {
err.append(stackTraceElement.toString()).append("\n"); err.append(stackTraceElement.toString()).append("\n");
} }
Throwable cause = ex.getCause(); Throwable cause = ex.getCause();
if (cause != null) { if (cause != null) {
err.append("【Caused by】: "); err.append("【Caused by】: ");
err.append(cause.toString()); err.append(cause.toString());
err.append("\n"); err.append("\n");
StackTraceElement[] stackTrace = cause.getStackTrace(); StackTraceElement[] stackTrace = cause.getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) { for (StackTraceElement stackTraceElement : stackTrace) {
err.append(stackTraceElement.toString()).append("\n"); err.append(stackTraceElement.toString()).append("\n");
} }
}
err.append("===================================================");
return err.toString();
} }
err.append("===================================================");
return err.toString();
}
/** /**
* 读取下载配置文件 * 读取下载配置文件
*/ */
public static Properties loadConfig(File file) { public static Properties loadConfig(File file) {
Properties properties = new Properties(); Properties properties = new Properties();
FileInputStream fis = null; FileInputStream fis = null;
try { try {
fis = new FileInputStream(file); fis = new FileInputStream(file);
properties.load(fis); properties.load(fis);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {
if (fis != null) { if (fis != null) {
fis.close(); fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
return properties; } catch (IOException e) {
e.printStackTrace();
}
} }
return properties;
}
/** /**
* 保存配置文件 * 保存配置文件
*/ */
public static void saveConfig(File file, Properties properties) { public static void saveConfig(File file, Properties properties) {
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
fos = new FileOutputStream(file, false); fos = new FileOutputStream(file, false);
properties.store(fos, null); properties.store(fos, null);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {
if (fos != null) { if (fos != null) {
fos.flush(); fos.flush();
fos.close(); 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>

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