Android下的Service的基本用法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35317635/article/details/77104112
Service的介绍:
谈到服务,就必须要先知道什么是进程,
1、进程概念介绍
  四大组件都是运行在主线程,Android中的服务 也是在后台运行  可以理解成是在后台运行并且是没有界面的Activity。
  下面这个5个进程是按照等级就行排列,等级的高低关乎该进程被系统关闭的难易程度,从一到五难度降低
  (1)Foreground process 前台进程  用户正在交互  可以理解成相 当于 Activity执行onResume方法
  (2)Visible process 可视进程 用户没有在交互 但用户还一直能看得见页面 相当于Activity执行了onPause方法 
  (3)Service Process  服务进程  通过startService()开启了一个服务
  (4)Background process  后台进程  当前用户看不见页面 相当于Activity执行了onStop方法
  (5)Empty process 空进程


2、Service分为本地服务(LocalService)和远程服务(RemoteService):
  (1)本地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要
IPC(进程间通信),也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。
  (2)远程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。


按使用方式可以分为以下三种:
1、startService 启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService;
2、bindService 启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService,自定义的服务类即使继承了服务,但是在new一个对象时,并不能直接调用服务中的方法,所以引用bindService 就是为了调用bindService 里面的方法
3、startService 同时也 bindService 启动的服务:停止服务应同时使用stepService与unbindService


总之:服务是在后台运行 可以理解成是没有界面的activity
      定义四大组件的方式都是一样的
      定义一个类继承Service重写方法

  
一、start方式开启服务的特点:
(1)服务通过startservice方式开启 第一次点击按钮开启服务 会执行服务的onCreate 和 onStart方法
(2)如果第二次开始在点击按钮开启服务 服务之后执行onStrat方法
(3)服务被开启后 会在设置页面里面的 running里面找得到这个服务 
(4)startservice 方式开启服务 服务就会在后台长期运行 直到用户手工停止 或者调用StopService方法 服务才会被销毁


二、bindService方式开启服务的特点: 
(1)当点击按钮第一次开启服务 会执行服务的onCreate方法 和 onBind()方法
(2) 当我第二次点击按钮在调用bindservice  服务没有响应 
(3) 当activity销毁的时候服务也销毁  不求同时生但求同时死 
(4)通过bind方式开启服务  服务不能再设置页面里面找到  相当于是一个隐形的服务

(5)bindservice不能多次解绑 多次解绑会报错

总结:

混合方式开启服务 

(1)先调用startService()方法 保证服务在后台长期运行
(2)调用bindservice()目的获取我们定义的中间人对象 调用服务里面的方法
(3)unbindservice() 看这时候服务会不会销毁
(4)最后调用stopservice() 停止服务 :

通过bindservice方式调用服务方法里面的过程:

(1)定义一个服务 服务里面有一个方法需要Activity调用

(2)定义一个中间人对象(IBinder) 继承Binder; 

(3)在onbind方法里面把我们定义的中间人对象返回  

(4)在Activity的oncreate 方法里面调用bindservice 目的是为来获取我们定义的中间人对象

(4.1)获取中间人对象

(5)拿到中间人对象后就可以间接的调用到服务里面的方法 

百度音乐盒案例:

在软件开发中,一般不会只是单一的使用startservice(),或者是bindService,而是两种相结合。下面这个小程序,则演示了两者服务同时使用需求:我既想让服务在后台长期运行  又想调用服务里面的方法  


UI:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click1"
        android:text="播放" />

    
      <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click2"
        android:text="暂停" />
      
      <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="click3"
        android:text="继续播放" />

      <SeekBar
          android:id="@+id/seekBar1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content" />
    
</LinearLayout>


Mainactivity代码:

package com.itheima.baidumusic;

import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity {

	private Iservice iservice; // 这个就是我们定义的中间人对象
	private MyConn conn;
	private static SeekBar sbar;  
	public  static Handler handler = new Handler(){
		//当 接收到消息该方法执行
		public void handleMessage(android.os.Message msg) {
			//[1]获取msg 携带的数据 
			Bundle data = msg.getData();
			//[2]获取当前进度和总进度
			int duration = data.getInt("duration");
			int currentPosition = data.getInt("currentPosition");
			
			//[3]设置seekbar的最大进度和当前进度 
			sbar.setMax(duration);  //设置进度条的最大值
			sbar.setProgress(currentPosition);//设置当前进度
			
			
			
		};
	};
	
	

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

		sbar = (SeekBar) findViewById(R.id.seekBar1);
		
		
		//[0]先调用startservice 方法开启服务 保证服务在后台长期运行
		Intent intent = new Intent(this, MusicService.class);
		startService(intent);
		
		// [1]调用bindservice 目的是为了获取我们定义的中间人对象
		conn = new MyConn();
		// 连接MusicService 服务 获取我们定义的中间人对象
		bindService(intent, conn, BIND_AUTO_CREATE);

		//[2]给seekbar 设置监听 

		sbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			//当停止拖动执行
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				
				//设置播放的位置 
				iservice.callSeekToPosition(seekBar.getProgress());
			}
			//开始拖动
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				
			}
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
					boolean fromUser) {
				
			}
		});
		
	}

	// 点击按钮 进行 音乐播放
	public void click1(View v) {

		// 调用播放音乐的方法
		iservice.callPlayMusic();
	}

	// 暂停音乐
	public void click2(View v) {

		// 调用暂停音乐的方法
		iservice.callPauseMusic();
	}

	// 继续播放
	public void click3(View v) {

		// 调用继续播放
		iservice.callrePlayMusic();
	}

	// 当Activity销毁的时候调用
	@Override
	protected void onDestroy() {
		// 在Activity销毁的时候 取消绑定服务
		unbindService(conn);

		super.onDestroy();
	}

	private class MyConn implements ServiceConnection {

		// 当连接成功时候调用
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// 获取我们定义的中间人对象
			iservice = (Iservice) service;

		}

		@Override
		public void onServiceDisconnected(ComponentName name) {

		}

	}

}


