几种检查更新并下载新版本的实现
2015-12-01 12:35
483 查看
1.首先是获取当前程序的版本号
这里需要注意,由于UpdateInfoService类的getUpdateInfo方法中访问服务器不是异步的,如果直接在Activity的onCreate()中直接调用isNeedUpdate(getVersion())获取不到更新信息,需要将isNeedUpdate(getVersion())放入到子线程中。
4.一种方式使用AsyncTask来下载apk文件
5.另一种方式使用Service,参照http://blog.csdn.net/xiaanming/article/details/9750689
public class DownloadFileService extends Service {
private String urlPath="";
//文件存储
private File updateFile = null;
private OnProgressListener onProgressListener;
private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
public DownloadFileService() {
}
public void setOnProgressListener(OnProgressListener onProgressListener) {
this.onProgressListener = onProgressListener;
}
/**
* 返回一个Binder对象
*/
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
return new DownloadBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
urlPath = intent.getStringExtra("url");
//创建文件
if(FileUtil.haveSDCard()) {
updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
}
//开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new DownloadRunnable()).start();
return super.onStartCommand(intent, flags, startId);
}
class DownloadRunnable implements Runnable {
@Override
public void run() {
HttpURLConnection httpURLConnection = null;
InputStream input = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(2000);
httpURLConnection.setRequestMethod("GET");
if(httpURLConnection.getResponseCode() == 200) {
int total = httpURLConnection.getContentLength();
if(onProgressListener != null) {
onProgressListener.onProgressInitialize(total);
}
input = httpURLConnection.getInputStream();
fos = new FileOutputStream(updateFile);
byte[] buffer = new byte[1024];
int len;
int progress = 0;
while((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
progress += len;
//进度发生变化通知调用方
if(onProgressListener != null){
onProgressListener.onProgressUpdate(progress);
}
}
fos.flush();
if(onProgressListener != null){
onProgressListener.onProgressComplete(updateFile);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null) {
fos.close();
}
if(input != null) {
input.close();
}
if(httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class DownloadBinder extends Binder {
b81b
/**
* 获取当前Service的实例
*/
public DownloadFileService getService() {
return DownloadFileService.this;
}
}
}
为了能使DownloadFileService中进度变化信息通知给调用方,首先定义一个接口
public interface OnProgressListener {
void onProgressInitialize(int total);
void onProgressUpdate(int progress);
void onProgressComplete(File file);
}
然后在Activity中绑定Service
public class SplashActivity extends BaseActivity {
private ProgressDialog progressDialog;
private UpdateInfo info;
private static final String TAG = "SplashActivity";
private DownloadFileService downloadFileService;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回一个DownloadFileService对象
downloadFileService = ((DownloadFileService.DownloadBinder)service).getService();
//注册回调接口来接收下载进度的变化
downloadFileService.setOnProgressListener(new OnProgressListener() {
@Override
public void onProgressInitialize(int total) {
progressDialog.setMax(total);
}
@Override
public void onProgressUpdate(int progress) {
progressDialog.setProgress(progress);
}
@Override
public void onProgressComplete(File file) {
progressDialog.dismiss();
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
unbindService(conn);
stopService(intent);
//安装下载的文件
install(file);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
在ServiceConnection的onServiceConnected回调中为service设置了回调监听器。当在DownloadFileService中调用时就会执行这里的回调,更新progressDialog
然后在对话框的确定按钮的响应事件中启动Service
将new DownloadFileTask().execute(info.getUrl(), apkPath); 替换为
//绑定DownloadFileService
//Intent intent = new Intent("com.yifeng.chaoshibang.service.DOWNLOAD_APK_ACTION");
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
intent.putExtra("url", info.getUrl());
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
progressDialog.show();
这里需要注意,在DownloadFileService中是在onStartCommand()方法中启动线程去下载文件。根据Service的生命周期,bindService()方法不会调用onStartCommand(),所以还需使用startService()启动Service。
6.Service和BroadcastReceiver实现
public class DownloadFileService extends BaseService {
private String urlPath="";
//文件存储
private File updateFile = null;
private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
public DownloadFileService() {
}
/**
* 返回一个Binder对象
*/
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
urlPath = intent.getStringExtra("url");
//创建文件
if(FileUtil.haveSDCard()) {
updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
}
//开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new DownloadRunnable()).start();
return super.onStartCommand(intent, flags, startId);
}
class DownloadRunnable implements Runnable {
@Override
public void run() {
HttpURLConnection httpURLConnection = null;
InputStream input = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(2000);
httpURLConnection.setRequestMethod("GET");
if(httpURLConnection.getResponseCode() == 200) {
int total = httpURLConnection.getContentLength();
input = httpURLConnection.getInputStream();
fos = new FileOutputStream(updateFile);
byte[] buffer = new byte[1024];
int len;
int progress = 0;
while((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
progress += len;
mIntent.putExtra("progress", progress);
mIntent.putExtra("total", total);
sendBroadcast(mIntent);
}
fos.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null) {
fos.close();
}
if(input != null) {
input.close();
}
if(httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}onCreate()方法中注册广播接收器
//动态注册广播接收器
updateReceiver = new UpdateProgressReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
registerReceiver(updateReceiver, intentFilter);
protected void onDestroy() {
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
//停止服务
stopService(intent);
//注销广播
unregisterReceiver(updateReceiver);
super.onDestroy();
}
然后在确定下载按钮的监听事件响应中启动service
private void showUpdateDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Environment.getExternalStorageDirectory(), "/chaoshibang/update");
if(!dir.exists()) {
dir.mkdirs();
}
String apkPath = Environment.getExternalStorageDirectory() + "/chaoshibang/update/new.apk";
//启动服务
Intent mIntent = new Intent(SplashActivity.this, DownloadFileService.class);
mIntent.putExtra("url", info.getUrl());
startService(mIntent);
progressDialog.show();
} else {
Toast.makeText(SplashActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show();
loadMainUI();
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
loadMainUI();
}
});
builder.create().show();
}
private String getVersion() { try { PackageManager packageManager = getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0); return packageInfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); return "版本号未知"; } }2. 访问服务器检查是否更新
private boolean isNeedUpdate(String version) { UpdateInfoService updateInfoService = new UpdateInfoService(this); try { info = updateInfoService.getUpdateInfo(R.string.serverUrl); String v = info.getVersion(); if(v.equals(version)) { Log.i(TAG, "当前版本:" + version); Log.i(TAG, "最新版本:" + v); loadMainUI(); return false; } else { Log.i(TAG, "需要更新"); return true; } } catch (Exception e) { e.printStackTrace(); Toast.makeText(this, "获取更新信息异常,请稍后再试", Toast.LENGTH_SHORT).show(); loadMainUI(); } return false; }R.string.serverUrl是服务器放置更新信息的地址,使用一个类去查询更新信息
public class UpdateInfoService { private Context context; public UpdateInfoService(Context context) { this.context = context; } public UpdateInfo getUpdateInfo(int urlId) throws Exception { String path = context.getResources().getString(urlId);////拿到config.xml里面存放的地址 URL url = new URL(path); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();//开启一个http链接 httpURLConnection.setConnectTimeout(10000);//设置链接的超时时间,现在为5秒 httpURLConnection.setRequestMethod("GET");//设置请求的方式 InputStream is = httpURLConnection.getInputStream();//拿到一个输入流。里面包含了update.xml的信息 return UpdateInfoParser.getUpdateInfo(is);//解析xml } }其中用到了一个解析xml文件的类
public class UpdateInfoParser { public static UpdateInfo getUpdateInfo(InputStream is) throws Exception { UpdateInfo info = new UpdateInfo(); XmlPullParser xmlPullParser = Xml.newPullParser(); xmlPullParser.setInput(is, "utf-8"); int type = xmlPullParser.getEventType(); while(type != XmlPullParser.END_DOCUMENT) { switch(type) { case XmlPullParser.START_TAG : if(xmlPullParser.getName().equals("version")) { info.setVersion(xmlPullParser.nextText()); } else if (xmlPullParser.getName().equals("description")) { info.setDescription(xmlPullParser.nextText()); } else if (xmlPullParser.getName().equals("apkurl")) { info.setUrl(xmlPullParser.nextText()); } break; default : break; } type = xmlPullParser.next(); } return info; } }3.下面调用isNeedUpdate(getVersion())检查是否需要更新
这里需要注意,由于UpdateInfoService类的getUpdateInfo方法中访问服务器不是异步的,如果直接在Activity的onCreate()中直接调用isNeedUpdate(getVersion())获取不到更新信息,需要将isNeedUpdate(getVersion())放入到子线程中。
class UpdateHandler implements Runnable { @Override public void run() { Looper.prepare(); if(isNeedUpdate(getVersion())) { showUpdateDialog(); } Looper.loop(); } }然后在onCreate方法中启动线程
Runnable r = new UpdateHandler(); Thread thread = new Thread(r); thread.start();然后是显示对话框
private void showUpdateDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setCancelable(false); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { File dir = new File(Environment.getExternalStorageDirectory(), "/chaoshibang/update"); if(!dir.exists()) { dir.mkdirs(); } String apkPath = Environment.getExternalStorageDirectory() + "/chaoshibang/update/new.apk"; //这里启动DownloadFileTask任务 new DownloadFileTask().execute(info.getUrl(), apkPath); progressDialog.show(); } else { Toast.makeText(SplashActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show(); loadMainUI(); } } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { loadMainUI(); } }); builder.create().show(); }在对话框的确定按钮的响应事件中下载APK文件
4.一种方式使用AsyncTask来下载apk文件
private class DownloadFileTask extends AsyncTask<String, Integer, File> { public DownloadFileTask() { super(); } @Override protected void onPreExecute() { super.onPreExecute(); progressDialog.show(); } @Override protected void onPostExecute(File file) { super.onPostExecute(file); progressDialog.dismiss(); loadMainUI(); Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); startActivity(intent); } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); progressDialog.setMax(values[1]); progressDialog.setProgress(values[0]); } @Override protected File doInBackground(String... params) { try { URL url = new URL(params[0]); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setConnectTimeout(2000); httpURLConnection.setRequestMethod("GET"); if(httpURLConnection.getResponseCode() == 200) { int total = httpURLConnection.getContentLength(); InputStream is = httpURLConnection.getInputStream(); File file = new File(params[1]); FileOutputStream fos = new FileOutputStream(file); byte[] buffer = new byte[1024]; int len; int process = 0; while((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); process += len; publishProgress(process, total); } fos.flush(); fos.close(); is.close(); return file; } } catch (Exception e) { e.printStackTrace(); } return null; } }doInbackground()在子线程中下载apk文件,在其它三个方法中操作progressDialog的显示、进度
5.另一种方式使用Service,参照http://blog.csdn.net/xiaanming/article/details/9750689
public class DownloadFileService extends Service {
private String urlPath="";
//文件存储
private File updateFile = null;
private OnProgressListener onProgressListener;
private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
public DownloadFileService() {
}
public void setOnProgressListener(OnProgressListener onProgressListener) {
this.onProgressListener = onProgressListener;
}
/**
* 返回一个Binder对象
*/
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
return new DownloadBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
urlPath = intent.getStringExtra("url");
//创建文件
if(FileUtil.haveSDCard()) {
updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
}
//开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new DownloadRunnable()).start();
return super.onStartCommand(intent, flags, startId);
}
class DownloadRunnable implements Runnable {
@Override
public void run() {
HttpURLConnection httpURLConnection = null;
InputStream input = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(2000);
httpURLConnection.setRequestMethod("GET");
if(httpURLConnection.getResponseCode() == 200) {
int total = httpURLConnection.getContentLength();
if(onProgressListener != null) {
onProgressListener.onProgressInitialize(total);
}
input = httpURLConnection.getInputStream();
fos = new FileOutputStream(updateFile);
byte[] buffer = new byte[1024];
int len;
int progress = 0;
while((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
progress += len;
//进度发生变化通知调用方
if(onProgressListener != null){
onProgressListener.onProgressUpdate(progress);
}
}
fos.flush();
if(onProgressListener != null){
onProgressListener.onProgressComplete(updateFile);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null) {
fos.close();
}
if(input != null) {
input.close();
}
if(httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public class DownloadBinder extends Binder {
b81b
/**
* 获取当前Service的实例
*/
public DownloadFileService getService() {
return DownloadFileService.this;
}
}
}
为了能使DownloadFileService中进度变化信息通知给调用方,首先定义一个接口
public interface OnProgressListener {
void onProgressInitialize(int total);
void onProgressUpdate(int progress);
void onProgressComplete(File file);
}
然后在Activity中绑定Service
public class SplashActivity extends BaseActivity {
private ProgressDialog progressDialog;
private UpdateInfo info;
private static final String TAG = "SplashActivity";
private DownloadFileService downloadFileService;
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回一个DownloadFileService对象
downloadFileService = ((DownloadFileService.DownloadBinder)service).getService();
//注册回调接口来接收下载进度的变化
downloadFileService.setOnProgressListener(new OnProgressListener() {
@Override
public void onProgressInitialize(int total) {
progressDialog.setMax(total);
}
@Override
public void onProgressUpdate(int progress) {
progressDialog.setProgress(progress);
}
@Override
public void onProgressComplete(File file) {
progressDialog.dismiss();
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
unbindService(conn);
stopService(intent);
//安装下载的文件
install(file);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
在ServiceConnection的onServiceConnected回调中为service设置了回调监听器。当在DownloadFileService中调用时就会执行这里的回调,更新progressDialog
然后在对话框的确定按钮的响应事件中启动Service
将new DownloadFileTask().execute(info.getUrl(), apkPath); 替换为
//绑定DownloadFileService
//Intent intent = new Intent("com.yifeng.chaoshibang.service.DOWNLOAD_APK_ACTION");
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
intent.putExtra("url", info.getUrl());
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
progressDialog.show();
这里需要注意,在DownloadFileService中是在onStartCommand()方法中启动线程去下载文件。根据Service的生命周期,bindService()方法不会调用onStartCommand(),所以还需使用startService()启动Service。
6.Service和BroadcastReceiver实现
public class DownloadFileService extends BaseService {
private String urlPath="";
//文件存储
private File updateFile = null;
private Intent mIntent = new Intent("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
public DownloadFileService() {
}
/**
* 返回一个Binder对象
*/
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
urlPath = intent.getStringExtra("url");
//创建文件
if(FileUtil.haveSDCard()) {
updateFile = FileUtil.getFile(Config.sd_folder_name, Config.sd_apk_name);
}
//开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞
new Thread(new DownloadRunnable()).start();
return super.onStartCommand(intent, flags, startId);
}
class DownloadRunnable implements Runnable {
@Override
public void run() {
HttpURLConnection httpURLConnection = null;
InputStream input = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlPath);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setConnectTimeout(2000);
httpURLConnection.setRequestMethod("GET");
if(httpURLConnection.getResponseCode() == 200) {
int total = httpURLConnection.getContentLength();
input = httpURLConnection.getInputStream();
fos = new FileOutputStream(updateFile);
byte[] buffer = new byte[1024];
int len;
int progress = 0;
while((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
progress += len;
mIntent.putExtra("progress", progress);
mIntent.putExtra("total", total);
sendBroadcast(mIntent);
}
fos.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(fos != null) {
fos.close();
}
if(input != null) {
input.close();
}
if(httpURLConnection != null) {
httpURLConnection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}onCreate()方法中注册广播接收器
//动态注册广播接收器
updateReceiver = new UpdateProgressReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.yifeng.chaoshibang.broadcast.UPDATE_APK");
registerReceiver(updateReceiver, intentFilter);
protected void onDestroy() {
Intent intent = new Intent(SplashActivity.this, DownloadFileService.class);
//停止服务
stopService(intent);
//注销广播
unregisterReceiver(updateReceiver);
super.onDestroy();
}
然后在确定下载按钮的监听事件响应中启动service
private void showUpdateDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(SplashActivity.this);
builder.setIcon(android.R.drawable.ic_dialog_info);
builder.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dir = new File(Environment.getExternalStorageDirectory(), "/chaoshibang/update");
if(!dir.exists()) {
dir.mkdirs();
}
String apkPath = Environment.getExternalStorageDirectory() + "/chaoshibang/update/new.apk";
//启动服务
Intent mIntent = new Intent(SplashActivity.this, DownloadFileService.class);
mIntent.putExtra("url", info.getUrl());
startService(mIntent);
progressDialog.show();
} else {
Toast.makeText(SplashActivity.this, "SD卡不可用,请插入SD卡", Toast.LENGTH_SHORT).show();
loadMainUI();
}
}
});
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
loadMainUI();
}
});
builder.create().show();
}
相关文章推荐
- 给你的Linux装一个"D盘"
- Android:在子线程中更新UI,解析异步消息处理机制(Handler)
- 20135305姚歌 20135310陈巧然 实验五:通讯协议设计
- IOS控件学习:UILabel常用属性与用法
- Java内功提升之封装
- Oracle 两个时间段是否重合 冲突
- POJ 1928 The Peanuts
- 响应式设计 @media
- Linux 中断之下半部机制
- perl 截取 fastq文件
- Nginx负载均衡配置说明
- php 读取文件自身内容,与读取文件输出内容
- 字符串批量替换工具,R资源id动态获取
- 实现鼠标移上去变样式
- linux下的程序调试工具gdb
- 7.数据结构之哈希表
- POJ 1338 Ugly Numbers
- Python基础——numpy.ndarray一维数组与多维数组
- \backend\models\core\Country
- http request和response的存储内容