下载工具死锁修复

This commit is contained in:
lyy
2016-10-13 22:10:32 +08:00
72 changed files with 3830 additions and 3541 deletions

229
.idea/codeStyleSettings.xml generated Normal file
View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<Objective-C-extensions>
<option name="GENERATE_INSTANCE_VARIABLES_FOR_PROPERTIES" value="ASK" />
<option name="RELEASE_STYLE" value="IVAR" />
<option name="TYPE_QUALIFIERS_PLACEMENT" value="BEFORE" />
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" />
<pair source="c" header="h" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Aria" />
</component>
</project>

3
.idea/dictionaries/AriaL.xml generated Normal file
View File

@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="AriaL" />
</component>

2
.idea/misc.xml generated
View File

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

View File

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

View File

@ -13,7 +13,7 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--android:name=".activity.SimpleTestActivity"-->
<!--android:name=".activity.SingleTaskActivity"-->
<activity
android:name=".activity.MainActivity"
android:label="@string/app_name"
@ -24,6 +24,9 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".activity.SingleTaskActivity"/>
<activity android:name=".activity.MultiTaskActivity"/>
</application>
</manifest>

View File

@ -1,29 +1,19 @@
package com.arialyy.simple.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.frame.util.show.L;
import android.support.v7.widget.Toolbar;
import android.view.View;
import butterknife.Bind;
import com.arialyy.simple.R;
import com.arialyy.simple.adapter.DownloadAdapter;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMainBinding;
import com.arialyy.simple.module.DownloadModule;
import butterknife.Bind;
/**
* Created by Lyy on 2016/9/27.
* Created by Lyy on 2016/10/13.
*/
public class MainActivity extends BaseActivity<ActivityMainBinding> {
@Bind(R.id.list) RecyclerView mList;
DownloadAdapter mAdapter;
@Bind(R.id.toolbar) Toolbar mBar;
@Override protected int setLayoutId() {
return R.layout.activity_main;
@ -31,60 +21,18 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> {
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
mAdapter = new DownloadAdapter(this, getModule(DownloadModule.class).getDownloadData());
mList.setLayoutManager(new LinearLayoutManager(this));
mList.setAdapter(mAdapter);
setSupportActionBar(mBar);
mBar.setTitle("多线程多任务下载");
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
long len = 0;
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
DownloadEntity entity = intent.getParcelableExtra(DownloadManager.ENTITY);
switch (action) {
case DownloadManager.ACTION_PRE:
len = entity.getFileSize();
L.d(TAG, "download pre");
public void onClick(View view) {
switch (view.getId()) {
case R.id.single_task:
startActivity(new Intent(this, SingleTaskActivity.class));
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");
case R.id.multi_task:
startActivity(new Intent(this, MultiTaskActivity.class));
break;
}
}
};
@Override protected void onResume() {
super.onResume();
registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter());
}
@Override protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
}

View File

@ -0,0 +1,91 @@
package com.arialyy.simple.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import butterknife.Bind;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R;
import com.arialyy.simple.adapter.DownloadAdapter;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivityMultiBinding;
import com.arialyy.simple.module.DownloadModule;
/**
* Created by Lyy on 2016/9/27.
*/
public class MultiTaskActivity extends BaseActivity<ActivityMultiBinding> {
@Bind(R.id.list) RecyclerView mList;
@Bind(R.id.toolbar) Toolbar mBar;
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);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
long len = 0;
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
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() {
super.onResume();
registerReceiver(mReceiver, getModule(DownloadModule.class).getDownloadFilter());
}
@Override protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
}

View File

