- 浏览: 238149 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
xchd:
分别在什么时候(情况下)用ThreadFactory、Exec ...
Executor线程池实例 -
mikey_5:
是不是没有写完啊
Executor线程池实例 -
xinyao:
楼主,你好,请问能给我发个源码吗,我要在一个页面能实时看到下载 ...
Android学习系列(19)--App离线下载 -
sdtzkj:
...
jasperReport 帮助文档 api -
shero_ys:
public class VrowsePicActivity ...
android handler 实现三步曲
Android学习系列(19)--App离线下载
- 博客分类:
- android
Android学习系列(19)--App离线下载
宜未雨而绸缪,毋临渴而掘井。----朱用纯《治家格言》
离线下载,在有网络的情况下下载服务器数据,以便无网络时也能阅读,就是离线阅读。
离线下载的功能点如下:
1.下载管理(开始、取消下载)。
2.网络判断(Wi-Fi,3G)。
3.独立进程。
4.定时和手机催醒。
5.自启动。
1.下载管理
这里不便关注下载的细节方法,网络下载的方法很多,大概如下:
/** * 下载文件 * @param url 下载地址 * @param dest 下载存放的本地文件 * @param append 断点续传 * @return * @throws Exception */ public long download(String url, File dest, boolean append) throws Exception{ //初始化变量 //准备工作 // ... ... try { // ... ... while((readSize = is.read(buffer)) > 0){ //网络判断 os.write(buffer, 0, readSize); os.flush(); //如果需要停止下载,如取消,跳出当前下载 } } } finally { // ... ... } // ... ... }
这里要注意几点:
(1).在下载的时候,我们希望能及时检测到网络状况,比如由Wi-Fi切换到3G网络下,我们应该能及时停止下载。
(2).当用户选择取消下载的时候,我们也能停止当前下载。
2.网络判断
获取当前网络状态,主要分为Wi-Fi和Mobile(包括3G,GPRS)两种,我们写一个工具类如下:
public class NetworkUtils { public final static int NONE = 0;//无网络 public final static int WIFI = 1;//Wi-Fi public final static int MOBILE = 2;//3G,GPRS /** * 获取当前网络状态 * @param context * @return */ public static int getNetworkState(Context context){ ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); //手机网络判断 State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState(); if(state == State.CONNECTED||state == State.CONNECTING){ return MOBILE; } //Wifi网络判断 state = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState(); if(state == State.CONNECTED||state == State.CONNECTING){ return WIFI; } return NONE; } }
根据网络状态,我们能够控制下载方式:
(1).下载量很大的情况下,我们不大可能在3G情况下进行下载,容易引起用户的反感和担忧。
(2).当客户十分确认可以在3G情况下进行下载,那么也是允许的。
所以,这里提出一个需求,我们要为下载方式设置一个灵活的等级,结合离线下载的特点,我们给出3中方案由用户选择:
(1).移动数据情况下自动下载
(2).只允许Wi-Fi情况下自动下载
(3).关闭下载
这里只列出了自动下载,是因为如果不是自动下载,手动下载用户可以随意控制,无需设置,当然设计到丢流量情况下,如3G下手动下载,提示用户会消耗较大的数据流量,慎用即可。
public class Constant { //离线下载网络设置 public final static int OFFLINE_MOBILE = 0; public final static int OFFLINE_WIFI = 1; public final static int OFFLINE_OFF = 3; } public class Global { //设置默认关闭状态, //为了应用程序下次启动能够记住用户选择,在第一次启动应用的时候,这个值最终应该存放到数据库中, public static int OfflineNetworkSetting = Constant.OFFLINE_OFF; }
现在可以根据规则比较当前网络和离线网络设置,判定离线下载服务的开启。
3.独立进程
离线下载,无论何时何地,只要适宜进行,则当进行,目前主流的做法是建立后台服务。
public class OfflineSerivice extends Service { // ... ... }
(1).OfflineService的进程如果默认和应用程序一致,则在应用进程kill的时候,会重启一次(网易新闻在离线下载的时候,退出应用,下载会停顿一小会儿就是这个原因),如果影响不大,这个方案也是可选的。
(2).OfflineService的进程和应用程序分开,如应用程序进程为"cn.cnblogs.tianxia.download",则离线下载服务的进程设置为"cn.cnblogs.tianxia.download.offline",撇清和应用程序的进程的关系。当然,这个会带来一个新的问题,进程间通信,当然因为离线下载和应用程序间的模块比较独立,这个问题还算比较好规避。
(3).OfflineService的进程如果默认和应用程序一致,但是OfflineService继承IntentService,可避免重启的问题,这个是《Pro Android 3》书中提到的方法,非常的好用,但是非常遗憾,本人最近才看到,暂时没有亲手测验,不敢在工作中试用。
按理说,方案3是最佳方案, 但是个人原因,选择了方案2.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cnblogs.download"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <!--省略其他--> <service android:name="cn.cnblogs.download.OfflineService" android:process="cn.cnblogs.download.offline"/> </application> </manifest>
4.定时下载和手机催醒
根据用户设置,在wifi的情况下自动下载,但是自动下载的方案有很多种,频繁的更新下载,定点下载(早上8点,下午4点),间隔下载(每隔6小时)。
这里,我们选择每隔6个小时下载。
(1).这里介绍一种错误的方案。一看到每隔6小时,很容易想到开启一个子线程计时,累计到6个小时,子线程通知下载服务开始新一轮下载。这个方案的思路是没有错的,但是却忽略了手机处于休眠状态,这个子线程其实是停止执行的,那么所谓的6个小时的效果就又可能永远达不到,而且必然不正确或者不准确。
(2).所以,需要使用到一种不休眠的办法:定时器和广播接收器。每隔6小时我们发送一个广播,广播接收器通知开始离线下载。(可参考newsrob源码和书籍《Pro Android 3》):
public class OfflineSerivice extends Service { //上次成功下载的时间 private long lastDownloadTime; // 省略代码... ... public static void startAlarm(Context context){ AlarmManager alarmManager = (AlarmManager) context.getSystemService("alarm"); //每隔6个小时发送广播到OfflineAlarmReceiver //也可以设置为10分钟检测一下下载条件,而在OfflineAlarmRecrive中判断开始下载,避免6小时下载失败需再等待6小时过长时间的问题 Intent intent = new Intent(context,OfflineAlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, intent, 0); alarmManager.cancel(pendingIntent); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(), 3600000*6, pendingIntent); } }
OfflineAlarmRecriver中处理开始下载条件,并通知开始下载:
public class OfflineAlarmReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent arg1) { // 省略代码...,初始化变量,准备工作... if(System.currentTimeMillis()-OfflineService.lastDownloadTime>3600000*60&&其他条件){ //打开离线下载服务 Intent alarmIntent = new Intent(context, OfflineService.class); context.startService(alarmIntent); } } }
前面我们提到了线程休眠的问题,需要在下载的时候能够唤醒手机,下载完成后能回到休眠状态,下面是两个工具方法:
public static PowerManager.WakeLock wakeLock; /** * 唤醒服务 */ public static void acquireWakeLock(Context context){ if(wakeLock!=null){ return; } PowerManager powerManager = (PowerManager)(context.getSystemService(Context.POWER_SERVICE)); wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "com.cnblogs.download.OfflineService"); wakeLock.acquire(); } /** * 释放唤醒服务,返回休眠状态 */ public static void releaseWakeLock(){ if(wakeLock!=null&&wakeLock.isHeld()){ wakeLock.release(); wakeLock = null; } }
其中PowerManager.PARTIAL_WAKE_LOCK意思是仅唤醒CPU方式,此时能自动主动检测网络状态,从而保证网络正常。
需要在Mainifest.xml中设置权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />然后在下载服务的onStartConmmand()激活催醒状态,然后在下载完成后释放催醒状态:
@Override public int onStartCommand(Intent intent, int flags, int startId) { acquireWakeLock(OfflineService.this); //省略代码... ... return super.onStartCommand(intent, flags, startId); }
5.自启动
为了代码清晰,我们再定义一个自启动的receiver:
/** * 自启动离线下载服务 * @author user */ public class OfflineReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent arg1) { //启动定时器 OfflineService.startAlarm(context); } }
在AndroidManifest.xml注册此接收器,如下:
<receiver android:name="cn.cnblogs.download.OfflineReceiver"> <intent-filter> <!--自启动--> <action android:name="android.intent.action.BOOT_COMPLETED" /> <category android:name="android.intent.category.HOME" /> </intent-filter> </receiver>
这样,在启动的时候,能够接受启动广播,并执行启动定时器操作。
6.小结
为了简洁明晰,开门见山,本文仅针对离线下载的最重要的关联点列举说明,而对于清理策略,手动和自动模式,界面跳转,UI设计和业务要求没有过多的涉及,但是往往这些东西才是花费你大量的时间,需要大量细节的积累和耐心的调试,我们唯一要做的事情就是不断的完善!
发表评论
-
Android学习系列(20)-App数据格式之解析Json
2011-08-13 11:28 1600JSON数据格式,在Android中被广泛运用于客户端和网络( ... -
Android学习系列(1)--为App签名(为apk签名)
2011-08-13 11:20 1678写博客是一种快乐,前提是你有所写,与人分享,是另一种快乐, ... -
Android学习系列(4)--App自适应draw9patch不失真背景
2011-08-13 11:16 2207做人要大度,海纳百川,做事要圆滑,左右逢源,这让我想到了编程也 ... -
Android自定义View之一:初探实例 .
2011-08-13 11:09 1482Android自定义View实现很简单 继承View,重写构 ... -
Android多媒体学:播放网络上的视频 .
2011-08-13 11:05 2065Android支持播放网络上的视频。在播放网络上的视频时,牵涉 ... -
Android多媒体学:利用AudioRecord类实现自己的音频录制程序 .
2011-08-13 11:02 5871AudioRecord类相对于MediaRecorder来说, ... -
Android多媒体:实现图像的编辑和合成 .
2011-08-13 10:59 2162package demo.camera; import ja ... -
自动完成框
2011-05-03 13:44 739请下载源码 -
读取sd卡照片
2011-05-03 13:43 1303请下载源码 -
UC菜单栏布局
2011-05-03 13:41 1122请下载附件 -
Executor线程池实例
2011-04-06 17:42 6675Executor 是 java5 下的一个 ... -
android handler 实现三步曲
2011-04-06 16:59 1433一. 要实现接口: public class VrowseP ... -
android 横竖屏切换
2011-03-25 14:33 1931①不理会。。②只竖屏 ... -
android 分辨率调试
2011-03-25 13:36 1866一:不同的layout Android ... -
android 图片内存溢出
2011-03-21 18:24 3084我的代码如下 is = new FileI ... -
android Exid 不可修改
2011-03-21 13:47 1258Android:只读EditText内容可滚动(禁止输入法)的 ... -
android 对话提示框大全
2011-03-21 12:34 3188Android 对话框(Dialog)大全 建立你自己的对话框 ... -
Android消息提示框和对话框
2011-03-21 12:29 1360在某些情况下需要向用户弹出提示消息,如显示错误信息,收到短消息 ... -
android tab 用法
2011-03-11 15:10 1747TabHost广泛运用于android程序中,在程序中运用Ta ... -
Android Intent 用法汇总
2011-03-08 18:17 1119显示网页 1. Uri uri = Uri.parse( ...
相关推荐
6. **使用mui打包成app**:mui是一个轻量级的前端框架,适用于快速构建移动应用。将上述HTML和JavaScript整合到mui项目中,根据mui的文档指导进行配置,如设置页面路由、启动页等,然后使用mui的打包工具将Web应用...
- **安装工具**:可以使用Android SDK Manager在线或离线安装Android SDK。 **知识点11:Android开发语言** - **语言**:开发Android应用程序时,主要使用的编程语言是Java。 **知识点12:错误日志分析** - **示例...
5. 离线地图:支持下载地图到本地,便于无网络环境使用。 6. 导出与分享:允许用户将制作的地图导出为不同格式,或者通过社交平台分享。 7. 同步功能:可能支持云同步,方便在多设备间同步数据。 8. 数据导入:能...
在Android开发中,WebView是一个非常重要的组件,它允许我们在应用程序中内嵌网页并与网页进行交互。这个"安卓浏览器WebViewJSHTML5相关-Android调用JavaScript.rar"的压缩包文件,很显然,聚焦于Android如何利用...
为了实现这一目标,了解并掌握一系列关键的诀窍至关重要。以下就是从"打造高质量Android应用 Android开发必知的50个诀窍"中提炼出的一些核心知识点: 1. **性能优化**:包括对内存管理的理解,避免内存泄漏,合理...
基于清华紫光证照(二代身份证正反面、驾驶证、车辆行驶证)识别库的单机版、Android APP代码。 开发环境:eclipse(Kepler),jdk 1.6,32位, 最小api level为8,最大为19(可调整)。免责申明:仅供学习、研究用,...
在Xamarin.Android开发中,集成地图功能是一项常见的需求。Xamarin是一个强大的跨平台移动开发工具,它允许开发者使用C#语言来构建原生的iOS、Android和Windows应用程序。本示例"Xamarin.Android 一个简单的地图Demo...
17. **数据库操作**:SQLite是Android内置的轻型数据库,可以用于缓存部分数据,如离线查看的微博。 18. **单元测试与自动化测试**:使用JUnit和Mockito等工具进行应用的功能测试,确保代码质量。 19. **性能优化*...
19.Android Holo Colors Generator 通过自定义Holo主题颜色生成对应的Drawable和布局文件 20.dagger-intellij-plugin dagger可视化辅助工具 21.GradleDependenciesHelperPlugin maven gradle 依赖支持自动...
介绍了Google Play Store的发布过程,以及如何通过ASO(App Store Optimization)提升游戏的可见性和下载量。 综上所述,这份源代码包提供了从游戏性能优化到商业变现的全方位学习资源,对于想要深入Android游戏...
16. **Android App Bundle**:使用App Bundle发布应用,通过Google Play动态分发,降低应用大小。 17. **国际化与本地化**:实现应用的多语言支持,适应全球市场。 18. **推送通知与消息中心**:集成Firebase ...
HybridApp 一种可以下载的Native App,其用户界面的全部或者部分元素在嵌入式浏览器组件(WebView之类的)里面运行 优雅降级 一开始就构建站点的完整功能,然后针对浏览器测试和修复。认为应该针对那些最高级、最...
#### 19. 跑马灯效果的TextView - **MarqueeTextView**:利用TextView的marquee属性实现滚动文本效果。 #### 20. 图片异步加载方法 - **第三方库**:Glide、Picasso等。 - **自定义Loader**:使用AsyncTask或...
- 在App Store搜索Microsoft,选择需要的应用(如Excel)进行下载安装。 - 安装完成后,打开应用并登录Office365账户。 综上所述,Office365解决方案为远程办公提供了一套全面、灵活且高效的工具集,不仅满足了...
本文将详细介绍如何使用Python脚本来控制Android设备,并提供了一系列常用的ADB命令。 ##### 1. 关闭ADB服务 ```sh adb kill-server ``` 此命令用于终止当前运行的ADB守护进程。当遇到ADB异常或需要重新启动ADB服务...
10. **网站创建教程**:通过系列教程,学习如何利用jQuery Mobile构建功能丰富的移动网站。 11. **jQuery Mobile应用构建**:深入理解特性,逐步构建应用首页,掌握开发流程。 12. **主题定制**:jQuery Mobile...
1. Ionic框架: Ionic是一个基于AngularJS的开源前端框架,用于开发跨平台的移动应用,支持iOS、Android等主流操作系统。通过HTML、CSS和JavaScript编写,可以利用ionic提供的丰富的UI组件和工具,快速构建美观、功能...
12. **Web与App测试区别**:Web测试主要关注浏览器兼容性和网络稳定性,App测试涉及设备特性、离线功能和内存管理。 13. **Android与iOS测试区别**:主要在于系统差异、设备硬件差异和用户界面交互方式。 14. **...