- 浏览: 232625 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
xchd:
分别在什么时候(情况下)用ThreadFactory、Exec ...
Executor线程池实例 -
mikey_5:
是不是没有写完啊
Executor线程池实例 -
xinyao:
楼主,你好,请问能给我发个源码吗,我要在一个页面能实时看到下载 ...
Android学习系列(19)--App离线下载 -
sdtzkj:
...
jasperReport 帮助文档 api -
shero_ys:
public class VrowsePicActivity ...
android handler 实现三步曲
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 1548JSON数据格式,在Android中被广泛运用于客户端和网络( ... -
Android学习系列(1)--为App签名(为apk签名)
2011-08-13 11:20 1622写博客是一种快乐,前提是你有所写,与人分享,是另一种快乐, ... -
Android学习系列(4)--App自适应draw9patch不失真背景
2011-08-13 11:16 2178做人要大度,海纳百川,做事要圆滑,左右逢源,这让我想到了编程也 ... -
Android自定义View之一:初探实例 .
2011-08-13 11:09 1428Android自定义View实现很简单 继承View,重写构 ... -
Android多媒体学:播放网络上的视频 .
2011-08-13 11:05 2028Android支持播放网络上的视频。在播放网络上的视频时,牵涉 ... -
Android多媒体学:利用AudioRecord类实现自己的音频录制程序 .
2011-08-13 11:02 5806AudioRecord类相对于MediaRecorder来说, ... -
Android多媒体:实现图像的编辑和合成 .
2011-08-13 10:59 2121package demo.camera; import ja ... -
自动完成框
2011-05-03 13:44 708请下载源码 -
读取sd卡照片
2011-05-03 13:43 1249请下载源码 -
UC菜单栏布局
2011-05-03 13:41 1091请下载附件 -
Executor线程池实例
2011-04-06 17:42 6610Executor 是 java5 下的一个 ... -
android handler 实现三步曲
2011-04-06 16:59 1385一. 要实现接口: public class VrowseP ... -
android 横竖屏切换
2011-03-25 14:33 1896①不理会。。②只竖屏 ... -
android 分辨率调试
2011-03-25 13:36 1834一:不同的layout Android ... -
android 图片内存溢出
2011-03-21 18:24 3046我的代码如下 is = new FileI ... -
android Exid 不可修改
2011-03-21 13:47 1216Android:只读EditText内容可滚动(禁止输入法)的 ... -
android 对话提示框大全
2011-03-21 12:34 3136Android 对话框(Dialog)大全 建立你自己的对话框 ... -
Android消息提示框和对话框
2011-03-21 12:29 1322在某些情况下需要向用户弹出提示消息,如显示错误信息,收到短消息 ... -
android tab 用法
2011-03-11 15:10 1693TabHost广泛运用于android程序中,在程序中运用Ta ... -
Android Intent 用法汇总
2011-03-08 18:17 1070显示网页 1. Uri uri = Uri.parse( ...
相关推荐
uni-app项目本地离线android打包步骤 uni-app很好,但按照官方的android离线打包指导并不容易很顺利完成离线打包 结合官方文档,经过反复试验、百度总算打包成功 为此特整理成word,按自己认为合适的方式把打包步骤...
uniapp 不提供旧版离线 APP sdk , 满足旧项目需求, 仅供下载
dlib-android-app See http://dlib.net for the main project documentation. See dlib-android for JNI lib. Refer to dlib-android/jni/jnilib_ex Grap the source $ git clone ...
npm install -g create-react-app-offline用法很简单,就像喝水一样crao -n < app> 例如 :crao -n my-app 它将在当前文件夹中创建一个名为my-app的目录。 在该目录内,它将生成初始项目结构并安装可传递依赖项: my...
Android Payments Support both Google Play and Amazon Kindle Fire in-app purchase payments with a single API Handy for small apps with in-app purchase (IAP) items that need both Google Play store and ...
Android-create-android-kotlin-app.zip,使用一行命令创建android kotlin应用程序。,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。
android-gradle-kotlin-app-template, Gradle Android Studio Robolectric Espresso JaCoCo Android Gradle Kotlin应用模板 Gradle Android Studio Robolectric Espresso JaCoCo使用的技术:构建工具:名称描述Grad
Book Dash is an Android App for the NPO where you can download books in different languages for free. Screenshots What does this app do? It is an open source Android application that allows ...
wallabag - Android App wallabag is a self-hosted read-it-later app. Unlike other services, wallabag is free and open source. wallabag for Android is a companion app for wallabag. wallabag is ...
https://nativesupport.dcloud.net.cn/NativePlugin/course/android uni-app原生插件开发需要的App离线SDK,官网的资源网盘下载,太慢了~~
Android-Just-Another-Android-App.zip,一个android基础应用程序,包含大量的酷库/配置,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。
Android基础教程之---AppWidget讲解2
1.前端开发离不开Chrome的开发者工具,尤其是调试Android WebView时。然而,如果使用chrome://Inspect的方法,国内的开发者会惊奇地发现“空白啊”!为此,我发布过这个离线包的解决方案!可以无需FanQ就能调试了。 ...
android-app-bootstrap A starting tutorial for Android application. native-in-practice Output npmcdn.com: android_app_bootstrap-debug.apk License The MIT License (MIT) Copyright (c) 2015 xdf
Android源码——oschina-android-app(开源中国).zip
由于官网不提供旧版离线 APP sdk , 为了满足旧项目需求, 仅供参考下载使用 为了项目的运行最好升级SDK同时升级HBuilder
uni-app离线打包的全过程,遇到问题、需要的版本号等
android oschina-android-app源码.rar
Android oschina-android-app(开源中国).zip
安卓Android源码——oschina-android-app(开源中国).zip