1.下载监听回调接口UpdateDownloadListener.java
package com.czhappy.appupdate.utils;
/**
* Description:
* User: chenzheng
* Date: 2016/12/14 0014
* Time: 16:23
*/
public interface UpdateDownloadListener {
public void onStarted();
public void onProgressChanged(int progress, String downloadUrl);
public void onFinished(float completeSize, String downloadUrl);
public void onFailure();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2.文件下载及线程通信UpdateDownloadRequest.java
package com.czhappy.appupdate.utils;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
/**
* Description:文件下载及线程间通信
* User: chenzheng
* Date: 2016/12/14 0014
* Time: 16:24
*/
public class UpdateDownloadRequest implements Runnable{
private String downloadUrl;
private String localFilePath;
private UpdateDownloadListener listener;
private boolean isDownloading = false;
private long currentLength;
private DownloadResponseHandler downloadResponseHandler;
public UpdateDownloadRequest(String downloadUrl, String localFilePath, UpdateDownloadListener listener){
this.downloadUrl = downloadUrl;
this.localFilePath = localFilePath;
this.listener = listener;
this.isDownloading = true;
downloadResponseHandler = new DownloadResponseHandler();
}
private String getTwoPointFloatStr(float value){
DecimalFormat df = new DecimalFormat("0.00000000000");
return df.format(value);
}
private void makeRequest() throws IOException, InterruptedIOException{
if(!Thread.currentThread().isInterrupted()){
try {
URL url = new URL(downloadUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.connect();
currentLength = connection.getContentLength();
if(!Thread.currentThread().isInterrupted()){
downloadResponseHandler.sendResponseMessage(connection.getInputStream());
}
}catch (Exception e){
throw e;
}
}
}
@Override
public void run() {
try{
makeRequest();
}catch (IOException e){
}
}
/**
* 下载过程中的异常
*/
public enum FailureCode{
UnknownHost, Socket, SocketTimeout, connectionTimeout,IO, HttpResponse,
Json, Interrupted
}
public class DownloadResponseHandler{
protected static final int SUCCESS_MESSAGE = 0;
protected static final int FAILURE_MESSAGE = 1;
protected static final int START_MESSAGE = 2;
protected static final int FINISH_MESSAGE = 3;
protected static final int NETWORK_OFF = 4;
private static final int PROGRESS_CHANGED = 5;
private float completeSize = 0;
private int progress = 0;
private Handler handler;
public DownloadResponseHandler(){
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
handleSelfMessage(msg);
}
};
}
protected void sendFinishMessage(){
sendMessage(obtainMessage(FINISH_MESSAGE, null));
}
private void sendProgressChangedMessage(int progress){
sendMessage(obtainMessage(PROGRESS_CHANGED, new Object[]{progress}));
}
protected void sendFailureMessage(FailureCode failureCode){
sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]{failureCode}));
}
protected void sendMessage(Message msg){
if(handler!=null){
handler.sendMessage(msg);
}else{
handleSelfMessage(msg);
}
}
protected Message obtainMessage(int responseMessge, Object response){
Message msg = null;
if(handler!=null){
msg = handler.obtainMessage(responseMessge, response);
}else{
msg = Message.obtain();
msg.what = responseMessge;
msg.obj = response;
}
return msg;
}
protected void handleSelfMessage(Message msg){
Object[] response;
switch (msg.what){
case FAILURE_MESSAGE:
response = (Object[]) msg.obj;
sendFailureMessage((FailureCode) response[0]);
break;
case PROGRESS_CHANGED:
response = (Object[]) msg.obj;
handleProgressChangedMessage(((Integer)response[0]).intValue());
break;
case FINISH_MESSAGE:
onFinish();
break;
}
}
protected void handleProgressChangedMessage(int progress){
listener.onProgressChanged(progress, downloadUrl);
}
protected void onFinish(){
listener.onFinished(completeSize, "");
}
private void handleFailureMessage(FailureCode failureCode){
onFailure(failureCode);
}
protected void onFailure(FailureCode failureCode){
listener.onFailure();
}
void sendResponseMessage(InputStream is){
RandomAccessFile randomAccessFile = null;
completeSize=0;
try{
byte[] buffer = new byte[1024];
int length=-1;//读写长度
int limit=0;
randomAccessFile = new RandomAccessFile(localFilePath, "rwd");
while((length = is.read(buffer))!=-1){
if(isDownloading){
randomAccessFile.write(buffer, 0 ,length);
completeSize += length;
if(completeSize < currentLength){
Log.e("tag", "completeSize="+completeSize);
Log.e("tag", "currentLength="+currentLength);
progress = (int)(Float.parseFloat(getTwoPointFloatStr(completeSize/currentLength))*100);
Log.e("tag", "下载进度:"+progress);
if(limit % 30==0 && progress <= 100){//隔30次更新一次notification
sendProgressChangedMessage(progress);
}
limit++;
}
}
}
sendFinishMessage();
}catch(IOException e){
sendFailureMessage(FailureCode.IO);
}finally{
try{
if(is!=null){
is.close();
}
if(randomAccessFile!=null){
randomAccessFile.close();
}
}catch(IOException e){
sendFailureMessage(FailureCode.IO);
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
3.文件下载对外方法UpdateManager.java
package com.czhappy.appupdate.utils;
import android.util.Log;
import java.io.File;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* Description:
* User: chenzheng
* Date: 2016/12/14 0014
* Time: 16:24
*/
public class UpdateManager {
private static UpdateManager updateManager;
private ThreadPoolExecutor threadPoolExecutor;
private UpdateDownloadRequest request;
private UpdateManager(){
threadPoolExecutor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
}
static{
updateManager = new UpdateManager();
}
public static UpdateManager getInstance(){
return updateManager;
}
public void startDownloads(String downloadUrl, String localPath, UpdateDownloadListener listener){
if(request != null){
return;
}
checkLocalFilePath(localPath);
request = new UpdateDownloadRequest(downloadUrl, localPath, listener);
Future<?> future = threadPoolExecutor.submit(request);
}
/**
* 检查文件路径是否存在
* @param path
*/
private void checkLocalFilePath(String path) {
Log.e("tag", path);
File dir = new File(path.substring(0, path.lastIndexOf("/")+1));
if(!dir.exists()){
dir.mkdir();
}
File file = new File(path);
if(!file.exists()){
try{
file.createNewFile();
}catch (Exception e){
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
4.通知栏进度更新进程UpdateService.java
package com.czhappy.appupdate.utils;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import com.czhappy.appupdate.R;
import java.io.File;
/**
* Description:更新下载后台进程
* User: chenzheng
* Date: 2016/12/14 0014
* Time: 16:24
*/
public class UpdateService extends Service{
private String apkUrl;
private String filePath;
private NotificationManager notificationManager;
private Notification notification;
@Override
public void onCreate() {
Log.e("tag", "UpdateService onCreate()");
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
filePath = Environment.getExternalStorageDirectory()+"/AppUpdate/czhappy.apk";
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("tag", "UpdateService onStartCommand()");
if(intent==null){
notifyUser(getString(R.string.update_download_failed), getString(R.string.update_download_failed), 0);
stopSelf();
}
apkUrl = intent.getStringExtra("apkUrl");
notifyUser(getString(R.string.update_download_start), getString(R.string.update_download_start), 0);
startDownload();
return super.onStartCommand(intent, flags, startId);
}
private void startDownload() {
UpdateManager.getInstance().startDownloads(apkUrl, filePath, new UpdateDownloadListener() {
@Override
public void onStarted() {
Log.e("tag", "onStarted()");
}
@Override
public void onProgressChanged(int progress, String downloadUrl) {
Log.e("onProgressChanged", progress+"");
notifyUser(getString(R.string.update_download_progressing), getString(R.string.update_download_progressing), progress);
}
@Override
public void onFinished(float completeSize, String downloadUrl) {
Log.e("tag", "onFinished()");
notifyUser(getString(R.string.update_download_finish), getString(R.string.update_download_finish), 100);
stopSelf();
}
@Override
public void onFailure() {
Log.e("tag", "onFailure()");
notifyUser(getString(R.string.update_download_failed), getString(R.string.update_download_failed), 0);
stopSelf();
}
});
}
/**
* 更新notification
* @param result
* @param msg
* @param progress
*/
private void notifyUser(String result, String msg, int progress){
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setContentTitle(getString(R.string.app_name));
if(progress>0 && progress<=100){
builder.setProgress(100,progress,false);
}else{
builder.setProgress(0, 0, false);
}
builder.setAutoCancel(true);
builder.setWhen(System.currentTimeMillis());
builder.setTicker(result);
builder.setContentIntent(progress>=100 ? getContentIntent() :
PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT));
notification = builder.build();
notificationManager.notify(0, notification);
}
/**
* 进入apk安装程序
* @return
*/
private PendingIntent getContentIntent() {
Log.e("tag", "getContentIntent()");
File apkFile = new File(filePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("file://"+apkFile.getAbsolutePath()),
"application/vnd.android.package-archive");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
startActivity(intent);
return pendingIntent;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
5.测试类MainActivity.java
package com.czhappy.appupdate.activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import com.czhappy.appupdate.R;
import com.czhappy.appupdate.dialog.CommonDialog;
import com.czhappy.appupdate.utils.UpdateService;
public class MainActivity extends AppCompatActivity {
private Button update_btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
update_btn = (Button) this.findViewById(R.id.update_btn);
update_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkVersion();
}
});
checkVersion();
}
private void checkVersion(){
//这里不发送检测新版本网络请求,直接进入下载新版本安装
CommonDialog.Builder builder = new CommonDialog.Builder(this);
builder.setTitle("升级提示");
builder.setMessage("发现新版本,请及时更新");
builder.setPositiveButton("立即升级", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
Intent intent = new Intent(MainActivity.this, UpdateService.class);
intent.putExtra("apkUrl", "http://121.42.53.175:8080/hello_project/resources/upload/TianQiBao201605231.apk");
startService(intent);
}
});
builder.setNegativeButton("下次再说", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}