文件下載這種事情是很耗時(shí)的。之前使用AsyncTask這樣的異步類來(lái)做下載,然后切到后臺(tái)就被干掉。所以打算試試Service。(不過(guò)按目前那些系統(tǒng)的尿性,其實(shí)Service也分分鐘被干掉)
不過(guò),這里并不是直接使用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)直省心。
話不多說(shuō),開(kāi)始擼代碼。
首先,要建個(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();  }}通過(guò)Intent接收任務(wù),這里在MainActivity中通過(guò)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)說(shuō)明都在注釋里。
  /**   * 文件下載   * @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());      // 開(kāi)始下載      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)行過(guò)程中,你的app未必是一直活動(dòng)著的,可能早就destroy了。)(當(dāng)然用綁定來(lái)啟動(dòng)service的另說(shuō),那是另一種使用場(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è)十分紳士的IDmanager.notify(_notificationID,builder.build());
為了顯示進(jìn)度,使用handler和Runnable來(lái)定時(shí)刷新,并通過(guò)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());      // 開(kāi)始下載      downloadFile(downloadUrl, file);      // 下載結(jié)束      builder.setProgress(0,0,false);//移除進(jìn)度條      builder.setContentText("下載結(jié)束");      manager.notify(_notificationID,builder.build());//      manager.cancelAll();//      manager.cancel(_notificationID);      // 廣播下載完成事件,通過(guò)廣播調(diào)起對(duì)文件的處理。(就不多說(shuō)了,在實(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í)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注