@ -1,248 +0,0 @@
package com.arialyy.simple.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.command.CommandFactory;
import com.arialyy.downloadutil.core.command.IDownloadCommand;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.orm.DbEntity;
import com.arialyy.downloadutil.util.Util;
import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivitySimpleBinding;
import com.arialyy.simple.module.DownloadModule;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
public class SimpleTestActivity extends BaseActivity<ActivitySimpleBinding> {
private static final int DOWNLOAD_PRE = 0x01;
private static final int DOWNLOAD_STOP = 0x02;
private static final int DOWNLOAD_FAILE = 0x03;
private static final int DOWNLOAD_CANCEL = 0x04;
private static final int DOWNLOAD_RESUME = 0x05;
private static final int DOWNLOAD_COMPLETE = 0x06;
private ProgressBar mPb;
private String mDownloadUrl = "http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk";
private Button mStart, mStop, mCancel;
private TextView mSize;
@Bind(R.id.toolbar) Toolbar toolbar;
private CommandFactory mFactory;
private DownloadManager mManager;
private DownloadEntity mEntity;
private Handler mUpdateHandler = new Handler() {
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DOWNLOAD_PRE:
mSize.setText(Util.formatFileSize((Long) msg.obj));
setBtState(false);
break;
case DOWNLOAD_FAILE:
Toast.makeText(SimpleTestActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
setBtState(true);
break;
case DOWNLOAD_STOP:
Toast.makeText(SimpleTestActivity.this, "暂停下载", Toast.LENGTH_SHORT).show();
mStart.setText("恢复");
setBtState(true);
break;
case DOWNLOAD_CANCEL:
mPb.setProgress(0);
Toast.makeText(SimpleTestActivity.this, "取消下载", Toast.LENGTH_SHORT).show();
mStart.setText("开始");
setBtState(true);
break;
case DOWNLOAD_RESUME:
Toast.makeText(SimpleTestActivity.this,
"恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj),
Toast.LENGTH_SHORT).show();
setBtState(false);
break;
case DOWNLOAD_COMPLETE:
Toast.makeText(SimpleTestActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
mStart.setText("重新开始?");
mCancel.setEnabled(false);
setBtState(true);
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_simple;
}
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
setSupportActionBar(toolbar);
init();
}
private void init() {
mPb = (ProgressBar) findViewById(R.id.progressBar);
mStart = (Button) findViewById(R.id.start);
mStop = (Button) findViewById(R.id.stop);
mCancel = (Button) findViewById(R.id.cancel);
mSize = (TextView) findViewById(R.id.size);
mFactory = CommandFactory.getInstance();
mManager = DownloadManager.getInstance();
mEntity = DbEntity.findData(DownloadEntity.class, new String[]{"downloadUrl"},
new String[]{mDownloadUrl});
if (mEntity != null) {
mPb.setProgress((int) ((mEntity.getCurrentProgress() * 100) / mEntity.getFileSize()));
mSize.setText(Util.formatFileSize(mEntity.getFileSize()));
if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
setBtState(false);
} else if (mEntity.isDownloadComplete()) {
mStart.setText("重新开始?");
setBtState(true);
}
} else {
mEntity = new DownloadEntity();
}
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.start:
start();
// if (PermissionManager.getInstance()
// .checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// start();
// } else {
// PermissionManager.getInstance()
// .requestPermission(this, new OnPermissionCallback() {
// @Override public void onSuccess(String... permissions) {
// start();
// }
//
// @Override public void onFail(String... permissions) {
//
// }
// }, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// }
break;
case R.id.stop:
stop();
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();
}
}

View File

