1. 程式人生 > >(一)service和activity通訊方式

(一)service和activity通訊方式

實現效果圖:

使用service在後臺播放音樂,拖動進度條,與服務進行互動,改變音樂的播放進度

(1)首先,我們需要申請讀取本地檔案的許可權,播放本機的音樂

  <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"/>

(2)把服務註冊了。因為服務是四大元件之一,需要註冊,位置和activity平行

   <service
            android:name="com.example.administrator.testz.MusicService"
            android:enabled="true"
            android:exported="true">
        </service>

(3)使用MyBind接收資料,進出處理 ,重點是code,根據code的值來進行服務和介面的互動


import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.view.animation.LinearInterpolator;

import java.io.IOException;

/**
 * Created by Administrator on 2018\11\13 0013.
 */

public class MusicService extends Service {
    private int flag = 0;
    public static MediaPlayer mediaPlayer = new MediaPlayer();
    private IBinder mBinder = new MyBinder();
    public static ObjectAnimator animator;
    public static String which= "";
    public static int returnFlag = 0;


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;//一定要返回binder
    }

    public class MyBinder extends Binder{
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code){
                case 101:
                    //播放 處理服務的函式
                    playOrPauseHandler();
                    break;
                case 102:
                    //處理服務的函式 停止
                    stopHandler();
                    break;
                case 103:
                    //處理服務的函式 退出
                    quitHandler();
                    break;
                case 104:
                    //處理服務的函式 介面重新整理

                    break;
                case 105:
                    //處理服務的函式 拖動進度處理

                    break;
                default:
                    break;
            }
            return super.onTransact(code, data, reply, flags);
        }
    }

    //退出
    private void quitHandler() {
        animator.end();
        mediaPlayer.stop();
        mediaPlayer.release();
    }

    //停止
    private void stopHandler() {
        which = "stop";
        animator.pause();
        if(mediaPlayer != null){
            mediaPlayer.pause();
            mediaPlayer.stop();
            try {
                mediaPlayer.prepare();
                mediaPlayer.seekTo(0);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //播放
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    private void playOrPauseHandler() {
        flag++;
        if(flag>=1000){
            flag=2;
        }
        which = "pause";
        if(mediaPlayer.isPlaying()){
            mediaPlayer.pause();
            animator.pause();
        }else {
            mediaPlayer.start();
            if(flag==1 || returnFlag == 1){
                animator.setDuration(5000); //設定持續時間
                animator.setInterpolator(new LinearInterpolator()); //設定勻速轉動
                animator.setRepeatCount(ValueAnimator.INFINITE);    //設定無限迴圈
                animator.setRepeatMode(ValueAnimator.RESTART);  //設定重複模式 RESTART:重新從頭開始執行。 REVERSE:反方向執行
                animator.start(); //開始
            }else{
                animator.start();
            }
        }
    }

    //獲取檔案路徑  設定播放屬性
    public MusicService(){
        try {
            String Assets_path1 = "/storage/emulated/0/Android/data/暗香.mp3";
            mediaPlayer.setDataSource(Assets_path1);
            mediaPlayer.prepare(); //prepare()或prepareAsync()方法把流媒體裝載進MediaPlayer,呼叫start()方法播放流媒體
            mediaPlayer.setLooping(true); //設定是否迴圈播放。
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //設定轉動
    public void setAnimation(){
        if(mediaPlayer.isPlaying()){
            animator.setDuration(5000); //設定持續時間
            animator.setInterpolator(new LinearInterpolator()); //設定勻速轉動
            animator.setRepeatCount(ValueAnimator.INFINITE);    //設定無限迴圈
            animator.setRepeatMode(ValueAnimator.RESTART);  //設定重複模式 RESTART:重新從頭開始執行。 REVERSE:反方向執行
            animator.start(); //開始

        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mediaPlayer.stop();
        mediaPlayer.release(); //釋放資源
    }
}

(4)主介面呼叫

import android.Manifest;
import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.icu.text.SimpleDateFormat;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

@RequiresApi(api = Build.VERSION_CODES.N)
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private IBinder mBinder;
    private ServiceConnection mConnection;
    /*控制元件*/
    private Button playButton;
    private Button stopButton;
    private Button quitButton;
    private ImageView image;
    private TextView currentTime;
    private TextView endTime;
    private TextView txt_state;
    private SeekBar seekBar;

    private MusicService musicService;
    private SimpleDateFormat time  = new SimpleDateFormat("mm:ss");
    public Handler handler = new Handler();

    public Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if(musicService.mediaPlayer.isPlaying()){
                txt_state.setText("Playing");
            }else{
                if(musicService.which.equals("stop")){
                    txt_state.setText("stop");
                }else if(musicService.which.equals("pause")){
                    txt_state.setText("pause");
                }
            }
            currentTime.setText(time.format(musicService.mediaPlayer.getCurrentPosition()));
            endTime.setText(time.format(musicService.mediaPlayer.getDuration()));
            seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition());
            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                    if(b){
                        //直接拖懂  mediaplayer的seekto方法
                        musicService.mediaPlayer.seekTo(seekBar.getProgress());
                    }
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {

                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {

                }
            });
            handler.postDelayed(runnable,100);
        }
    };

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

        musicService = new MusicService();

        //繫結服務,開啟服務
        mConnection  = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                mBinder = iBinder;  //資料繫結
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                mConnection = null;
            }
        };

        Intent intent = new Intent(this,MusicService.class);
        startService(intent);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

        //初始化
        initViews();
        initEvent();    //事件

    }

    private void initEvent() {
        playButton.setOnClickListener(this);
        stopButton.setOnClickListener(this);
        quitButton.setOnClickListener(this);
    }

    private void initViews() {
        image = (ImageView)findViewById(R.id.image);
        txt_state = (TextView)findViewById(R.id.txt_state);
        currentTime = (TextView)findViewById(R.id.start_time);
        endTime = (TextView)findViewById(R.id.end_time);
        seekBar = (SeekBar)findViewById(R.id.seekbar);
        playButton = (Button)findViewById(R.id.isPlayButton);
        stopButton = (Button)findViewById(R.id.stopButton);
        quitButton = (Button) findViewById(R.id.quitButton);
        musicService.animator = ObjectAnimator.ofFloat(image,"rotation",0,350); //動畫繫結
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.isPlayButton:
                playButtonHandler();
                break;
            case R.id.stopButton:
                stopButtonHandler();
                break;
            case R.id.quitButton:
                quitButtonHanler();
                break;

        }
    }

    //退出
    private void quitButtonHanler() {
        try {
            int code = 103;
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            mBinder.transact(code,data,reply,0);
        }catch (RemoteException e){
            e.printStackTrace();
        }
        handler.removeCallbacks(runnable);
        unbindService(mConnection);
        try {
            finish();
            System.exit(0);
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private void stopButtonHandler() {
        try {
            int code = 102;
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            mBinder.transact(code,data,reply,0);
        }catch (RemoteException e){
            e.printStackTrace();
        }
    }

    private void playButtonHandler() {
        if(musicService.mediaPlayer.isPlaying()){
            txt_state.setText("Pause");
            playButton.setText("play");
        }else{
            txt_state.setText("Playing");
             playButton.setText("Pause");
        }
        try {
            int code = 101;
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            mBinder.transact(code,data,reply,0);
        }catch (RemoteException e){
            e.printStackTrace();
        }

    }

    @Override
    protected void onResume() {
        super.onResume();
        if(musicService != null){
            musicService.setAnimation();
        }
        checkStoragePerssion(this);
        if(musicService.mediaPlayer.isPlaying()){
            txt_state.setText("playing");
        }else{
            if(musicService.which.equals("stop")){
                txt_state.setText("stop");
            }else if(musicService.which.equals("pause")){
                txt_state.setText("pause");
            }
        }
        seekBar.setProgress(musicService.mediaPlayer.getCurrentPosition()); //獲取當前進度
        seekBar.setMax(musicService.mediaPlayer.getDuration());  //獲取最大值
        handler.post(runnable);
    }

    private void checkStoragePerssion(MainActivity mainActivity) {
        String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
        final int REQUEST_EXTERNAL_STORAGE = 1;
        try{
            int permission = ActivityCompat.checkSelfPermission(mainActivity,"android.permission.READ_EXTERNAL_STORAGE");
            if(permission!= PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(mainActivity,PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if(grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
            Toast.makeText(MainActivity.this,"您已授予應用許可權",Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(MainActivity.this,"應用許可權不足,啟動失敗",Toast.LENGTH_SHORT).show();
            System.exit(0);
        }
        return;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        musicService.returnFlag = 1;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(mConnection);
        mConnection = null;
        try {
            MainActivity.this.finish();
        }catch (Exception e){
            e.printStackTrace();
        }
    }



}

(5)介面效果

  <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:id="@+id/image"
        android:layout_marginTop="20dp"
        android:scaleType="centerInside"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/likena" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txt_state"
        android:text=""
        android:layout_below="@+id/image"
        android:padding="15dp"/>

    <TableRow
        android:id="@+id/tbr_row1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/txt_state"
        android:padding="15dp">

        <TextView
            android:id="@+id/start_time"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_weight="1"
            android:text="00:00"
            android:textSize="20sp" />

        <SeekBar
            android:layout_width="0dp"
            android:layout_weight="4"
            android:layout_height="wrap_content"
            android:id="@+id/seekbar"
            android:layout_gravity="center_vertical" />
        <TextView
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:id="@+id/end_time"
            android:text="00:00"
            android:textSize="20sp"/>
    </TableRow>

    <TableRow
        android:id="@+id/tbr_row2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tbr_row1"
        android:gravity="center_horizontal"
        android:padding="15dp">
        <Button
            android:id="@+id/isPlayButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22dp"
            android:text="PLAY" />

        <Button
            android:id="@+id/stopButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22dp"
            android:text="STOP"
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"/>
        <Button
            android:id="@+id/quitButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="22dp"
            android:text="QUIT" />
    </TableRow>