Android學習之---------服務(案例:音樂播放器)

我們手機中很多app在運行的過程中都能在后臺運行,例如邊聽歌邊打游戲,這一功能得益于服務,后臺功能屬于Android四大組件之一。
下面通過音樂播放器的案列走進服務:
服務(Service)是Android中的四大組件之一,它能夠長期在后臺運行切不提供用戶界面,即使用戶切換到另一應用程序,服務仍可在后臺運行。它的創(chuàng)建過程與創(chuàng)建Activity相似,只需繼承Service類即可。

下面我們先來創(chuàng)建一個服務:創(chuàng)建一個項目,在項目中新建一個MyService類繼承自Service,然后會自動實現(xiàn)onBind()方法:

  public class MyService extends Service {
    @Nullable
    @Override
   public IBinder onBind(Intent intent) {
     return null;
 }
}

本服務目前沒有實現(xiàn)任何功能。需要注意的是,在MyService中有一個onBi()方法,該方法是Service類中唯一的抽象方法,所以必須要在子類中實現(xiàn)。
接下來我們需要在清單文件中配置,這是因為服務屬于Android四大組件之一,所以要在AndroidManifest.xml清單文件中進行注冊。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lxz.android0804">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<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=".MyService"/>
</application>
</manifest>

至此服務便創(chuàng)建成功了,需要注意到是不要忘記在清單文件中注冊,否則服務不會生效。

服務與其他組件不同的是:Service不能自己主動執(zhí)行,需要調用相應的方法來啟動。啟動服務的方法有兩個,分別是Context.startService()和Context.bindService()。使用不同方式開啟服務,服務的生命周期也會不同。
1、startService方式開啟服務的生命周期:
onCreate()(第一次創(chuàng)建服務時執(zhí)行)→onStartCommend()(啟動服務調用的方法)→onDestroy(服務被銷毀時執(zhí)行的方法)
2、bindService方式開啟服務的生命周期:
onCreate()(第一次創(chuàng)建服務時執(zhí)行)→onBind(啟動服務調用的方法)→onUnbind(斷開服務綁定時執(zhí)行的方法)→onDestroy(服務被銷毀時執(zhí)行的方法)
兩種方式都可以顯現(xiàn)編寫播放器的功能,但為了全面起見,我們采用混合開啟服務的方式來寫,而且這樣也有很大的優(yōu)點。
讓服務在后臺長期運行,又調用服務里的方法流程:
1、先調用startService 開啟一個服務
2、然后調用BindService方法,獲取中間人(運行服務中的方法)
3、unBindService方法
4、調用StopService方法

接下來就正式進入音樂播放器的編寫:
首先在來寫我們的布局頁面:

<LinearLayout       xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context="com.lxz.android0804.MainActivity">

<SeekBar
    android:id="@+id/seekbar"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="0dp"
    android:layout_marginTop="20dp"
    />

<ImageButton
    android:id="@+id/btn_play"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:scaleType="fitXY" //scaleType等比例縮放屬性
    android:background="@null"
    android:onClick="startmusic"
    android:src="@drawable/start" />
</LinearLayout>

這里設置了一個進度條,和一個圖片按鈕,同時給ImageButton設置了點擊事件,采用線性布局,水平放置。這里在處理圖片按鈕時用到了一個圖片等比例縮放的屬性,即:scaleType屬性。界面如圖顯示(主要用于功能的實現(xiàn),所以沒有優(yōu)化界面的美觀度):


image.png

然后在MainActivity中來實現(xiàn)我們設置的點擊事件,同時開啟我們的服務:

public class MainActivity extends AppCompatActivity {
 MyConn conn;//聲明
 MyService.MyBinder myBinder;
 private ImageButton imageButton;
 private SeekBar seekBar;  
 @Override
protected void onCreate(Bundle savedInstanceState) {     
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    imageButton=findViewById(R.id.btn_play);
    seekBar=findViewById(R.id.seekbar);
    Intent intent = new Intent(this, MyService.class);
    startService(intent);  //開啟服務
    conn=new MyConn(); //
    bindService(intent,conn,BIND_AUTO_CREATE);
}

class MyConn implements ServiceConnection{//自己定義一個MyConn類實現(xiàn)接口

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder service) {
      myBinder=(MyService.MyBinder) service;//得到傳過來的中間人,因為放音樂也需要用中間人,所以把中間人設置為全局變量
     }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
}
//播放音樂
public void startmusic(View view){
           }

  }
}

