欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android Service服務(wù)詳細(xì)介紹及使用總結(jié)

 更新時(shí)間:2016年12月02日 10:59:17   作者:崢嶸life  
這篇文章主要介紹了Android Service 服務(wù)的詳細(xì)資料,網(wǎng)上關(guān)于Android Service 服務(wù)的文章比較多,但是不是很全面,不夠細(xì)致,畢竟是Android 四大組件之一,重要性不用說(shuō),這里總結(jié)下,需要的朋友可以參考下

Android Service服務(wù)詳解

一.Service簡(jiǎn)介

       Service是android 系統(tǒng)中的四大組件之一(Activity、Service、BroadcastReceiver、 ContentProvider),它跟Activity的級(jí)別差不多,但不能頁(yè)面顯示只能后臺(tái)運(yùn)行,并且可以和其他組件進(jìn)行交互。service可以在很多場(chǎng)合的應(yīng)用中使用,比如播放多媒體的時(shí)候用戶(hù)啟動(dòng)了其他Activity這個(gè)時(shí)候程序要在后臺(tái)繼續(xù)播放,比如檢測(cè)SD卡上文件的變化,再或者在后臺(tái)記錄你地理信息位置的改變等等,總之服務(wù)總是藏在后臺(tái)的,例如,一個(gè)service可能處理網(wǎng)絡(luò) 事物,播放音樂(lè),執(zhí)行文件I/O,或與一個(gè)內(nèi)容提供者交互,所有這些都在后臺(tái)進(jìn)行。
       我們一定要知道的是這里Service的后臺(tái)運(yùn)行并不是子線程。Service的運(yùn)行是在主線程中進(jìn)行的,只是它沒(méi)有界面顯示而已,它的耗時(shí)操作同樣需要開(kāi)啟子線程,否者會(huì)跟Activity一樣出現(xiàn)ANR(application not response–程序沒(méi)有響應(yīng))。
       我們要知道的是主線程的內(nèi)容包括UI和后臺(tái)。只要程序中的UI或后臺(tái)其中一個(gè)在跑,程序都算是在運(yùn)行狀態(tài)。

(一)Service的創(chuàng)建和注冊(cè)1.Service服務(wù)的創(chuàng)建

必須要實(shí)現(xiàn)重寫(xiě)其中的onBind方法,可以在里面做各種操作,也可以接收傳遞過(guò)來(lái)的Intent的數(shù)據(jù)做處理。

public class MyService extends Service {
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    System.out.println("MyService.onBind");
    return null;
  }
 }

2.Service服務(wù)的注冊(cè),在AndroidManifest中注冊(cè)

<service android:name=".MyService" />

       服務(wù)的注冊(cè)是四大組件中最簡(jiǎn)單的一個(gè),一般只要設(shè)置name屬性就可以了。但是如果有其他需求還是要設(shè)置其他的屬性值的。

       對(duì)Service服務(wù)做好創(chuàng)建和注冊(cè)后,就可以操作服務(wù)了。

(二)Service兩種啟動(dòng)模式

Service的啟動(dòng)有兩種方式:Context.startService() 和 Context.bindService()。這里的Context是上下文的意思。

1.startService()方式啟動(dòng)時(shí)的生命周期回調(diào)方法

(1)啟動(dòng)服務(wù)startService : –>onCreate()–> onStart()
(2)停止服務(wù)stopService : –>onDestroy()
       如果調(diào)用者直接退出而沒(méi)有停止Service,則Service 會(huì)一直在后臺(tái)運(yùn)行。這里的退走只是關(guān)閉了UI界面。
       startService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate()方 法,接著調(diào)用onStart()方法。如果調(diào)用startService()方法前服務(wù)已經(jīng)被創(chuàng)建,多次調(diào)用 startService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù),但會(huì)導(dǎo)致多次調(diào)用onStart()方法。采用 startService()方法啟動(dòng)的服務(wù),只能調(diào)用stopService()方法結(jié)束服務(wù),服務(wù)結(jié)束時(shí) 會(huì)調(diào)用生命周期的onDestroy()方法。