@ -0,0 +1,241 @@
package com.arialyy.simple.activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.Bind;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.command.CommandFactory;
import com.arialyy.downloadutil.core.command.IDownloadCommand;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.orm.DbEntity;
import com.arialyy.downloadutil.util.Util;
import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseActivity;
import com.arialyy.simple.databinding.ActivitySingleBinding;
import com.arialyy.simple.module.DownloadModule;
import java.util.ArrayList;
import java.util.List;
public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
private static final int DOWNLOAD_PRE = 0x01;
private static final int DOWNLOAD_STOP = 0x02;
private static final int DOWNLOAD_FAILE = 0x03;
private static final int DOWNLOAD_CANCEL = 0x04;
private static final int DOWNLOAD_RESUME = 0x05;
private static final int DOWNLOAD_COMPLETE = 0x06;
private ProgressBar mPb;
private String mDownloadUrl =
"http://static.gaoshouyou.com/d/12/0d/7f120f50c80d2e7b8c4ba24ece4f9cdd.apk";
private Button mStart, mStop, mCancel;
private TextView mSize;
@Bind(R.id.toolbar) Toolbar toolbar;
private CommandFactory mFactory;
private DownloadManager mManager;
private DownloadEntity mEntity;
private Handler mUpdateHandler = new Handler() {
@Override public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case DOWNLOAD_PRE:
mSize.setText(Util.formatFileSize((Long) msg.obj));
setBtState(false);
break;
case DOWNLOAD_FAILE:
Toast.makeText(SingleTaskActivity.this, "下载失败", Toast.LENGTH_SHORT).show();
setBtState(true);
break;
case DOWNLOAD_STOP:
Toast.makeText(SingleTaskActivity.this, "暂停下载", Toast.LENGTH_SHORT).show();
mStart.setText("恢复");
setBtState(true);
break;
case DOWNLOAD_CANCEL:
mPb.setProgress(0);
Toast.makeText(SingleTaskActivity.this, "取消下载", Toast.LENGTH_SHORT).show();
mStart.setText("开始");
setBtState(true);
break;
case DOWNLOAD_RESUME:
Toast.makeText(SingleTaskActivity.this,
"恢复下载,恢复位置 ==> " + Util.formatFileSize((Long) msg.obj), Toast.LENGTH_SHORT).show();
setBtState(false);
break;
case DOWNLOAD_COMPLETE:
Toast.makeText(SingleTaskActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
mStart.setText("重新开始?");
mCancel.setEnabled(false);
setBtState(true);
break;
}
}
};
/**
* 设置start 和 stop 按钮状态
*/
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;
}
@Override protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
setSupportActionBar(toolbar);
toolbar.setTitle("单任务下载");
init();
}
private void init() {
mPb = (ProgressBar) findViewById(R.id.progressBar);
mStart = (Button) findViewById(R.id.start);
mStop = (Button) findViewById(R.id.stop);
mCancel = (Button) findViewById(R.id.cancel);
mSize = (TextView) findViewById(R.id.size);
mFactory = CommandFactory.getInstance();
mManager = DownloadManager.getInstance();
mEntity = DbEntity.findData(DownloadEntity.class, new String[] { "downloadUrl" },
new String[] { mDownloadUrl });
if (mEntity != null) {
mPb.setProgress((int) ((mEntity.getCurrentProgress() * 100) / mEntity.getFileSize()));
mSize.setText(Util.formatFileSize(mEntity.getFileSize()));
if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
setBtState(false);
} else if (mEntity.isDownloadComplete()) {
mStart.setText("重新开始?");
setBtState(true);
}
} else {
mEntity = new DownloadEntity();
}
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.start:
start();
// if (PermissionManager.getInstance()
// .checkPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// start();
// } else {
// PermissionManager.getInstance()
// .requestPermission(this, new OnPermissionCallback() {
// @Override public void onSuccess(String... permissions) {
// start();
// }
//
// @Override public void onFail(String... permissions) {
//
// }
// }, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// }
break;
case R.id.stop:
stop();
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();
}
}

View File

