功能:版本更新、文件后台下载以及Notification显示进度条。
效果图:
主要代码:
package com.ljp.download;
import java.io.File;
import android.app.ActivityGroup;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import com.ljp.download.service.AppUpgradeService;
import com.ljp.version.R;
public class MainActivity extends ActivityGroup {
private Button button1;
private String mDownloadUrl = "http://gdown.baidu.com/data/wisegame/ba226d3cf2cfc97b/baiduyinyue_4920.apk";
private String apkUpdateMsg = "1.内容1\n2.内容2\n3.内容3";
private Dialog updateVersionDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
showDialog();
}
});
}
private void showDialog() {
updateVersionDialog = new AlertDialog.Builder(MainActivity.this).setTitle("有新版本需要更新").setMessage(apkUpdateMsg)
.setPositiveButton("现在更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
downLoadApk();
}
}).setNegativeButton("以后再说", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
}
}).create();
updateVersionDialog.show();
}
/**
* 文件下载
*/
private void downLoadApk() {
Intent intent = new Intent(MainActivity.this, AppUpgradeService.class);
intent.putExtra("mDownloadUrl", mDownloadUrl);
startService(intent);
updateVersionDialog.dismiss();
}
}
package com.ljp.download.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import com.ljp.download.DownloadUtils;
import com.ljp.download.MainActivity;
import com.ljp.version.R;
/**
* 程序版本更新Service
* @author yingjun10627
*
*/
public class AppUpgradeService extends Service {
private NotificationManager mNotificationManager = null;
private Notification mNotification = null;
private PendingIntent mPendingIntent = null;
private String mDownloadUrl;
private File destDir = null;
private File destFile = null;
public static final String downloadPath = "/winner";
public static final int mNotificationId = 111;
private static final int DOWNLOAD_FAIL = -1;
private static final int DOWNLOAD_SUCCESS = 0;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOAD_SUCCESS:
Toast.makeText(getApplicationContext(), "下载成功", Toast.LENGTH_LONG).show();
install(destFile);
mNotificationManager.cancel(mNotificationId);
break;
case DOWNLOAD_FAIL:
Toast.makeText(getApplicationContext(), "下载失败", Toast.LENGTH_LONG).show();
mNotificationManager.cancel(mNotificationId);
break;
default:
break;
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent==null){
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
mDownloadUrl = intent.getStringExtra("mDownloadUrl");
if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
destDir = new File(Environment.getExternalStorageDirectory().getPath() + downloadPath);
if (destDir.exists()) {
File destFile = new File(destDir.getPath() + "/" + URLEncoder.encode(mDownloadUrl));
if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) {
install(destFile);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
} else {
return super.onStartCommand(intent, flags, startId);
}
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotification = new Notification();
Intent completingIntent = new Intent();
completingIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
completingIntent.setClass(getApplicationContext(), AppUpgradeService.class);
// 创建Notifcation对象,设置图标,提示文字,策略
mPendingIntent = PendingIntent.getActivity(AppUpgradeService.this, R.string.app_name, completingIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mNotification.icon = R.drawable.ic_launcher;
mNotification.tickerText = "开始下载";
mNotification.contentIntent = mPendingIntent;
mNotification.contentView = new RemoteViews(getPackageName(), R.layout.app_upgrade_notification);
mNotification.contentView.setProgressBar(R.id.app_upgrade_progressbar, 100, 0, false);
mNotification.contentView.setTextViewText(R.id.app_upgrade_title, "正在下载...");
mNotification.contentView.setTextViewText(R.id.app_upgrade_text, "当前进度:0%");
mNotificationManager.cancel(mNotificationId);
mNotificationManager.notify(mNotificationId, mNotification);
new AppUpgradeThread().start();
return super.onStartCommand(intent, flags, startId);
}
/**
* 用于监听文件下载
*/
private DownloadUtils.DownloadListener downloadListener = new DownloadUtils.DownloadListener() {
@Override
public void downloading(int progress) {
System.out.println(progress);
mNotification.contentView.setProgressBar(R.id.app_upgrade_progressbar, 100, progress, false);
mNotification.contentView.setTextViewText(R.id.app_upgrade_text, "当前进度:" + progress + "%");
mNotificationManager.notify(mNotificationId, mNotification);
}
@Override
public void downloaded() {
mNotification.contentView.setViewVisibility(R.id.app_upgrade_progressbar, View.GONE);
mNotification.defaults = Notification.DEFAULT_SOUND;
mNotification.contentIntent = mPendingIntent;
mNotification.contentView.setTextViewText(R.id.app_upgrade_title, "下载完成");
mNotificationManager.notify(mNotificationId, mNotification);
if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) {
Message msg = mHandler.obtainMessage();
msg.what = DOWNLOAD_SUCCESS;
mHandler.sendMessage(msg);
}
mNotificationManager.cancel(mNotificationId);
}
};
/**
* 用于文件下载线程
* @author yingjun10627
*
*/
class AppUpgradeThread extends Thread {
@Override
public void run() {
if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
if (destDir == null) {
destDir = new File(Environment.getExternalStorageDirectory().getPath() + downloadPath);
}
if (destDir.exists() || destDir.mkdirs()) {
destFile = new File(destDir.getPath() + "/" + URLEncoder.encode(mDownloadUrl));
if (destFile.exists() && destFile.isFile() && checkApkFile(destFile.getPath())) {
install(destFile);
} else {
try {
DownloadUtils.download(mDownloadUrl, destFile, false, downloadListener);
} catch (Exception e) {
Message msg = mHandler.obtainMessage();
msg.what = DOWNLOAD_FAIL;
mHandler.sendMessage(msg);
e.printStackTrace();
}
}
}
}
stopSelf();
}
}
/**
* apk文件安装
*
* @param apkFile
*/
public void install(File apkFile) {
Uri uri = Uri.fromFile(apkFile);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
/**
* 判断文件是否完整
*
* @param apkFilePath
* @return
*/
public boolean checkApkFile(String apkFilePath) {
boolean result = false;
try {
PackageManager pManager = getPackageManager();
PackageInfo pInfo = pManager.getPackageArchiveInfo(apkFilePath, PackageManager.GET_ACTIVITIES);
if (pInfo == null) {
result = false;
} else {
result = true;
}
} catch (Exception e) {
result = false;
e.printStackTrace();
}
return result;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
package com.ljp.download;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class DownloadUtils {
private static final int CONNECT_TIMEOUT = 10000;
private static final int DATA_TIMEOUT = 40000;
private final static int DATA_BUFFER = 8192;
public interface DownloadListener {
public void downloading(int progress);
public void downloaded();
}
public static long download(String urlStr, File dest, boolean append, DownloadListener downloadListener) throws Exception {
int downloadProgress = 0;
long remoteSize = 0;
int currentSize = 0;
long totalSize = -1;
if (!append && dest.exists() && dest.isFile()) {
dest.delete();
}
if (append && dest.exists() && dest.exists()) {
FileInputStream fis = null;
try {
fis = new FileInputStream(dest);
currentSize = fis.available();
} catch (IOException e) {
throw e;
} finally {
if (fis != null) {
fis.close();
}
}
}
HttpGet request = new HttpGet(urlStr);
if (currentSize > 0) {
request.addHeader("RANGE", "bytes=" + currentSize + "-");
}
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, CONNECT_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, DATA_TIMEOUT);
HttpClient httpClient = new DefaultHttpClient(params);
InputStream is = null;
FileOutputStream os = null;
try {
HttpResponse response = httpClient.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
is = response.getEntity().getContent();
remoteSize = response.getEntity().getContentLength();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
is = new GZIPInputStream(is);
}
os = new FileOutputStream(dest, append);
byte buffer[] = new byte[DATA_BUFFER];
int readSize = 0;
int temp=0;
while ((readSize = is.read(buffer)) > 0) {
os.write(buffer, 0, readSize);
os.flush();
totalSize += readSize;
if (downloadListener != null) {
downloadProgress = (int) (totalSize * 100 / remoteSize);
if(downloadProgress>=temp){
temp++;
downloadListener.downloading(downloadProgress);
}
}
}
if (totalSize < 0) {
totalSize = 0;
}
}
} finally {
if (os != null) {
os.close();
}
if (is != null) {
is.close();
}
}
if (totalSize < 0) {
throw new Exception("Download file fail: " + urlStr);
}
if (downloadListener != null) {
downloadListener.downloaded();
}
return totalSize;
}
}
Service启动方式说明:
START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。