2.bindService()方式啟動(dòng)時(shí)的生命周期回調(diào)方法

(1)綁定bindService : –> onCreate() –> onBind()
(2)解綁unbindService: –>onUnbind()
(3)正常停止程序服務(wù)的方法是先解綁unbindService,再停止服務(wù)stopService。
(4)如果綁定后調(diào)用stopService 方法,這時(shí)是不能停止服務(wù)的,如果這時(shí)再調(diào)用解綁unbindService,程序后先解綁,后停止服務(wù)。
       用bindService()方法啟動(dòng)服務(wù),在服務(wù)未被創(chuàng)建時(shí),系統(tǒng)會(huì)先調(diào)用服務(wù)的onCreate() 方法,接著調(diào)用onBind()方法。這個(gè)時(shí)候調(diào)用者和服務(wù)綁定在一起,調(diào)用者退出了,系統(tǒng)就會(huì)
先調(diào)用服務(wù)的onUnbind()方法,接著調(diào)用onDestroy()方法。如果調(diào)用       bindService()方法前服務(wù)已經(jīng)被綁定,多次調(diào)用bindService()方法并不會(huì)導(dǎo)致多次創(chuàng)建服務(wù)及綁定(也就是說(shuō) onCreate()和onBind()方法并不會(huì)被多次調(diào)用)。如果調(diào)用者希望與正在綁定的服務(wù)解除綁 定,可以調(diào)用unbindService()方法,調(diào)用該方法也會(huì)導(dǎo)致系統(tǒng)調(diào)用服務(wù)的onUnbind()->onDestroy()方法。

綁定Service方法:bindService(intent, conn, Service.BIND_AUTO_CREATE);
三個(gè)參數(shù)的說(shuō)明:
第一個(gè):Intent對(duì)象
第二個(gè):ServiceConnection對(duì)象,創(chuàng)建該對(duì)象要實(shí)現(xiàn)它的onServiceConnected()和 on ServiceDisconnected()來(lái)判斷連接成功或者是斷開(kāi)連接
第三個(gè):創(chuàng)建Service的模式,一般指定綁定的時(shí)候自動(dòng)創(chuàng)建

(三)Service的五個(gè)生命周期的回調(diào)方法

1.周期命名

(1)onCreate()
(2)onStart()
(3)onBind()
(4)onUnBind()
(5)onDestroy()

2.生命周期圖解

sheng
上面展示的是沒(méi)有綁定服務(wù)和有綁定服務(wù)的生命周期的不同情況的過(guò)程。

3.關(guān)于幾個(gè)方法的說(shuō)明

(1)onCreate()說(shuō)明服務(wù)第一次被創(chuàng)建
(2)onStartComand()說(shuō)明服務(wù)開(kāi)始工作
(3)onBind()說(shuō)明服務(wù)已經(jīng)綁定
(4)onUnBind()說(shuō)明服務(wù)已經(jīng)解綁
(5)onDestroy()說(shuō)明服務(wù)已經(jīng)停止
       正如上面說(shuō)的啟動(dòng)服務(wù)有兩種方式,一個(gè)是使用startService,另一個(gè)方法是使用bindService方法;使用bindService方法沒(méi)有回調(diào)到startCommand方法;
       也可以先啟動(dòng)服務(wù)用startService,再綁定服務(wù)用bindService,這時(shí)的Service的回調(diào)方法的順序是:
       –>onCreate()–>onStartCommand()–>onBind()

