有时候会有些业务需要后台运行并以通知的形式,比如升级,监控什么的。
这里说下我的业务,通过提示用户升级,然后点击升级开启一个service服务在
后台进行下载并以通知的形式提供用户查看,下载完成点击通知进入安装。
1.开启服务
Intent intent = new Intent(); intent.setClass(mContext, UpgradeService.class); startService(intent);
2.建立一个服务servive类
在onStart方法中建立notification,做写准备工作.
@Override
public void onStart(Intent intent, int startId) {
String sdPath = FileHelper.getSDCardPath();
if (sdPath != null) {
updateFile = new File(sdPath + Global.downloadDir + "petfone.apk");
// 初始化通知管理器
this.updateNotificationMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
this.updateNotification = new Notification();
updateNotification.icon=R.drawable.ic_launcher;
updateIntent = new Intent(this, UpdateAppDemoActivity.class);
updatePendingIntent = PendingIntent.getActivity(this, 0,updateIntent, 0);
//通知自定义视图
updateNotification.contentView = new RemoteViews(getPackageName(),com.hua.test.R.layout.mynotification_progressbar);
updateNotification.contentView.setProgressBar(com.hua.test.R.id.pb_notifi, 100, 0, false);
updateNotification.contentIntent = updatePendingIntent;//这个pengdingIntent很重要,必须要设置
// 发出通知
//updateNotificationMgr.notify(notificationId, updateNotification);
// 开启线程进行下载
new Thread(new updateThread()).start();
}
super.onStart(intent, startId);
}
3.开启一个线程来下载防止主线程堵塞。这里在servce写了一个内部类实现了Runnable
class updateThread implements Runnable {
Message msg = handler.obtainMessage();
@Override
public void run() {
try {
if (!updateFile.exists()) {
updateFile.createNewFile();
}
long downSize = downloadFile(Global.NET_ADDRESS+"PetFone_G_Google.apk",updateFile);
if(downSize>0){
//下载成功!
msg.what=DOWNLOAD_SUCCESS;
handler.sendMessage(msg);
}
} catch (Exception ex) {
ex.printStackTrace();//下载失败
msg.what=DOWNLOAD_FALL;
handler.sendMessage(msg);
}
}
}
/**
* 下载文件
* @param downloadUrl 下载路径
* @param saveFile 保存文件名
*/
public long downloadFile(String downloadUrl, File saveFile) throws Exception {
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;
HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try{
URL url = new URL(/blog_article/downloadUrl/index.html);
httpConnection = (HttpURLConnection)url.openConnection();
httpConnection.setRequestProperty("User-Agent", "PacificHttpClient");
if(currentSize > 0) {
httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-");
}
httpConnection.setConnectTimeout(10000);
httpConnection.setReadTimeout(20000);
updateTotalSize = httpConnection.getContentLength();//总大小
if(httpConnection.getResponseCode()==404){
throw new Exception("conection net 404!");
}
is = httpConnection.getInputStream();
fos = new FileOutputStream(saveFile);
byte[] buf = new byte[1024];
int readSize = -1;
while((readSize = is.read(buf)) != -1){
fos.write(buf, 0, readSize);
//通知更新进度
totalSize += readSize;
int tmp = (int) (totalSize * 100 / updateTotalSize);
//为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次
if(downloadCount == 0 || tmp-10>downloadCount){
downloadCount+=10;
Message msg = handler.obtainMessage();
msg.what=DOWNLOAD_COMPLETE;
msg.arg1=downloadCount;
handler.sendMessage(msg);
}
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(httpConnection != null) {
httpConnection.disconnect();
}
if(is != null) {
is.close();
}
if(fos != null) {
fos.close();
}
}
return totalSize;
}
4.需要不段的给progressBar 提供值,所以要使用handler,下载文件一定也就有3种状态,
1).下载中,2).下载失败,3).下载成功。
在servive中定义好handler并定义这个3个状态码。
private final int DOWNLOAD_COMPLETE = 1, DOWNLOAD_FALL=2,DOWNLOAD_SUCCESS=3;
然后在处理这个message
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case DOWNLOAD_SUCCESS:
//下载完成点击通知进入安装
Uri uri = Uri.fromFile(updateFile);
Intent installIntent = new Intent(Intent.ACTION_VIEW);
installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
updatePendingIntent = PendingIntent.getActivity(UpgradeService.this, 0, installIntent, 0);
updateNotification.defaults = Notification.DEFAULT_SOUND;//设置铃声
updateNotification.contentIntent = updatePendingIntent;
//更新通知视图值
updateNotification.contentView.setTextViewText(com.hua.test.R.id.tv_downInfo, "下载成功,点击安装。");
updateNotification.contentView.setProgressBar(com.hua.test.R.id.pb_notifi, 100, 100, false);
updateNotificationMgr.notify(notificationId, updateNotification);
stopService(updateIntent);//停止service
break;
case DOWNLOAD_COMPLETE://下载中状态
System.out.println(msg.arg1);
updateNotification.contentView.setProgressBar(com.hua.test.R.id.pb_notifi, 100, msg.arg1, false);
updateNotification.contentView.setTextViewText(R.id.tv_downInfo, "下载中"+msg.arg1+"%");
updateNotificationMgr.notify(notificationId, updateNotification);
break;
case DOWNLOAD_FALL://失败状态
//updateNotification.setLatestEventInfo(UpgradeService.this, "下载失败", "", updatePendingIntent);]
updateNotification.contentView.setTextViewText(com.hua.test.R.id.tv_downInfo, "下载失败");
updateNotificationMgr.notify(notificationId, updateNotification);
stopService(updateIntent);//停止service
break;
default:
stopService(updateIntent);
}
}
};
网络地址本为用户提供三种数据同步方式:
1.地址本备份(上传):用户通过点击手机终端上的“备份”菜单实现手机终端数据全量备份到服务器上,并且服务器上原来的所有地址本数据将被自动删除到回收站中,使得终端与服务器上的地址本数据保持一致;采用OMA SyncML DS 协议定义的“客户端刷新同步(Refresh Sync from Client Only)”方式实现。
2.地址本恢复(下载):用户通过点击手机终端上的“恢复”菜单实现手机终端数据全量备份到服务器上,并且服务器会对数据进行比对分析将服务器原来有而手机终端没有的地址本数据恢复到手机终端上,使得终端与服务器上的地址本数据保持一致;采用OMA SyncML DS 协议定义的“慢同步(Slow Sync)”方式实现。
3.地址本自动更新:用户对手机终端上的地址本数据进行增加、删除、修改操作后,手机终端自动将这些增、删、改地址本数据信息同步到服务器,服务器对这些数据进行分析后将更新服务器上相应地址本数据,并且把服务器上自上次与终端同步(包括地址本备份、恢复、自动更新)后增加、删除、修改的数据同步到手机上,使得终端与服务器上的地址本数据保持一致;采用OMA SyncML DS 协议定义的“双向同步(Two-Way Sync)”方式实现。
问题一:双向同步与慢同步的区别?
a.双向同步-客户端与服务器互相传递表中得更改内容,进行增量更改
b.慢同步-双向同步的一种方式,客户端和服务器都传输整个表的内容,并将收到的所有数据进行逐项比较,并对本地数据库进行增量更改。由于这种同步方式传输的数据量大,因此效率低下。
使用静态类库的好处:
加快编译速度。如果类文件多了,在编译的时候,特别是重新清除完Target之后,会特别慢。如果把某些不需要经常改动,但又很必须的类单独拿出来编译成静态类库,整个项目的编译速度将会大大提高。
方便代码共享。有些代码,不方便开源给别人,但又要提供给别人使用。比如,两个公司之间的合作。
制作静态类库:
为方便讲解,更方便与初期代码测试,新建一个项目,StaticLibraryExample
新建Target。 假设我们需要制作的静态类库名为 IMIBase. 右击Targets,添加新Target。选择Static Library, 名字为IMIBase
添加类文件到IMIBase。在新建文件选项中注意,添加到的Target是IMIBase,而不是默认的StaticLibraryExample。
随便写一个方法printAAA 打印字符串AAA。
测试。双击Target StaticLibraryExample,在General中添加直接依赖关系,选择IMIBase。这样做的目的是保证每次运行测试的时候都会编译 IMIBase。 完成后command+b 编译。我们会在Products智能文件夹发现2个产品,一个是StaticLibraryExample.app 另一个是libIMIBase.a 后者就是我们需要的静态类库了,默认前缀是lib 后缀是.a的文件。(需要注意的是.a文件会被svn默认忽略掉,请google svn配制)。将.a文件拖到Target StaticLibraryExample的Link Binary With Libraries文件夹。
在AppDelegate中使用我们刚才建的类。
#import "IMIBaseNSStringHelper.h"
[IMIBaseNSStringHelper printAAA ];
运行,恭喜,看到AAA在调试终端上打印出来了!
输出产品。现在.a文件已经就是我们需要的了,我们可以把这个文件拷贝出来用了。需要注意的是:1 头文件,也要拷贝出来。2 现在的类库只能在模拟器上用,我们还需要编译一遍为真机使用。