首页 > 代码库 > app离线下载
app离线下载
前段时间做了一个离线下载的模块,需求如下:
1、后台独立进程运行,可以脱离主程序运行
2、可以暂停、继续下载
3、可以判断网络状况和SD卡
4、显示下载进度
4、多个个任务在一个队列中
5、定时下载
一、选择离线下载的核心方法
后台独立运行,我们很容易想到服务(Service),但是有以下几种问题
(1)如果服务的进程和应用一致,那么在应用退出后,服务会重启一次
(2)如果服务的进程和应用不一致,进程间的通信就会麻烦一点
(3)如果服务的进程和应用一致,选择IntentService,可以避免重启问题
而且我们不需要多个任务同时下载,用IntentService完全可以,而且IntentService还有其他优势
参考这篇文章:Android中IntentService与Service的比较
二、下载管理
由于用IntentService,一个任务就是一个intent,服务处理一个Intent就是下载一个任务
(1)当前任务的暂停,可以设置一个下载状态的变量
1 public static final int CANCEL_STATE = 1 ; 2 3 private state int state ; 4 5 ... 6 7 //download 8 9 10 11 while ( ... ) {12 13 ...14 15 if ( state == CANCEL_STATE ) {16 17 break ;18 19 }20 21 }
暂停就相当于取消了当前任务,服务去处理下一个intent。
如果要继续这个任务,就要重新发送一个Intent,为了可以从刚刚下载的地方接着下载,我们要坐下处理:
1 File file = new File ( path ) ;2 3 file.getParentFile().mkdirs () ;4 5 RandomAccessFile rdFile = new RandomAccessFile ( file, "rwd" ) ;
//获得刚刚下载的文件的大小
1 int mCurrentSize = ( int ) rdFile.length () ;2 3 HttpURLConnection conn = ( HttpURLConnection ) new URL ( url ).openConnection () ;4 5 conn.setConnectTimeout ( 5000 ) ;6 7 conn.setRequestMethod ( "get" ) ;
//从mCurrentSize后开始下载
conn.setRequestProperty ( "Range", "bytes=" + mCurrentSize + "-" ) ;
rdFile.seek ( mCurrentSize ) ;
发现IntentService不可以取消还未处理的Intent,看IntentService的源码,发现只需略作修改就可以了
//下面自定义一个可以删除intent的服务,只显示新增的代码和覆盖的部分,其他和IntentService一样
1 public abstract class BaseIntentService extends Service { 2 3 private final int MESSAGE_TYPE = 12 ; //消息类型 4 5 6 7 @Override 8 9 public void onStart ( Intent intent, int startId ) {10 11 Message msg = mServiceHandler.obtainMessage () ;12 13 msg.arg1 = startId ;14 15 msg.obj = intent ;16 17 msg.what = MESSAGE_TYPE ;18 19 mServiceHandler.sendMessage ( msg ) ;20 21 }22 23 24 25 protected boolean hasIntent ( Intent intent ) {26 27 return mServiceHandler.hasMessages ( MESSAGE_TYPE, intent ) ;28 29 }30 31 32 33 protected void removeIntent ( Intent intent ) {34 35 if ( mServiceHandler.hasMessages ( MESSAGE_TYPE, intent ) ) {36 37 mServiceHandler.removeMessages ( MESSAGE_TYPE, intent ) ;38 39 }40 41 }42 43 44 45 protected void removeAllIntent () {46 47 mServiceHandler.removeMessages ( MESSAGE_TYPE ) ;48 49 }50 51 }
这边还有另外一个需要注意的地方:在测试中发现删除不了,后来才知道是个低级错误,默认Intent的equals方法是判断两个引用是否指向一个对象,所以我们要重载Intent的 hashCode 和 equals 方法。
三、判断网络状态和SD卡
获得当前的网络状态,如果不是wifi就停止下载,如果SD卡没有挂载,也停止下载
1 public class NetworkUtils { 2 3 public static boolean existWifi ( Context context ) { 4 5 ConnectivityManager connManager = ( ConnectivityManager ) context.getSystemService ( Context.CONNECTIVITY_SERVICE ) ; 6 7 NetworkInfo info = connManager.getActiveNetworkInfo () ; 8 9 return ( null != info && ConnectivityManager.TYPE_WIFI == info.getType () ) ;10 11 }12 13 }
1 public class SDUtils { 2 3 public static boolean existSDCard () { 4 5 return ( android.os.Environment.getExternalStorageStage(). 6 7 equals( android.os.Environment.MEDIA_MOUNTED ) ) ; 8 9 }10 11 }
四、显示下载进度
(1)应用程序中显示下载进度,利用ResultReceiver
1 public class MainActivity extends Activity { 2 3 ... 4 5 6 7 public void startDownload () { 8 9 Intent intent = new ...10 11 intent.putExtra ( "receiver", new DownloadReceiver() ) ;12 13 ...14 15 startService ( intent ) ;16 17 }18 19 20 21 public class DownloadReceiver extends ResultReceiver {22 23 ...24 25 }26 27 28 29 }
//在IntentService中的onHandleIntent中,获得ResultReceiver
ResultReceiver receiver = intent.getParcelableExtra ( "receiver" ) ;
//在循环下载处理中,发送下载进度
1 Bundle resultData = http://www.mamicode.com/new Bundle () ;2 3 resultData.putString ( "progress", percent ) ;4 5 receiver.send ( UPDATE_PROGRESS, resultData ) ;
(2)在通知栏中,更新下载进度,利用Notifications
五、定时下载
这个和闹钟的原理相类似,定义一个定时器和广播接收器,利用AlarmManager
1 public static void startAlarm ( Context context, long time ) { 2 3 AlarmManager am = (AlarmManager) context.getSystemService ( Context.ALARM_SERVICE ) ; 4 5 Intent intent = new Intent ( context, AlarmReceiver.class ) ; 6 7 PendingIntent pIntent = PendingIntent.getBroadcast ( context, 0, intent, 0 ) ; 8 9 am.cancel ( pIntent ) ;10 11 am.setRepeating ( AlarmManager.RTC_WAKEUP, time, AlarmManager.INTERVAL_DAY, pIntent ) ;12 13 }14 15 16 17 public class AlarmReceiver extends BroadcastReceiver {18 19 @Override20 21 public void onReceive ( Context context, Intent intent ) {22 23 //启动下载服务24 25 。。。26 27 }28 29 }
我们在下载的时候可以唤醒手机,下载后可以回到休眠状态,利用PowerManager
1 public class WakeLockUtils { 2 3 public static WakeLock wl ; 4 5 public static String tag ; // 服务的包名 6 7 8 9 public static void acquirePratialWakeLock ( Context context ) {10 11 if ( null != wl ) return ;12 13 PowerManager pm = ( PoweerManager ) ( context.getSystemService ( Context.POWER_SERVICE ) ) ;14 15 wl = pm.newWakeLock ( PowerManager.PARTIAL_WAKE_LOCK, tag ) ;16 17 wl.acquire () ;18 19 }20 21 22 23 public static void releaseWakeLock () {24 25 if ( null != wl && wl.isHeld () ) {26 27 wl.release () ;28 29 wl = null ;30 31 }32 33 }34 35 }36 37
六、自启动
为了让我们的闹钟可以在开机后自动startAlarm
1 public AutoRunReceiver extends BroadcastReceiver { 2 3 public void onReceive ( Context context, Intent intent ) { 4 5 //启动定时器 6 7 8 9 。。。startAlram () ;10 11 }12 13 }
在AndroidManifest.xml注册此接收器:
1 <receiver android:name="包名"> 2 3 <intent-filter> 4 5 <action android:name="android.intent.action.BOOT_COMPLETED"/> 6 7 <category android:name="android.intent.category.HOME"/> 8 9 </intent-filter>10 11 </receiver>
app离线下载
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。