@ -4,7 +4,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.view.View;
import android.widget.Button;
import butterknife.Bind;
import com.arialyy.absadapter.common.AbsHolder;
import com.arialyy.absadapter.recycler_view.AbsRVAdapter;
import com.arialyy.downloadutil.core.DownloadManager;
@ -14,15 +14,12 @@ import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.frame.util.show.L;
import com.arialyy.simple.R;
import com.arialyy.simple.widget.HorizontalProgressBarWithNumber;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import butterknife.Bind;
/**
* Created by Lyy on 2016/9/27.
* 下载列表适配器
@ -145,24 +142,24 @@ public class DownloadAdapter extends AbsRVAdapter<DownloadEntity, DownloadAdapte
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);
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);
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);
IDownloadCommand cancelCommand =
mFactory.createCommand(getContext(), entity, CommandFactory.TASK_CANCEL);
mManager.setCommand(cancelCommand).exe();
}
}

View File

@ -2,7 +2,6 @@ package com.arialyy.simple.base;
import android.databinding.ViewDataBinding;
import android.os.Bundle;
import com.arialyy.frame.core.AbsActivity;
/**

View File

@ -1,7 +1,6 @@
package com.arialyy.simple.base;
import android.app.Application;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.frame.core.AbsFrame;

View File

@ -1,7 +1,6 @@
package com.arialyy.simple.base;
import android.content.Context;
import com.arialyy.frame.module.AbsModule;
/**

View File

@ -3,7 +3,6 @@ package com.arialyy.simple.module;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Environment;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Util;
@ -11,7 +10,6 @@ import com.arialyy.frame.util.AndroidUtils;
import com.arialyy.frame.util.StringUtil;
import com.arialyy.simple.R;
import com.arialyy.simple.base.BaseModule;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@ -26,21 +24,50 @@ public class DownloadModule extends BaseModule {
/**
* 设置下载数据
*
* @return
*/
public List<DownloadEntity> getDownloadData() {
List<DownloadEntity> list = DownloadEntity.findAllData(DownloadEntity.class);
List<DownloadEntity> newDownload = createNewDownload();
if (list == null) {
list = createNewDownload();
list = newDownload;
} else {
list = filter(list, newDownload);
}
return list;
}
/**
* 过滤任务
*
* @param sqlEntity 数据库的下载实体
* @param createdEntity 通过下载链接生成的下载实体
*/
private List<DownloadEntity> filter(List<DownloadEntity> sqlEntity,
List<DownloadEntity> createdEntity) {
List<DownloadEntity> list = new ArrayList<>();
list.addAll(sqlEntity);
for (DownloadEntity cEntity : createdEntity) {
int count = 0;
for (DownloadEntity sEntity : sqlEntity) {
if (cEntity.getDownloadUrl().equals(sEntity.getDownloadUrl())) {
break;
}
count++;
if (count == sqlEntity.size()) {
list.add(cEntity);
}
}
}
return list;
}
/**
* 创建下载列表
*/
private List<DownloadEntity> createNewDownload() {
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) {
String fileName = Util.keyToHashCode(url) + ".apk";
DownloadEntity entity = new DownloadEntity();
@ -54,8 +81,6 @@ public class DownloadModule extends BaseModule {
/**
* 下载广播过滤器
*
* @return
*/
public IntentFilter getDownloadFilter() {
IntentFilter filter = new IntentFilter();
@ -71,10 +96,13 @@ public class DownloadModule extends BaseModule {
return filter;
}
/**
* 设置下载队列
*/
private String getDownloadPath(String url) {
String path = Environment.getExternalStorageDirectory()
.getPath() + "/" + AndroidUtils.getAppName(getContext()) + "downloads/" + StringUtil
.keyToHashKey(url) + ".apk";
String path =
Environment.getExternalStorageDirectory().getPath() + "/" + AndroidUtils.getAppName(
getContext()) + "downloads/" + StringUtil.keyToHashKey(url) + ".apk";
File file = new File(path);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();

View File

@ -7,7 +7,6 @@ import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.ProgressBar;
import com.arialyy.simple.R;
public class HorizontalProgressBarWithNumber extends ProgressBar {
@ -32,13 +31,13 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
/**
* offset of draw progress
*/
protected int mTextOffset = dp2px(
DEFAULT_SIZE_TEXT_OFFSET);
protected int mTextOffset =
dp2px(DEFAULT_SIZE_TEXT_OFFSET);
/**
* height of reached progress bar
*/
protected int mReachedProgressBarHeight = dp2px(
DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
protected int mReachedProgressBarHeight =
dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);
/**
* color of reached bar
*/
@ -50,8 +49,8 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
/**
* height of unreached progress bar
*/
protected int mUnReachedProgressBarHeight = dp2px(
DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
protected int mUnReachedProgressBarHeight =
dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);
/**
* view width except padding
*/
@ -86,9 +85,7 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
} else {
float textHeight = (mPaint.descent() - mPaint.ascent());
result = (int) (getPaddingTop() + getPaddingBottom() + Math.max(
Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight),
Math.abs(textHeight))
);
Math.max(mReachedProgressBarHeight, mUnReachedProgressBarHeight), Math.abs(textHeight)));
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
@ -101,17 +98,18 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
*/
private void obtainStyledAttributes(AttributeSet attrs) {
// init values from custom attributes
final TypedArray attributes = getContext().obtainStyledAttributes(attrs,
R.styleable.HorizontalProgressBarWithNumber);
mTextColor = attributes.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
final TypedArray attributes =
getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressBarWithNumber);
mTextColor =
attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_text_color,
DEFAULT_TEXT_COLOR);
mTextSize = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_size, mTextSize);
mReachedBarColor = attributes.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_color, mTextColor);
mUnReachedBarColor = attributes.getColor(
R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
mReachedBarColor =
attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,
mTextColor);
mUnReachedBarColor =
attributes.getColor(R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,
DEFAULT_COLOR_UNREACHED_COLOR);
mReachedProgressBarHeight = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,
@ -121,8 +119,9 @@ public class HorizontalProgressBarWithNumber extends ProgressBar {
mUnReachedProgressBarHeight);
mTextOffset = (int) attributes.getDimension(
R.styleable.HorizontalProgressBarWithNumber_progress_text_offset, mTextOffset);
int textVisible = attributes.getInt(
R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility, VISIBLE);
int textVisible =
attributes.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,
VISIBLE);
if (textVisible != VISIBLE) {
mIfDrawText = false;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android">
<layout xmlns:android="http://schemas.android.com/apk/res/android"
>
<LinearLayout
android:layout_width="match_parent"
@ -8,10 +8,24 @@
android:orientation="vertical"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
<include layout="@layout/layout_bar"/>
<Button
android:id="@+id/single_task"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="单任务下载"
style="?buttonBarButtonStyle"
/>
<Button
android:id="@+id/multi_task"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="多任务下载"
style="?buttonBarButtonStyle"
/>
</LinearLayout>

View File

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

View File

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

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.design.widget.CoordinatorLayout
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_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
>
<include layout="@layout/layout_bar"/>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/content_single"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@android:drawable/ic_dialog_email"
/>
</android.support.design.widget.CoordinatorLayout>
</layout>

View File

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.arialyy.simple.activity.SimpleTestActivity"
tools:showIn="@layout/activity_simple"
>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:layout_toLeftOf="@+id/size"
/>
<TextView
android:id="@+id/size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/progressBar"
android:layout_marginRight="16dp"
android:text="ssss"
android:textSize="16sp"
/>
<LinearLayout
android:layout_width="match_parent"
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_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
android:id="@+id/cancel"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="删除任务"
/>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.arialyy.simple.activity.SingleTaskActivity"
tools:showIn="@layout/activity_single"
>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:layout_toLeftOf="@+id/size"
/>
<TextView
android:id="@+id/size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignTop="@+id/progressBar"
android:layout_marginRight="16dp"
android:text="ssss"
android:textSize="16sp"
/>
<LinearLayout
android:layout_width="match_parent"
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_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
android:id="@+id/cancel"
style="?buttonBarButtonStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="onClick"
android:text="删除任务"
/>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
/>

View File

@ -9,4 +9,20 @@
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!--设置导航栏内容可用-->
<!--<item name="android:windowTranslucentNavigation">true</item>-->
<!--设置状态栏内容可以-->
<!--<item name="android:windowTranslucentStatus">true</item>-->
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>
</resources>

View File

@ -6,6 +6,8 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.NoActionBar">

View File

@ -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);
}
}