MusicService代码如下:

package com.itheima.baidumusic;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;

//音乐播放服务
public class MusicService extends Service {

	private MediaPlayer player;

	//[2]把我们定义的中间人对象 返回
	@Override
	public IBinder onBind(Intent intent) {
		return new MyBinder();
	}
	//服务第一次开启的是调用
	@Override
	public void onCreate() {
		
		//[1]初始化mediaplayer 
		player = new MediaPlayer();
		
		super.onCreate();
	}
	
	
	//当服务销毁的时候调用
	@Override
	public void onDestroy() {
		super.onDestroy();
	}
	
	//设置播放音乐指定位置的方法
	public void seekToPosition(int position){
		player.seekTo(position);
	}
	
	

	//专门用来播放音乐的 
	public void playMusic(){
		System.out.println("音乐播放了");
		
		//[2]设置要播放的资源  path 可以是本地也可是网络路径 
				try {
					player.reset();
					
					player.setDataSource("/mnt/sdcard/xpg.mp3");
					
					//[3]准备播放 
					player.prepare(); 
					
					//[4]开始播放 
					player.start();
					
					//[5]更新进度条 
					updateSeekBar();
					
				} catch (Exception e) {
					e.printStackTrace();
				}
		
		
	}
	
	//更新进度条的方法 
	private void updateSeekBar() {
		//[1]获取当前歌曲总时长 
		final int duration = player.getDuration();
		//[2]一秒钟获取一次当前进度  
		final Timer timer = new Timer();
		final TimerTask task = new TimerTask() {
			
			@Override
			public void run() {
				//[3]获取当前歌曲的进度 
				int currentPosition = player.getCurrentPosition();
				
				//[4]创建message对象  
				Message msg = Message.obtain();
				//[5]使用msg携带多个数据   
				Bundle bundle = new Bundle();
				bundle.putInt("duration", duration);
				bundle.putInt("currentPosition", currentPosition);
				msg.setData(bundle);
				//发送消息 MainActivity的handlemessage方法会执行
				MainActivity.handler.sendMessage(msg);
				
			}
		};
		//300毫秒后 每隔1秒钟获取一次当前歌曲的进度
		timer.schedule(task, 300, 1000);
		//[3]当歌曲播放完成的时候 把timer 和task 取消 
		player.setOnCompletionListener(new OnCompletionListener() {
			
			//当歌曲播放完成的回调
			@Override
			public void onCompletion(MediaPlayer mp) {
				System.out.println("歌曲播放完成了 ");
				
				timer.cancel();
				task.cancel();
				
			}
		});
		
		
	}
	//音乐暂停了
	public void pauseMusic(){
		System.out.println("音乐暂停了");
		//暂停 
		player.pause();
		
	}
	
	//音乐继续播放的方法
	public void  rePlayMusic(){
		System.out.println("音乐继续播放了");
		
		player.start();
		
	}
	
	//[1]定义一个中间人对象(IBinder) 
	private class MyBinder extends Binder implements Iservice{

		//调用播放音乐的方法
		@Override
		public void callPlayMusic() {
			
			playMusic();
		}

		//调用暂停音乐的方法
		@Override
		public void callPauseMusic() {
			
			pauseMusic();
		}

		//调用继续播放的方法 
		@Override
		public void callrePlayMusic() {
			
			rePlayMusic();
		}

		//调用设置播放指定位置的方法 
		@Override
		public void callSeekToPosition(int position) {
			
			seekToPosition(position);
		}
		
	}
	
	
	
}
接口Iservice的具体代码:

package com.itheima.baidumusic;

public interface Iservice {
	//把我们想暴露的方法放到接口中
	public void callPlayMusic();
	public void callPauseMusic();
	public void callrePlayMusic();
	
	public void callSeekToPosition(int position);
	
}



猜你喜欢

转载自blog.csdn.net/qq_35317635/article/details/77104112
今日推荐