二.IntentService

       普通的Service要?jiǎng)?chuàng)建一個(gè)線程去完成耗時(shí)操作,因?yàn)槠溥\(yùn)行在主線程,並且要手動(dòng)停止IntentService是繼承于Service并處理異步請(qǐng)求的一個(gè)類(lèi),在IntentService內(nèi)有一個(gè)工作線程 來(lái)處理耗時(shí)操作,啟動(dòng)IntentService的方式和啟動(dòng)傳統(tǒng)Service一樣,同時(shí),當(dāng)任務(wù)執(zhí)行完 后,IntentService會(huì)自動(dòng)停止,而不需要我們?nèi)ナ謩?dòng)控制。
       另外,可以啟動(dòng)IntentService多次,而每一個(gè)耗時(shí)操作會(huì)以工作隊(duì)列的方式在IntentService的onHandleIntent回調(diào)方法中執(zhí)行,并且,每次只會(huì)執(zhí)行一個(gè)工作線程,執(zhí)行完第一個(gè)再執(zhí)行第二個(gè),以此類(lèi)推。 而且,所有請(qǐng)求都在一個(gè)單線程中,不會(huì)阻塞應(yīng)用程序的主線程(UI Thread),同一時(shí)間只處理一個(gè)請(qǐng)求。
       那么,用IntentService有什么好處呢?
       首先,我們省去了在Service中手動(dòng)開(kāi)線程的麻煩,
       第二,當(dāng)操作完成時(shí),我們不用手動(dòng)停止Service IntentService,一個(gè)方便我們處理業(yè)務(wù)流程的類(lèi),它是一個(gè)Service,但是比Service更智能

三.查看Service的生命周期回調(diào)方法的簡(jiǎn)單示例

本示例只是用來(lái)看看Service在服務(wù)開(kāi)啟時(shí),停止時(shí),綁定時(shí),解綁時(shí),生命周期方法的回調(diào)情況加深對(duì)Service生命周期的印象。

(一)創(chuàng)建MyService類(lèi)(繼承Service)

package com.lwz.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;

  /**
   * 服務(wù)的創(chuàng)建,
   * 測(cè)試生命周期的過(guò)程和先后
   * 五個(gè)生命周期:
   * onCreate
   * onStartCommand
   * onDestroy
   * onBind
   * onUnBind
   */

public class MyService extends Service {
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    System.out.println("MyService.onBind");
    return null;
  }

  @Override
  public void onCreate() {
    System.out.println("MyService.onCreate");
    super.onCreate();
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    System.out.println("MyService.onStartCommand");

    return super.onStartCommand(intent, flags, startId);
  }

  @Override
  public void onDestroy() {
    System.out.println("MyService.onDestroy");
    super.onDestroy();
  }

  @Override
  public boolean onUnbind(Intent intent) {
    System.out.println("MyService.onUnbind");
    return super.onUnbind(intent);
  }
}

(二)在AndroidManifest中注冊(cè)服務(wù)

<service android:name=".MyService" />

(三)設(shè)計(jì)控制服務(wù)開(kāi)啟、停止、綁定、解綁狀態(tài)的代碼

package com.lwz.service;

import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

/**
 * 服務(wù)的創(chuàng)建和使用
 * 注意這里的服務(wù)不依賴(lài)于Activity頁(yè)面,即使頁(yè)面關(guān)閉了,服務(wù)沒(méi)有主動(dòng)去停止,是不會(huì)關(guān)閉的
 * Service也是在主線程中執(zhí)行任務(wù)的,但是為什么不會(huì)造成主線程阻塞??
 * 因?yàn)樽龅牟皇呛臅r(shí)操作,如果做耗時(shí)操作一樣會(huì)造成ANR。。。
 * 這里點(diǎn)擊綁定服務(wù)后,點(diǎn)擊停止服務(wù)按鈕是無(wú)效的,要先解綁后,才能停止服務(wù)。
 * 正常情況下,從綁定狀態(tài)到解綁狀態(tài)是不會(huì)停止服務(wù)的。只是一種狀態(tài)改變而已。
 * 這里點(diǎn)擊綁定服務(wù)后,點(diǎn)擊停止服務(wù)按鈕是無(wú)效的,但是解綁后,會(huì)馬上停止服務(wù)。
 */

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  //開(kāi)啟服務(wù)
  public void startService(View view) {
    //開(kāi)啟服務(wù)需要Intent對(duì)象,和Activity跳轉(zhuǎn)類(lèi)似
    startService(new Intent(this, MyService.class));

  }

  //停止服務(wù)
  public void stopService(View view) {
    //停止服務(wù)的方法
    stopService(new Intent(this, MyService.class));
  }

  //綁定服務(wù)
  public void bindService(View view) {
    //綁定服務(wù)
    bindService(new Intent(this, MyService.class), conn, flags);
  }

  //解綁服務(wù)
  public void unBindService(View view) {
    //防止在沒(méi)有綁定的情況下,去解除綁定,拋出異常
    try {
      //解除綁定
      unbindService(conn);
    } catch (Exception e) {
      System.out.println("MainActivity.unBindService" + e);
    }


  }

  //服務(wù)綁定的連接對(duì)象
  private ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
  };

  //服務(wù)綁定的標(biāo)識(shí)
  //BIND_AUTO_CREATE 綁定的同時(shí),啟動(dòng)Service
  private int flags = Service.BIND_AUTO_CREATE;


}

