例子编写

This commit is contained in:
lyy
2016-09-27 22:41:35 +08:00
parent 3496022c60
commit 2ad2f31594
53 changed files with 2793 additions and 2592 deletions

2
.idea/misc.xml generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

@ -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>

View File

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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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>

View File

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