文件下載這種事情是很耗時(shí)的。之前使用AsyncTask這樣的異步類來(lái)做下載,然后切到后臺(tái)就被干掉。所以打算試試Service。(不過按目前那些系統(tǒng)的尿性,其實(shí)Service也分分鐘被干掉)
十載的華亭網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整華亭建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“華亭網(wǎng)站設(shè)計(jì)”,“華亭網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
不過,這里并不是直接使用Service類,而是使用的是繼承自Service的IntentService。
這個(gè)東西有三大好處:
1.他有個(gè)任務(wù)隊(duì)列;
2.任務(wù)隊(duì)列執(zhí)行完后會(huì)自動(dòng)停止;
3.他會(huì)起一個(gè)獨(dú)立的線程,耗時(shí)操作不會(huì)影響你app的主線程。
這么自動(dòng)化的東西簡(jiǎn)直省心。
話不多說,開始擼代碼。
首先,要建個(gè)應(yīng)用,主文件如下(布局什么的代碼就不貼了):
package net.codepig.servicedownloaderdemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity { private String _url="http://www.boosj.com/apk/boosjDance.apk"; private EditText urlText; private Button goBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); goBtn=(Button) findViewById(R.id.goBtn); urlText=(EditText) findViewById(R.id.urlText); urlText.setText(_url); goBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { _url=urlText.getText().toString(); //start download start_service(); } }); } public void start_service(){ //等會(huì)再填 } }
以上代碼不重要,嗯。
接下來(lái)是重點(diǎn)。創(chuàng)建一個(gè)IntentService 類,然后重寫他的onHandleIntent 。
需要執(zhí)行的任務(wù)就寫在onHandleIntent 里
這里先用Thread.sleep模擬一下耗時(shí)任務(wù),試跑一下就可以看到主app關(guān)閉后service還在跑,跑完后就自己Destroy了。
package net.codepig.servicedownloaderdemo; import android.app.IntentService; import android.content.Intent; /** * 下載服務(wù) * Created by QZD on 2017/9/20. */ public class DownLoadService extends IntentService { public DownLoadService() { super("DownLoadService");//這就是個(gè)name } @Override public void onCreate() { super.onCreate(); } protected void onHandleIntent(Intent intent) { Bundle bundle = intent.getExtras(); String downloadUrl = bundle.getString("download_url"); Log.d(TAG,"下載啟動(dòng):"+downloadUrl); Thread.sleep(1_000); int count=0; while(count<20){ count++; Log.d(TAG,"下載運(yùn)行中--"+count); Thread.sleep(1000); } Log.d(TAG,"下載結(jié)束"); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } }
通過Intent接收任務(wù),這里在MainActivity中通過startService啟動(dòng)服務(wù)
public void start_service(){ Intent intent=new Intent(this,DownLoadService.class); intent.putExtra("download_url",_url); startService(intent); }
當(dāng)然,AndroidManifest.xml里也得注冊(cè)上
接下來(lái)我們看看怎么下載文件
首先別忘了添加權(quán)限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
添加downloadFile方法管理下載。
下載相關(guān)說明都在注釋里。
/** * 文件下載 * @param downloadUrl * @param file */ private void downloadFile(String downloadUrl, File file){ FileOutputStream _outputStream;//文件輸出流 try { _outputStream = new FileOutputStream(file); } catch (FileNotFoundException e) { Log.e(TAG, "找不到目錄!"); e.printStackTrace(); return; } InputStream _inputStream = null;//文件輸入流 try { URL url = new URL(downloadUrl); HttpURLConnection _downLoadCon = (HttpURLConnection) url.openConnection(); _downLoadCon.setRequestMethod("GET"); fileLength = Integer.valueOf(_downLoadCon.getHeaderField("Content-Length"));//文件大小 _inputStream = _downLoadCon.getInputStream(); int respondCode = _downLoadCon.getResponseCode();//服務(wù)器返回的響應(yīng)碼 if (respondCode == 200) { byte[] buffer = new byte[1024*8];// 數(shù)據(jù)塊,等下把讀取到的數(shù)據(jù)儲(chǔ)存在這個(gè)數(shù)組,這個(gè)東西的大小看需要定,不要太小。 int len; while ((len = _inputStream.read(buffer)) != -1) { _outputStream.write(buffer, 0, len); downloadLength = downloadLength + len; Log.d(TAG, downloadLength + "/" + fileLength ); } } else { Log.d(TAG, "respondCode:" + respondCode); } } catch (Exception e) { e.printStackTrace(); } finally { try {//別忘了關(guān)閉流 if (_outputStream != null) { _outputStream.close(); } if (_inputStream != null) { _inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
放入onHandleIntent執(zhí)行:
protected void onHandleIntent(Intent intent) { try { Bundle bundle = intent.getExtras(); String downloadUrl = bundle.getString("download_url"); File dirs = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download");//文件保存地址 if (!dirs.exists()) {// 檢查文件夾是否存在,不存在則創(chuàng)建 dirs.mkdir(); } File file = new File(dirs, "boosj.apk");//輸出文件名 Log.d(TAG,"下載啟動(dòng):"+downloadUrl+" --to-- "+ file.getPath()); // 開始下載 downloadFile(downloadUrl, file); // 下載結(jié)束 Log.d(TAG,"下載結(jié)束"); } catch (Exception e) { e.printStackTrace(); } }
跑一下,嗯,默默的下載完了。
但是,作為一個(gè)負(fù)責(zé)的app,當(dāng)然要給用戶反饋,所以我們要顯示一下進(jìn)度。
我們用Notification來(lái)顯示進(jìn)度。(需要注意的是,如果有必要調(diào)用主UI線程來(lái)顯示進(jìn)度的話,要充分考慮到Service運(yùn)行過程中,你的app未必是一直活動(dòng)著的,可能早就destroy了。)(當(dāng)然用綁定來(lái)啟動(dòng)service的另說,那是另一種使用場(chǎng)景。)
下載前(也就是執(zhí)行downloadFile方法前)先創(chuàng)建并對(duì)通知進(jìn)行相關(guān)設(shè)置。
這里使用了NotificationCompat.Builder()這個(gè)方法。如果不考慮舊版本的兼容,可以使用Notification.Builder()方法。
private NotificationCompat.Builder builder; private NotificationManager manager; public void initNotification(){ builder = new NotificationCompat.Builder(this); builder.setSmallIcon(R.mipmap.ic_launcher).setContentTitle("下載文件").setContentText("下載中……");//圖標(biāo)、標(biāo)題、內(nèi)容這三個(gè)設(shè)置是必須要有的。 manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); }
然后使用NotificationManager.notify()方法將通知發(fā)送給系統(tǒng)。需要更新的話再次notify()給同一個(gè)ID的通知,如果該通知已存在則會(huì)更新,不存在就新建。
private int _notificationID= 1024;//嗯,這是一個(gè)十分紳士的ID manager.notify(_notificationID,builder.build());
為了顯示進(jìn)度,使用handler和Runnable來(lái)定時(shí)刷新,并通過setProgress方法顯示進(jìn)度條。
private Handler handler = new Handler(); private Runnable run = new Runnable() { public void run() { int _pec=(int) (downloadLength*100 / fileLength); builder.setContentText("下載中……"+_pec+"%"); builder.setProgress(100, _pec, false);//顯示進(jìn)度條,參數(shù)分別是最大值、當(dāng)前值、是否顯示具體進(jìn)度(false顯示具體進(jìn)度,true就只顯示一個(gè)滾動(dòng)色帶) manager.notify(_notificationID,builder.build()); handler.postDelayed(run, 1000); } };
完事了以后如果需要清除通知可以使用manager.cancelAll();或者manager.cancel(int );
完整代碼再來(lái)一遍
package net.codepig.servicedownloaderdemo; import android.app.IntentService; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.support.v4.app.NotificationCompat; import android.util.Log; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * 下載服務(wù) * Created by QZD on 2017/9/20. */ public class DownLoadService extends IntentService { private final String TAG="LOGCAT"; private int fileLength, downloadLength;//文件大小 private Handler handler = new Handler(); private NotificationCompat.Builder builder; private NotificationManager manager; private int _notificationID = 1024; public DownLoadService() { super("DownLoadService");//這就是個(gè)name } @Override public void onCreate() { super.onCreate(); } protected void onHandleIntent(Intent intent) { try { initNotification(); Bundle bundle = intent.getExtras(); String downloadUrl = bundle.getString("download_url"); File dirs = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Download");//文件保存地址 if (!dirs.exists()) {// 檢查文件夾是否存在,不存在則創(chuàng)建 dirs.mkdir(); } File file = new File(dirs, "boosj.apk");//輸出文件名 Log.d(TAG,"下載啟動(dòng):"+downloadUrl+" --to-- "+ file.getPath()); manager.notify(_notificationID,builder.build()); // 開始下載 downloadFile(downloadUrl, file); // 下載結(jié)束 builder.setProgress(0,0,false);//移除進(jìn)度條 builder.setContentText("下載結(jié)束"); manager.notify(_notificationID,builder.build()); // manager.cancelAll(); // manager.cancel(_notificationID); // 廣播下載完成事件,通過廣播調(diào)起對(duì)文件的處理。(就不多說了,在實(shí)際需要的地方接收廣播就好了。) Intent sendIntent = new Intent("downloadComplete"); sendIntent.putExtra("downloadFile", file.getPath()); sendBroadcast(sendIntent); Log.d(TAG,"下載結(jié)束"); } catch (Exception e) { e.printStackTrace(); } } /** * 文件下載 * @param downloadUrl * @param file */ private void downloadFile(String downloadUrl, File file){ FileOutputStream _outputStream;//文件輸出流 try { _outputStream = new FileOutputStream(file); } catch (FileNotFoundException e) { Log.e(TAG, "找不到目錄!"); e.printStackTrace(); return; } InputStream _inputStream = null;//文件輸入流 try { URL url = new URL(downloadUrl); HttpURLConnection _downLoadCon = (HttpURLConnection) url.openConnection(); _downLoadCon.setRequestMethod("GET"); fileLength = Integer.valueOf(_downLoadCon.getHeaderField("Content-Length"));//文件大小 _inputStream = _downLoadCon.getInputStream(); int respondCode = _downLoadCon.getResponseCode();//服務(wù)器返回的響應(yīng)碼 if (respondCode == 200) { handler.post(run);//更新下載進(jìn)度 byte[] buffer = new byte[1024*8];// 數(shù)據(jù)塊,等下把讀取到的數(shù)據(jù)儲(chǔ)存在這個(gè)數(shù)組,這個(gè)東西的大小看需要定,不要太小。 int len; while ((len = _inputStream.read(buffer)) != -1) { _outputStream.write(buffer, 0, len); downloadLength = downloadLength + len; // Log.d(TAG, downloadLength + "/" + fileLength ); } } else { Log.d(TAG, "respondCode:" + respondCode); } } catch (Exception e) { e.printStackTrace(); } finally { try {//別忘了關(guān)閉流 if (_outputStream != null) { _outputStream.close(); } if (_inputStream != null) { _inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } private Runnable run = new Runnable() { public void run() { int _pec=(int) (downloadLength*100 / fileLength); builder.setContentText("下載中……"+_pec+"%"); builder.setProgress(100, _pec, false);//顯示進(jìn)度條,參數(shù)分別是最大值、當(dāng)前值、是否顯示具體進(jìn)度(false顯示具體進(jìn)度,true就只顯示一個(gè)滾動(dòng)色帶) manager.notify(_notificationID,builder.build()); handler.postDelayed(run, 1000); } }; @Override public void onDestroy() { Log.d(TAG, "onDestroy"); handler.removeCallbacks(run); super.onDestroy(); } public void initNotification(){ builder = new NotificationCompat.Builder(this); builder.setSmallIcon(R.mipmap.ic_launcher).setContentTitle("下載文件").setContentText("下載中……");//圖標(biāo)、標(biāo)題、內(nèi)容這三個(gè)設(shè)置是必須要有的。 manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); } }
相關(guān)github項(xiàng)目地址:serviceDownloaderDemo
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)站欄目:Android基于IntentService的文件下載的示例代碼
地址分享:http://aaarwkj.com/article26/isjicg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、自適應(yīng)網(wǎng)站、網(wǎng)站營(yíng)銷、外貿(mào)建站、品牌網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)