上面是使用四個(gè)按鈕來(lái)實(shí)現(xiàn)服務(wù)的幾種狀態(tài)的改變。

(四)布局文件的設(shè)計(jì)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:text="Service" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="startService"
    android:text="啟動(dòng)服務(wù)" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="stopService"
    android:text="停止服務(wù)" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="bindService"
    android:text="綁定服務(wù)" />

  <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="unBindService"
    android:text="解綁服務(wù)" />


</LinearLayout>

上面布局文件代碼比較簡(jiǎn)單的,只是用四個(gè)按鈕搞定!

程序運(yùn)行后顯示的界面:
s1

點(diǎn)擊“啟動(dòng)服務(wù)”按鈕后的Log信息:
s2
這時(shí)有兩個(gè)回調(diào)方法執(zhí)行。onCreate和onStartCommand.

點(diǎn)擊“停止服務(wù)”按鈕后的Log信息:
s3
執(zhí)行了一個(gè)回調(diào)方法:onDestroy;這時(shí)服務(wù)已經(jīng)停止,相當(dāng)于程序剛運(yùn)行的狀態(tài)!

點(diǎn)擊“綁定服務(wù)”按鈕后的Log信息:
s4
這里執(zhí)行了兩個(gè)回調(diào)方法,先啟動(dòng)服務(wù),再綁定服務(wù)!
在綁定服務(wù)的情況下是不能停止服務(wù)的,要解綁服務(wù)才能停止服務(wù)。
在程序的服務(wù)啟動(dòng)/綁定了的情況下,再點(diǎn)擊啟動(dòng)服務(wù),只會(huì)回調(diào)onStartCommand方法,也就是說(shuō)一個(gè)服務(wù)在一個(gè)生命周期內(nèi)只會(huì)回調(diào)一次onCreate方法。

點(diǎn)擊“解綁服務(wù)”按鈕后顯示的Log信息:
s5
執(zhí)行了兩個(gè)回調(diào)方法:onUnBind和onDestroy

       如果是用服務(wù)做簡(jiǎn)單 的事情,使用第一種方法來(lái)啟動(dòng)服務(wù)就可以了,但是如果需要涉及到比較復(fù)雜的數(shù)據(jù)處理和操作就用綁定服務(wù)的方法來(lái)啟動(dòng)服務(wù)。

四.IntentService的使用示例

程序設(shè)計(jì):查找手機(jī)SD卡中的所有圖片顯示在UI界面上。

//(一)布局文件activity_main.xml文件實(shí)際
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent">


  <ListView
    android:id="@+id/main_lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></ListView>
</RelativeLayout>

非常簡(jiǎn)單的布局設(shè)計(jì),使用List View來(lái)顯示所有的圖片

(二)遍歷文件的工具類(lèi)的設(shè)計(jì)

package com.lwz.intentservice;

import android.os.Environment;
import android.os.StatFs;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/** 
 * SD卡的路徑:Environment.getExternalStorageDirectory()
 */

public class FileUtils {  

  /**
   * 獲得指定目錄下的所有的圖片
   */
  public static final ArrayList<File> getAllPicture(File dir) {
    ArrayList<File> files = getAllFile(dir);
    ArrayList<File> imgList = new ArrayList<>();
    for (File file : files) {
      if (file.getName().endsWith(".png") || file.getName().endsWith(".jpg"))
        imgList.add(file);
    }
    return imgList;
  }

