app離線下載

前段時間作了一個離線下載的模塊,需求以下:html

一、後臺獨立進程運行,能夠脫離主程序運行
二、能夠暫停、繼續下載
三、能夠判斷網絡情況和SD卡
四、顯示下載進度
四、多個個任務在一個隊列中
五、定時下載
 
1、選擇離線下載的核心方法
 
後臺獨立運行,咱們很容易想到服務(Service),可是有如下幾種問題
(1)若是服務的進程和應用一致,那麼在應用退出後,服務會重啓一次
(2)若是服務的進程和應用不一致,進程間的通訊就會麻煩一點
(3)若是服務的進程和應用一致,選擇IntentService,能夠避免重啓問題
並且咱們不須要多個任務同時下載,用IntentService徹底能夠,並且IntentService還有其餘優點
 
2、下載管理
 
因爲用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" ) ;

 

//得到剛剛下載的文件的大小android

 

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 + "-" ) ;app

rdFile.seek ( mCurrentSize ) ;dom

 
(2)取消隊列中等待下載的任務
發現IntentService不能夠取消還未處理的Intent,看IntentService的源碼,發現只需略做修改就能夠了

//下面自定義一個能夠刪除intent的服務,只顯示新增的代碼和覆蓋的部分,其餘和IntentService同樣ide

 

 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 方法。
 
3、判斷網絡狀態和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 }

 

4、顯示下載進度
 
(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" ) ;ui

 

//在循環下載處理中,發送下載進度url

1 Bundle resultData = new Bundle () ;
2 
3 resultData.putString ( "progress", percent ) ;
4 
5 receiver.send ( UPDATE_PROGRESS, resultData ) ;

 

(2)在通知欄中,更新下載進度,利用 Notifications
 
5、定時下載
 
這個和鬧鐘的原理相相似,定義一個定時器和廣播接收器,利用 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 @Override
20 
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  

 

6、自啓動

 

爲了讓咱們的鬧鐘能夠在開機後自動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註冊此接收器:spa

 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>
相關文章
相關標籤/搜索