0
cache/build/mPro.properties vendored Normal file
View File

View File

@ -3,13 +3,10 @@ package com.arialyy.downloadutil.core;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import com.arialyy.downloadutil.core.command.IDownloadCommand;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.orm.DbEntity;
import com.arialyy.downloadutil.orm.DbUtil;
import com.arialyy.downloadutil.util.Task;
import java.util.ArrayList;
import java.util.List;

View File

@ -2,7 +2,6 @@ package com.arialyy.downloadutil.core;
import android.content.Context;
import android.util.Log;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;

View File

@ -3,7 +3,6 @@ package com.arialyy.downloadutil.core;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.arialyy.downloadutil.core.inf.IDownloader;
import com.arialyy.downloadutil.core.inf.ITask;
import com.arialyy.downloadutil.core.pool.CachePool;
@ -100,8 +99,6 @@ public abstract class IDownloadTarget implements IDownloader, ITask {
/**
* 获取任务执行池
*
* @return
*/
public ExecutePool getExecutePool() {
return mExecutePool;

View File

@ -2,7 +2,6 @@ package com.arialyy.downloadutil.core;
import android.content.Context;
import android.os.Handler;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;

View File

@ -2,9 +2,8 @@ package com.arialyy.downloadutil.core.command;
import android.content.Context;
import android.util.Log;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/**
* Created by lyy on 2016/8/22.

View File

@ -1,9 +1,8 @@
package com.arialyy.downloadutil.core.command;
import android.content.Context;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/**
* Created by lyy on 2016/9/20.

View File

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.core.command;
import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity;
/**

View File

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.core.command;
import android.content.Context;
import com.arialyy.downloadutil.core.DownloadTarget;
import com.arialyy.downloadutil.core.IDownloadTarget;
import com.arialyy.downloadutil.entity.DownloadEntity;

View File

@ -1,9 +1,8 @@
package com.arialyy.downloadutil.core.command;
import android.content.Context;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/**
* Created by lyy on 2016/8/22.

View File

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.core.command;
import android.content.Context;
import com.arialyy.downloadutil.entity.DownloadEntity;
/**

View File

@ -2,7 +2,6 @@ package com.arialyy.downloadutil.core.command;
import android.content.Context;
import android.util.Log;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;

View File

@ -1,7 +1,7 @@
package com.arialyy.downloadutil.core.inf;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.entity.DownloadEntity;
import com.arialyy.downloadutil.util.Task;
/**
* Created by lyy on 2016/8/16.

View File

@ -2,11 +2,9 @@ package com.arialyy.downloadutil.core.pool;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.util.Util;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

View File

@ -2,11 +2,9 @@ package com.arialyy.downloadutil.core.pool;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.core.inf.IPool;
import com.arialyy.downloadutil.util.Task;
import com.arialyy.downloadutil.util.Util;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;

View File

@ -2,7 +2,6 @@ package com.arialyy.downloadutil.entity;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.downloadutil.orm.DbEntity;
import com.arialyy.downloadutil.orm.Ignore;

View File

@ -3,10 +3,8 @@ package com.arialyy.downloadutil.help;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.downloadutil.R;
import com.arialyy.downloadutil.entity.DownloadEntity;
import java.io.File;
/**

View File

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.help;
import android.os.Environment;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -18,15 +17,11 @@ public class PathHelp {
* @return 保存路径
*/
public static String urlconvertPath(String downloadUrl) {
return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey(
downloadUrl);
return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey(downloadUrl);
}
/**
* 字符串转换为hash码
*
* @param str
* @return
*/
public static String StringToHashKey(String str) {
String cacheKey;
@ -42,9 +37,6 @@ public class PathHelp {
/**
* 将普通字符串转换为16位进制字符串
*
* @param src
* @return
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("0x");
@ -59,5 +51,4 @@ public class PathHelp {
}
return stringBuilder.toString();
}
}

View File

@ -1,9 +1,7 @@
package com.arialyy.downloadutil.orm;
import android.support.annotation.NonNull;
import com.arialyy.downloadutil.util.Util;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
@ -55,7 +53,6 @@ public class DbEntity {
mUtil.modifyData(this);
}
/**
* 保存自身,如果表中已经有数据,则更新数据,否则插入数据
*/

View File

@ -6,9 +6,7 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import android.util.Log;
import com.arialyy.downloadutil.util.Util;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
@ -375,7 +373,8 @@ public class DbUtil {
/**
* 根据数据游标创建一个具体的对象
*/
private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, Cursor cursor) {
private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz,
Cursor cursor) {
Field[] fields = Util.getFields(clazz);
List<T> entitys = new ArrayList<>();
if (fields != null && fields.length > 0) {
@ -401,8 +400,7 @@ public class DbUtil {
} else if (type == long.class || type == Long.class) {
field.setLong(entity, cursor.getLong(column));
} else if (type == boolean.class || type == Boolean.class) {
field.setBoolean(entity,
!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) {
field.set(entity, new Date(cursor.getString(column)));
} else if (type == byte[].class) {

View File

@ -4,9 +4,7 @@ import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;
import android.util.SparseArray;
import com.arialyy.downloadutil.entity.DownloadEntity;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@ -22,6 +20,7 @@ import java.util.Properties;
*/
final class DownLoadUtil {
private static final String TAG = "DownLoadUtil";
private static final Object LOCK = new Object();
//下载监听
private IDownloadListener mListener;
/**
@ -43,7 +42,6 @@ final class DownLoadUtil {
private Context mContext;
private DownloadEntity mDownloadEntity;
public DownLoadUtil(Context context, DownloadEntity entity) {
mContext = context.getApplicationContext();
mDownloadEntity = entity;
@ -84,8 +82,8 @@ final class DownLoadUtil {
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");
File config =
new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
if (config.exists()) {
config.delete();
}
@ -120,8 +118,8 @@ final class DownLoadUtil {
final String downloadUrl = mDownloadEntity.getDownloadUrl();
final File dFile = new File(filePath);
//读取已完成的线程数
final File configFile = new File(
mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
final File configFile =
new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
try {
if (!configFile.exists()) { //记录文件被删除,则重新下载
isNewTask = true;
@ -142,11 +140,11 @@ final class DownLoadUtil {
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.setConnectTimeout(TIME_OUT * 4);
conn.connect();
int len = conn.getContentLength();
if (len < 0) { //网络被劫持时会出现这个问题
@ -207,8 +205,9 @@ final class DownLoadUtil {
}
//分配下载位置
Object record = pro.getProperty(dFile.getName() + "_record_" + i);
if (!isNewTask && record != null && Long.parseLong(
record + "") > 0) { //如果有记录,则恢复下载
if (!isNewTask
&& record != null
&& Long.parseLong(record + "") > 0) { //如果有记录,则恢复下载
Long r = Long.parseLong(record + "");
mCurrentLocation += r - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
@ -227,9 +226,8 @@ final class DownLoadUtil {
//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
endL = fileLength;
}
ConfigEntity entity = new ConfigEntity(mContext, fileLength,
downloadUrl, dFile, i, startL,
endL);
ConfigEntity entity =
new ConfigEntity(mContext, fileLength, downloadUrl, dFile, i, startL, endL);
DownLoadTask task = new DownLoadTask(entity);
tasks.put(i, new Thread(task));
}
@ -249,9 +247,12 @@ final class DownLoadUtil {
failDownload("下载失败,返回码:" + code);
}
} catch (IOException e) {
failDownload(
"下载失败【downloadUrl:" + downloadUrl + "\n【filePath:" + filePath + "" + Util
.getPrintException(e));
failDownload("下载失败【downloadUrl:"
+ downloadUrl
+ "\n【filePath:"
+ filePath
+ ""
+ Util.getPrintException(e));
}
}
}).start();
@ -272,17 +273,25 @@ final class DownLoadUtil {
private ConfigEntity dEntity;
private String configFPath;
public DownLoadTask(ConfigEntity downloadInfo) {
private DownLoadTask(ConfigEntity downloadInfo) {
this.dEntity = downloadInfo;
configFPath = dEntity.context.getFilesDir()
.getPath() + "/temp/" + dEntity.tempFile.getName() + ".properties";
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 + "");
Log.d(TAG, "线程_"
+ dEntity.threadId
+ "_正在下载【"
+ "开始位置 : "
+ dEntity.startLocation
+ ",结束位置:"
+ dEntity.endLocation
+ "");
URL url = new URL(dEntity.downloadUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//在头里面请求下载开始位置和结束位置
@ -315,48 +324,19 @@ final class DownLoadUtil {
}
//把下载数据数据写入文件
file.write(buffer, 0, len);
synchronized (DownLoadUtil.this) {
mCurrentLocation += len;
mListener.onProgress(mCurrentLocation);
}
progress(len);
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();
}
}
cancel();
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);
}
}
stop(currentLocation);
return;
}
Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕");
@ -372,42 +352,59 @@ final class DownLoadUtil {
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();
}
}
failDownload(dEntity, currentLocation, "下载链接异常", e);
} 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();
}
}
failDownload(dEntity, currentLocation, "下载失败【" + dEntity.downloadUrl + "", e);
} catch (Exception e) {
synchronized (DownLoadUtil.this) {
try {
failDownload(dEntity, currentLocation, "获取流失败", e);
}
}
/**
* 停止下载
*
* @throws IOException
*/
private void stop(long currentLocation) throws IOException {
synchronized (LOCK) {
mStopNum++;
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId,
location);
failDownload("获取流失败" + Util.getPrintException(e));
} catch (IOException e1) {
e1.printStackTrace();
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);
}
}
}
/**
* 取消下载
*/
private void cancel() {
synchronized (LOCK) {
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();
}
}
}
private void progress(long len) {
synchronized (LOCK) {
mCurrentLocation += len;
mListener.onProgress(mCurrentLocation);
}
}
/**
@ -419,6 +416,30 @@ final class DownLoadUtil {
pro.setProperty(key, record);
Util.saveConfig(configFile, pro);
}
/**
* 下载失败
*/
private void failDownload(ConfigEntity dEntity, long currentLocation, String msg,
Exception ex) {
synchronized (LOCK) {
try {
isDownloading = false;
isStop = true;
Log.e(TAG, msg);
if (ex != null) {
Log.e(TAG, Util.getPrintException(ex));
}
if (currentLocation != -1) {
String location = String.valueOf(currentLocation);
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
}
mListener.onFail();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
@ -434,8 +455,8 @@ final class DownLoadUtil {
File tempFile;
Context context;
public ConfigEntity(Context context, long fileSize, String downloadUrl, File file,
int threadId, long startLocation, long endLocation) {
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;

View File

@ -5,11 +5,9 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.util.Log;
import com.arialyy.downloadutil.core.DownloadManager;
import com.arialyy.downloadutil.core.IDownloadTarget;
import com.arialyy.downloadutil.entity.DownloadEntity;
import java.net.HttpURLConnection;
/**
@ -105,9 +103,6 @@ public class Task {
/**
* 创建特定的Intent
*
* @param action
* @return
*/
private Intent createIntent(String action) {
Uri.Builder builder = new Uri.Builder();
@ -142,8 +137,7 @@ public class Task {
long INTERVAL_TIME = 60 * 1000; //10k大小的间隔
DownloadEntity downloadEntity;
DownloadListener(Context context, DownloadEntity downloadEntity,
Handler outHandler) {
DownloadListener(Context context, DownloadEntity downloadEntity, Handler outHandler) {
this.context = context;
this.outHandler = outHandler;
this.downloadEntity = downloadEntity;

View File

@ -1,7 +1,6 @@
package com.arialyy.downloadutil.util;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -59,9 +58,6 @@ public class Util {
/**
* 字符串转hashcode
*
* @param str
* @return
*/
public static int keyToHashCode(String str) {
int total = 0;

View File

@ -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);
}
}