  /**
   * 遞歸遍歷文件夾的方法
   */
  public static final void getFileFromDir(File dir, List<File> fileList) {
    File[] files = dir.listFiles();
    if (files == null)
      return;
    for (File file : files) {
      if (file.isDirectory())
        getFileFromDir(file, fileList);
      fileList.add(file);
    }
  }   

  /**
   * 獲得根目錄下的所有圖片
   */
  public static final ArrayList<File> getAllPicture() {
    return getAllPicture(Environment.getExternalStorageDirectory());
  }  

}

(三)簡(jiǎn)化BaseAdapter的一個(gè)工具類(lèi)

package com.lwz.intentservice;

import android.content.Context;
import android.widget.BaseAdapter;

import java.util.ArrayList;
import java.util.List;

/**
 * 這是一個(gè)簡(jiǎn)化BaseAdapter適配器的工具類(lèi)
 * 這是使用的是定義一個(gè)泛型T,使用時(shí)傳入什么數(shù)據(jù),T就是什么數(shù)據(jù)
 * 實(shí)際設(shè)計(jì)中除了getVIew方法外,其他的方法基本是差不多的
 * 所以繼承這個(gè)工具類(lèi)后只要重寫(xiě)getView方法,就可以使用BaseAdapter了
 */

public abstract class ListItemAdapter<T> extends BaseAdapter {
  List<T> list = new ArrayList<>();
  Context context;

  ListItemAdapter(Context context, List<T> list) {
    this.context = context;
    this.list = list;
  }

  ListItemAdapter(Context context, T[] list) {
    this.context = context;
    for (T t : list) {
      this.list.add(t);
    }
  }

  @Override
  public int getCount() {
    return list == null ? 0 : list.size();
  }

  @Override
  public T getItem(int position) {

    return list == null ? null : list.get(position);
  }

  @Override
  public long getItemId(int position) {
    return position;
  }

}

(四)MyIntentService的創(chuàng)建

package com.lwz.intentservice;

import android.app.IntentService;
import android.content.Intent;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.util.ArrayList;

/**
 * IntentService的使用
 * IntentService是Service的子類(lèi),也需要在xml中注冊(cè)
 * 它有自定義的子線程的方法
 * 這里主要需要解決的問(wèn)題是資源文件得到后怎么把數(shù)據(jù)傳遞給UI線程的Activity
 */

public class MyIntentService extends IntentService {
  /**
   * 通過(guò)構(gòu)造方法,傳入子線程的名字
   * 但是這里必須要?jiǎng)?chuàng)建一個(gè)無(wú)參的構(gòu)造方法
   */
  public MyIntentService() {
    super("myService");
  }

  /**
   * 這是在子線程中的執(zhí)行操作
   */
  @Override
  protected void onHandleIntent(Intent intent) {
    Log.e("TAG", "子線程開(kāi)始工作");
    //遍歷文件夾獲取圖片
    ArrayList<File> list = FileUtils.getAllPicture();
    //使用handler發(fā)送信息
    Message msg = Message.obtain();
    //這里給handler對(duì)象傳遞一個(gè)對(duì)象
    msg.obj = list;
    //發(fā)送廣播來(lái)傳遞數(shù)據(jù)
    Intent intent1 = new Intent("filefinish");
    intent1.putExtra("file", list);
    sendBroadcast(intent1);
  }

  @Override
  public void onCreate() {
    super.onCreate();
    Log.e("TAG", "onCreate");
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    Log.e("TAG", "onDestroy");
  }
}

這里的Intent Service的注冊(cè)和Intent的注冊(cè)是一樣的。

(五)MainActivity中的代碼設(shè)計(jì)

package com.lwz.intentservice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 這里使用服務(wù)來(lái)IntentService來(lái)遍歷文件夾
 * 在程序創(chuàng)建的使用就要啟動(dòng)服務(wù)
 * 在頁(yè)面銷(xiāo)毀的時(shí)候就停止服務(wù)
 但是Service執(zhí)行完任務(wù)后還有傳遞數(shù)據(jù)給MainActivity
 在MainActivity中才能進(jìn)行UI界面的更新
 這就涉及到Service和Activity的數(shù)據(jù)傳遞問(wèn)題了
 這里使用的是用廣播來(lái)傳遞數(shù)據(jù)
 */