同時在MainActivity中得到我們設置imageButton跟seekBar。
因為在執(zhí)行Bindservice時我們需要實例化ServiceConnection接口的實現(xiàn)類,所以自己定義了一個MyConn類實現(xiàn)接口,重寫onServiceConnected()和onServiceDisconnected()方法。

那么接下來我們就要在MyService類里面完成我們想要實現(xiàn)的創(chuàng)建、播放、暫停最基本的功能:

      public class MyService extends Service {
private static final String TAG = "MyService";
String path="mnt/sdcard/2.mp3";
MediaPlayer mediaPlayer;//全局變量
@Nullable
@Override
public IBinder onBind(Intent intent) {
    return new MyBinder();
}

@Override
public void onCreate() {
    Log.i(TAG, "onCreate: 準備播放");
    super.onCreate();
    //準備音樂播放器流程
    mediaPlayer=new MediaPlayer();//局部變量,本方法有效
    try {
        mediaPlayer.setDataSource(path);
        mediaPlayer.prepare();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

//播放音樂
public void play(){
    Log.i(TAG, "play: 開始播放");
    mediaPlayer.start();
}
//暫停
public void pause(){
    mediaPlayer.pause();
}
    }

在這里為了簡單我們直接聲明了音樂文件的路徑,然后實現(xiàn)各個功能,在過程中我們使用了MediaPlayer來實現(xiàn)播放音樂的功能。在Android中播放音頻文件一般都是使用MediaPlayer類來實現(xiàn)。
下面對MediaPlayer進行簡單的介紹下其中常用的方法:
setAudioStreamType:指定音頻文件類型必須在prepare()方法之前調用。
setDateSource():設置要播放的音頻文件的位置。
prepare():在開始播放之前調用這個方法來完成準備工作。
start():開始或繼續(xù)音頻播放。
pause():暫停播放音頻。
reset():將MediaPlayer重置到剛剛創(chuàng)建的狀態(tài)。
seekTo():從指定的位置開始播放音頻。
stop():停止播放音頻,調用該方法后MediaPlayer對象無法再播放音頻。
release():釋放掉與MediaPlayer對象相關的資源。
isplaying():判斷當前MediaPlayer是否正在播放。
getDuration():獲取載入音頻文件時長。
getCurrentPosition():獲取當前播放音頻文件的位置。
以上就是最常用的幾個方法了。

因為我們要播放音樂所以我們肯定也需要獲取音樂的播放時長,進度,當前狀態(tài)等功能,所以就用到上面的方法:我們將其加入到我們的服務類中。

 //獲取歌曲時長(毫秒數(shù))
public int getDuration(){
    return mediaPlayer.getDuration();
}
//查看當前播放進度(毫秒數(shù))
public int getCurrentPosition(){
    return mediaPlayer.getCurrentPosition();
}
//查看播放狀態(tài)
public boolean playstate(){
   return mediaPlayer.isPlaying();
}
//定位音樂播放器
public void setPosition(int newPosition){
    mediaPlayer.seekTo(newPosition);
}

因為Activity與服務時兩個不同的組件,所以當我們在Activity中不能直接調用的服務中的方法,所以我們準備了一個中間人MyBinder來連接服務于Activity之間的關系,講各個方法放入進去。

class MyBinder extends  Binder{ //定義內部類,中間人
    public void callMusic(){
        play();
    }
    public void stopMusic(){
        pause();
    }
    public boolean callPlayState(){
        return playstate();
    }
    public int callDuration(){
        return getDuration();
    }
    public int callCurrentPosition(){
        return getCurrentPosition();
    }
    public void callSetPosition(int x){
        setPosition(x);
    }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容