亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

全部開發者教程

Android 入門教程

菜單類控件
菜單:Menu
并發編程
多線程

服務:Service

今天來學習 Android 的另一個組件——Service,相比于 Activity,Service通常運行在后臺,沒有任何 UI 界面,對用戶是透明感知。通常用來執行一些后臺任務,比如播放音樂、下載、加載一些數據等等,也可以用作一些進程間通信(IPC)機制。

1. Service 的基本定義

我們還是先來看看官方文檔的部分解釋:

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package’s AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().

還是用我蹩腳的英語給大家簡單翻譯一下:

Service 是 Android 四大組件之一,通常用來執行一些需要長時間運行并且不需要和用戶發送交互的任務,或者是要持續給其他 App 提供服務的場景。每一個服務和 Activity 一樣,需要在包下的 “AndroidManifest.xml”文件中添加注冊,Service可以通過Context.startService()或者Context.bindService()兩種方式啟動。

簡而言之,Service適用于無 UI 界面并且長時間運行或者專門給其他 App 提供服務的場景。

2. Service 的基本概念

為了更好的理解 Service的運行機制,這里提出幾個容易混淆的概念:

  • **進程:**進程是操作系統為一個 App 提供的獨立的運行單元,是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位。
  • **線程:**線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是

一般說來,在 Android 中一個 App 運行在一個獨立進程,而每一個進程可以有多個線程。從編程的角度來看,多個線程是同時并行運行的(是否是真并行依賴操作系統的調度以及 CPU 的核數)。
我們的 Activity 就是運行在主線程(UI線程),而 Service 默認也是在主線程,所以如果需要做一些耗時操作仍然需要主動放到子線去運行。

3. Service 的啟動方式及生命周期

在第 1 小節的最后講到過,Service 有兩種啟動方式:Context.startService()Context.bindService(),所以也對應著兩類 Service:

  • Started Service
  • Bound Service

2.1 Started Service

顧名思義,Started 類型的 Service 就是通過Context.startService()方法啟動的 Service,此時 Service 會立即在后臺啟動,可以調用Context.stopService()關閉。當然,在 Service 內也可以使用Context.stopService()來關閉自己。

2.2 Bound Service

Service 進入 Bound 狀態需要在 Activity 中調用Context.bindService()方法,這樣這兩個組件就綁定到了一起,此后二者可以很方便的相互通信,調用Context.unbindService()可以解除綁定。

其實以上兩種方式的最大差異就是,第 1 種在 start 之后,兩個組件之間就沒有太大關系了,而第 2 種是以“bind”形式啟動的,啟動之后兩者仍然是綁定關系,可以進行數據的傳遞以及狀態的監聽。
這兩種啟動方式的生命周期如下:

service_lifecycle

相比于 Activity,Service 的生命周期就簡化了很多,主要還是依賴于啟動方式,通常如果是一個相對獨立的 Service,未來不需要和 Activity 強關聯,推薦使用第一種;當然如果需要在 Activity 里面做一些交互甚至對 Service 做一些管理,那么必須使用 bind 的方式。

4. Service 使用示例

接下通過 Service 實現一個非常常見的功能——音樂播放器?,F在市面的絕大多數音樂播放器都是在一個 Service 里面實現的,它需要長時間在后臺運行,所以天然就適合運行在 Service 中。

4.1 播放器控制

這里主要是演示 Service 的用法,所以只對播放器進行簡單的控制,大家課后感興趣的可以繼續補充,將示例做成一個更加完整的播放器。我們在 Service 創建的時候初始化播放器,在 Servce 啟動的時候啟動播放器,銷毀的時候關閉。首先創建“PlayerService”,代碼如下:

package com.emercy.myapplication;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.IBinder;
import android.widget.Toast;

public class PlayerService extends Service {
    MediaPlayer myPlayer;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();

        myPlayer = MediaPlayer.create(this, R.raw.mc_guitar);
        myPlayer.setLooping(false); // Set looping
    }

    @Override
    public void onStart(Intent intent, int startid) {
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        myPlayer.start();
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        myPlayer.stop();
    }
}

代碼很簡單,在 Service 的onCreate()中初始化播放器,設置音頻地址,將你喜歡的音樂放置在 raw 目錄,或者指定一個網絡 Mp3 的 url 地址均可;然后在onStart()中啟動播放器。

4.2 布局文件編寫

我們希望能夠隨時控制播放器的起播和停止,所以需要兩個 Button 分別進行控制:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/buttonStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="74dp"
        android:text="啟動播放器" />

    <Button
        android:id="@+id/buttonStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="停止播放" />
</RelativeLayout>

4.3 主控邏輯編寫

在 MainActivity 里主要要做兩件事:

  1. 通過startService()啟動 PlayerService,播放音樂;
  2. 通過stopService結束播放

package com.emercy.myapplication;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {
    Button buttonStart, buttonStop;

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

        buttonStart = findViewById(R.id.buttonStart);
        buttonStop = findViewById(R.id.buttonStop);

        buttonStart.setOnClickListener(this);
        buttonStop.setOnClickListener(this);
    }

    public void onClick(View src) {
        switch (src.getId()) {
            case R.id.buttonStart:
                startService(new Intent(this, PlayerService.class));
                break;
            case R.id.buttonStop:
                stopService(new Intent(this, PlayerService.class));
                break;
        }
    }
}

4.4 清單文件

需要注意的是,Service 是一個組件,凡是添加組件都需要在 AndroidManifest.xml 中注冊(動態注冊除外),否則無法使用:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.emercy.myapplication">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".PlayerService"
            android:enabled="true"
            android:exported="true" />
    </application>

</manifest>

**注意:**如果你的音頻文件是一個遠程的 url,還需要增加網絡權限:

    <uses-permission android:name="android.permission.INTERNET" />

到此,整個初級的播放器就開發完成了。大家如果感興趣還可以考慮增加其他的功能,比如快進、快退、切歌、增加通知欄、展示歌詞等等。

5. 小結

本節介紹了 Android 第二個組件,Service 的主要場景是運行一些耗時且在后臺的任務,并且相比 Activity 它更輕量且沒有用戶界面。有兩種啟動方式,通過startService()啟動之后 Service 與啟動它的 Activity 再無任何關聯,而bindService()方式啟動之后二者還會綁定在一起,可以進行相互的調用和數據傳遞。同時由于 Service 無 UI 界面,所以在用完后一定要記得要 stop,回收資源。