public class MainActivity extends AppCompatActivity {
  //定義布局內(nèi)的控件
  ListView listView;
  //定義適配器的數(shù)據(jù)的集合

  //一定要static???
  static ArrayList<File> fileList;
  static MyBaseAdapter adapter;
  MyBroadcastReceiver mbcr;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mbcr = new MyBroadcastReceiver();
    //動(dòng)態(tài)注冊(cè)一個(gè)廣播
    IntentFilter filter = new IntentFilter();
    filter.addAction("filefinish");
    registerReceiver(mbcr, filter);// 注冊(cè)
    //創(chuàng)建適配器的對(duì)象
    adapter = new MyBaseAdapter(this, fileList);
    //實(shí)例化布局內(nèi)的控件
    listView = (ListView) findViewById(R.id.main_lv);

    //給listView設(shè)置適配器
    listView.setAdapter(adapter);
    //啟動(dòng)服務(wù)
    startService(new Intent(this, MyIntentService.class));
  }


  //創(chuàng)建適配器的類(lèi)
  class MyBaseAdapter extends ListItemAdapter<File> {

    MyBaseAdapter(Context context, List<File> list) {
      super(context, list);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      ImageView image = null;
      if (convertView == null) {
        image = new ImageView(getBaseContext());
        convertView = image;
      } else {
        image = (ImageView) convertView;
      }
      //設(shè)置圖片資源和屬性
      image.setImageURI(Uri.fromFile(fileList.get(position)));
      image.setScaleType(ImageView.ScaleType.FIT_XY);
      image.setAdjustViewBounds(true);
      return image;
    }
  }

  //停止服務(wù)
  public void stop() {
    stopService(new Intent(MainActivity.this, MyIntentService.class));
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    //即使之前停止了服務(wù),再次停止服務(wù)也是不會(huì)報(bào)錯(cuò)的
    stop();
    //解除廣播
    unregisterReceiver(mbcr);
  }

  //動(dòng)態(tài)創(chuàng)建廣播接收者
  class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      //對(duì)接收到的廣播進(jìn)行處理,intent里面包含數(shù)據(jù)
      fileList = (ArrayList<File>) intent.getSerializableExtra("file");
      //刷新適配器
      adapter.notifyDataSetChanged();
      //停止服務(wù),它的子線程也會(huì)停止
      stop();
    }
  }


}

      程序運(yùn)行前還記得加上SD卡的訪問(wèn)權(quán)限;
      上面程序功能還是有點(diǎn)問(wèn)題!遍歷完文件后。頁(yè)面沒(méi)有馬上更新?退出程序再進(jìn)來(lái),頁(yè)面上馬上顯示SD卡的圖片。
      一般的說(shuō)遍歷文件夾也不算是耗時(shí)操作,這里只是簡(jiǎn)單示范。
      一般的耗時(shí)操作是從網(wǎng)絡(luò)下載數(shù)據(jù),或本地移動(dòng)大文件等等。

五.同一個(gè)程序中Service和Activity通信的一些方式,這里展示主要代碼。

這里組件不要忘記在AndroidManifest中注冊(cè)

(一)使用Intent來(lái)傳遞數(shù)據(jù)1.MainActivity中的代碼,發(fā)送數(shù)據(jù)

Intent intent = new Intent(this, MyService.class);

intent.putExtra("msg", "activity向service傳遞一個(gè)hello service");

startService(intent);

2.MyService中的代碼,接收數(shù)據(jù)

      這里要使用onStartCommand的方法來(lái)接收Intent的數(shù)據(jù),如果上面使用的是bind的方法來(lái)啟動(dòng)服務(wù),這里可以在onBind方法中接收數(shù)據(jù)。

@Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    Log.e("onStartCommand", intent.getStringExtra(msg));
    return super.onStartCommand(intent, flags, startId);
  }

(二)使用單例模式來(lái)傳遞數(shù)據(jù)

      這個(gè)方法算是有點(diǎn)麻煩的吧!這里要在MyService類(lèi)中先做好單例,然后在Activity中調(diào)用MyService對(duì)象的方法

1.MyService中的代碼

//定義一個(gè)靜態(tài)的類(lèi)變量,單例的使用準(zhǔn)備
  private static MyService instance;

  //靜態(tài)方法,返回的是一個(gè)本類(lèi)對(duì)象
  //為了能讓另一邊的類(lèi)調(diào)用Myservice的方法
  public static MyService getInstance() {
    return instance;
  }


  @Override
  public void onCreate() {
    super.onCreate();

    //單例模式變量賦值
    instance = this;
  }
public void print(String msg) {
    Log.e("service", msg);
  }

      其中print方法是在Activity中調(diào)用的,可以達(dá)到傳送數(shù)據(jù)給MyService,但是這里要先啟動(dòng)過(guò)服務(wù)后才能使用單例,因?yàn)檫@里是在MyService的onCreate方法中把對(duì)象賦值給instance,之后才能實(shí)現(xiàn)單例。

2.MainActivity中的代碼:

/**
   * 單例模式傳參
   *MyService這里通過(guò)一個(gè)靜態(tài)方法,來(lái)獲得MyService的對(duì)象
這里通過(guò)MyService.getInstance()方法來(lái)獲得MyService對(duì)象
   */
      //必須保證Myservice對(duì)象不能為null
    //靜態(tài)的變量,最后釋放(不用的時(shí)候,手動(dòng)將static變量=null)
    if (MyService.getInstance() != null) {
      MyService.getInstance().print("使用單例從activity中調(diào)用service的方法");
    }

(三)廣播傳參傳數(shù)據(jù)

      弄兩個(gè)廣播接收者相互傳數(shù)據(jù)。 

      這里要在MyService和MyService中分別動(dòng)態(tài)的創(chuàng)建廣播接收者和動(dòng)態(tài)注冊(cè)廣播接收者,然后在MainActivity中發(fā)送廣播,在MyService中接收到廣播傳來(lái)遞數(shù)據(jù)后,在發(fā)送廣播,讓MainActivity接收廣播數(shù)據(jù)!

1.MyService中的代碼:

@Override
  public void onCreate() {
    super.onCreate();
    //動(dòng)態(tài)注冊(cè)廣播接收者,要定義好接收的action屬性值
    IntentFilter filter = new IntentFilter("service");
    registerReceiver(serviceReceiver, filter);

  }

 //定義一個(gè)廣播接收者BroadcastReceiver
  BroadcastReceiver serviceReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      Log.e("service", "接收到了activity發(fā)送的廣播:" + intent.getStringExtra("msg"));
//發(fā)送廣播給MainActivity
      sendBroadcast(new Intent("activity").putExtra("msg", "發(fā)送給activity的消息"));
    }
  };

2.MainActivity中的代碼:

@Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //注冊(cè)本類(lèi)內(nèi)的廣播,定義好action的屬性值
    IntentFilter filter = new IntentFilter("activity");
    registerReceiver(activityReceiver, filter);

  }

 /**
   * 通過(guò)廣播來(lái)傳遞數(shù)據(jù)
   */
  public void sendBroadcast(View view) {
    //指明action屬性值
    Intent intent = new Intent("service");
    intent.putExtra("msg", "activity向廣播傳遞一個(gè)hello broadcast");
    sendBroadcast(intent);
  }

 //定義一個(gè)內(nèi)部類(lèi)的廣播接收者,用于接收MyService傳遞過(guò)來(lái)的數(shù)據(jù)
  BroadcastReceiver activityReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      Log.e("activity", intent.getStringExtra("msg"));
    }
  };

(四)MyService實(shí)例調(diào)用方法

      這個(gè)方法是最最麻煩的方法了!涉及到一個(gè)Binder類(lèi)的使用!這里要被調(diào)用的方法其實(shí)不是MyService中的方法,而是里面的內(nèi)部接口的抽象方法,需要在MainActivity中去實(shí)現(xiàn)這個(gè)方法!但是,實(shí)際這個(gè)方法實(shí)在MyService中執(zhí)行的。

1.MyService中的代碼:

//定義一個(gè)接口
  interface Callback {
    //定義兩個(gè)要實(shí)現(xiàn)的方法
    void call();

    void start();
  }

  //定義一個(gè)接口對(duì)象
  Callback callback;

  /**
   * 創(chuàng)建Binder類(lèi),很多很多的Service就是通過(guò)Binder機(jī)制來(lái)和客戶(hù)端通訊交互的。
   */
  class Mybinder extends Binder {
    public MyService getService() {
      return MyService.this;
    }

    //設(shè)置回調(diào)方法
    public void setCallback(Callback callback) {
      MyService.this.callback = callback;
    }
  }

  //定義一個(gè)模擬開(kāi)始音樂(lè)播放的方法
  //需要重寫(xiě)start里面的方法來(lái)開(kāi)始播放音樂(lè)
  public void startMusic() {
    //播放
    Toast.makeText(this, "音樂(lè)開(kāi)始播放", Toast.LENGTH_SHORT).show();
    callback.start();
  }

 @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    //要傳遞一個(gè)MyBinder對(duì)象給MainActivity
    return new MyBinder();
  }

//定義一個(gè)模擬開(kāi)始音樂(lè)播放的方法
  //需要重寫(xiě)start里面的方法來(lái)開(kāi)始播放音樂(lè)
  public void startMusic() {
    //播放
    Toast.makeText(this, "音樂(lè)開(kāi)始播放", Toast.LENGTH_SHORT).show();
//在MainActivity中實(shí)例化callback對(duì)象
    callback.start();
  }

      上面的代碼中要開(kāi)始播放音樂(lè)要調(diào)用startMusic方法,并且要實(shí)例化里面的callback對(duì)象,而要實(shí)例化callback對(duì)象必須要調(diào)用內(nèi)部類(lèi)Mybinder的set Callback方法,而實(shí)現(xiàn)這個(gè)方法又必須實(shí)現(xiàn)這個(gè)接口的方法!

2.MainActivity中的代碼:

/**
   * 綁定服務(wù)Service
調(diào)用MyService的方法來(lái)調(diào)用內(nèi)部類(lèi)的接口方法
   */
//定義一個(gè)MyService對(duì)象
MyService myService;
  public void bindService(View view) {
    bindService(new Intent(this, MyService.class), conn, BIND_AUTO_CREATE);
 myService.startMusic();
  }

//創(chuàng)建ServiceConnection對(duì)象
 ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      //連接服務(wù)后,操作。。。
      //獲取IBinder的bind對(duì)象,從MyService的onBinder中傳遞過(guò)來(lái)的
      MyService.Mybinder bind = (MyService.Mybinder) service;
      //通過(guò)bind對(duì)象獲取Service對(duì)象
      myService = bind.getService();
      //設(shè)置監(jiān)聽(tīng)事件的回調(diào)方法,并實(shí)現(xiàn)里面的兩個(gè)方法
//這里的回調(diào)方法不是MyService中的,而是內(nèi)部類(lèi)Mybinder中的
      bind.setCallback(new MyService.Callback() {
        @Override
        public void call() {
          Log.e("activity", "Service回調(diào)Activity");
        }

        @Override
        public void start() {
          //比如在后臺(tái)播放音樂(lè);開(kāi)始播放音樂(lè)
          Log.e("action", "正在播放音樂(lè)");
          //關(guān)閉頁(yè)面
          finish();
        }
      });

      上面的關(guān)系確實(shí)是有點(diǎn)亂,我發(fā)現(xiàn)我有些注解還是有點(diǎn)問(wèn)題的?。?nbsp;

      上面就是Service中的個(gè)方面的總結(jié)。 

      Service還可以用來(lái)做進(jìn)程間的數(shù)據(jù)傳遞,這里就涉及到AIDL(Android Interface Definition Language,安卓接口定義語(yǔ)言)進(jìn)程通信。這個(gè)相對(duì)來(lái)說(shuō)比較復(fù)雜,另作總結(jié)!

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

最新評(píng)論