什么是service?
service是被“后台服务”,它的运行不依赖ui界面,我个人还喜欢把它看着一种消息服务,因为你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver。
service分类
a、按运行地点分类
本地服务(Local) 该服务依附在主进程上
远程服务(Remote)该服务是独立进程的(少见的,并且一般都是系统服务)
b、按运行类型分类
前台服务 会在通知一栏显示 ONGOING 的 Notificatio
后台服务 默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification
c、按使用方式分类(重要¥¥¥¥¥¥¥)
startService 启动的服务 主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService
bindService 启动的服务 该方法启动的服务要进行通信(即外部可以调用service内部的方法)。停止服务使用unbindService
startService 同时也 bindService 启动的服务 停止服务应同时使用stepService与unbindService(这是混合服务)
三种开启服务的生命周期的区别
startService方式开启的服务,服务会长期在后台运行,直到用户手动停止服务或者调用stopService方法,其中onCreate方法只会执行一次,onstart()可能执行多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用
bindService方式开启服务会执行服务的onCreate方法 和 onBind()方法 onstart方法不会执行当连接建立后,服务会一直存在,直到调用它的Context对象销毁(比如activity销毁)或者调用了Context.unbindService()方法,系统将会自动停止Service,对应onDestroy将被调用。
如果一个Service是混合方式启动,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须调用 stopService 或 Service的 stopSelf 来停止服务。这样可以实现长期后台运行和实现通信的
Thread线程和Service的区别
Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作
Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程。
startService方式开启服务(电话窃听器)
重要:四大组件都需要配置,因此在创建服务后需要在xml文件中配置
AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alleged.phoneListener"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<!-- 对外部文件的写入和删除权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" >
</uses-permission>
<!-- 音频刻录权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" >
</uses-permission>
<!-- 接收手机完全开启状态权限 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" >
</uses-permission>
<!-- 读取电话状态权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" >
</uses-permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".phonelistener"></service>
<receiver android:name=".BootBrodcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
</application>
</manifest>
BootBrodcastReceiver设置开机启动服务的广播接受者
package com.alleged.phoneListener;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootBrodcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 接受到相应的广播后,调用onReceive()方法
//这里调用要开启的服务
//创建出相应的意图的对象 第一个参数是上下文 第二参数你要开启的类
System.out.println("广播开启");
Intent listenerIntent = new Intent(context,phonelistener.class);
context.startService(listenerIntent);
}
}
service phoneListenerService.java
package com.alleged.phoneListener;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
public class phonelistener extends Service {
private String TAG = "PhoneListenerService";// 这里设置一个Log标志,方便于调试
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
/* 复写onCreate()方法,当这个服务被创建的时候就实现监听 */
@Override
public void onStart(Intent intent, int startId) {
};
@Override
public void onCreate() {
System.out.println("oncreate is working");
/* 取得本机的电话服务 //创建电话管理者 */
TelephonyManager telmanager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
// 注册一个电话监听器 通过管理类的listen方法监听 这里要实现一个phoneStateListener对象,监听状态改变
// 实现PhoneStateListener对象
PhoneStateListener calllistener = new PhoneStateListener() {
private String callNum;// 定义一个监听电话号码
private boolean isRecord = false;// 定义一个当前是否正在复制的标志
private MediaRecorder recorder;// 媒体复制类
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// 判断一下电话属于什么状态
switch (state) {
// 无任何状态
case TelephonyManager.CALL_STATE_IDLE:
// 把来电号码设置为空
callNum = null;
// 判断录音是否为空和录音开关的状态
if (recorder != null && isRecord) {
Log.i(TAG, "录音完成");// 设定一个录音完成的标志,方便调试
recorder.stop();// 录音完成,
recorder.reset();// 通过reset()方法回到Initialized状态
recorder.release();// 释放所有和MediaRecorder对象绑定的资源
isRecord = false;// 录音完成,改变状态标志
}
break;
// 代表响铃状态
case TelephonyManager.CALL_STATE_RINGING:
// 获取来电的电话号码
this.callNum = incomingNumber;
break;
// 代表接起电话
case TelephonyManager.CALL_STATE_OFFHOOK:
// 判断来电号码,是否是要监听的电话号码
if (callNum.equals("1234567")) {
Log.i(TAG, "开始录音");
// 是要监听的电话,就开始录音
recorder = new MediaRecorder();
// 设置资源
// 定义声音来自于麦克风
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置输出格式为3gp格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// 定我编码
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 此处定义一个format类,方便对录音文件进行命名
SimpleDateFormat format = new SimpleDateFormat("yyMMddHHmmss");
String fileName = this.callNum + "_" + format.format(new Date());
System.out.println(
"/mnt/sdcard/luyin.3gp");
recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
// 准备资源
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start(); // 开始刻录
isRecord = true;// 标志录音成功
System.out.println("开始录制");
} else {
System.out.println("不是想要录音的电话号码");
Log.e(TAG, "不是想要录音的电话号码");
}
}
super.onCallStateChanged(state, incomingNumber);
}
};
// 正式监听
telmanager.listen(calllistener, PhoneStateListener.LISTEN_CALL_STATE);
super.onCreate();
}
}
(android的4.0后这个种服务安装启动的时候需要一个界面,为了安全)
package com.alleged.phoneListener;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("ma de zhi zhang");
//监听器的实现步骤
//第一步:注册一个广播接受者
//设置为开机启动的广播
//开启服务
//在onstart 定一个电话监听类
//在监听类中设置管理者
//注册一个监听类
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
混合开启服务的小例子
mainActivity.java
package com.alleged.hybrid;
import android.support.v7.app.ActionBarActivity;
import com.alleged.musicService.Ibinder;
import com.alleged.musicService.music_Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
public class MainActivity extends ActionBarActivity {
private Context context;
private Ibinder binder;
private MyConn conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
//在页面启动就开启服务
Intent intent = new Intent(context, music_Service.class);
context.startService(intent);
}
public void startService(View v) {
//开启服务
}
public void bindService(View v) {
System.out.println("bindservice");
Intent intent = new Intent(context, music_Service.class);
conn = new MyConn();
if(conn!=null){
bindService(intent, conn, BIND_AUTO_CREATE);
}
}
public void unbindService(View v) {
conn = new MyConn();
context.unbindService(conn);
}
public void stopService(View v) {
Intent intent = new Intent(context, music_Service.class);
context.stopService(intent);
}
public void play_music(View v){
binder.playMusic();
}
public void stop_music(View v){
binder.sleepmusic();
}
public void nextmusic(View v){
binder.nextOne();
}
public void prevmusic(View v){
binder.prev();
}
/* public class myconn implements ServiceConnection{
//连接成功
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("连接成功 ");
binder = (Ibinder) service;
System.out.println("连接成功 ");
}
//连接失败
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}*/
private class MyConn implements ServiceConnection {
// 当连接成功时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 获取我们定义的中间人对象
binder = (Ibinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
music_service.java
package com.alleged.musicService;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
public class music_Service extends Service {
//IBinder类返回,提供接口调用方法内部的方法
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new myIBinder();
}
public void play_Music(){
System.out.println("音乐播放");
}
public void sleep_music(){
System.out.println("音乐暂停");
}
public void next_One(){
System.out.println("下一首");
}
public void prev_one(){
System.out.println("上一首");
}
public class myIBinder extends Binder implements Ibinder{
@Override
public void playMusic() {
play_Music();
}
@Override
public void sleepmusic() {
sleep_music();
}
@Override
public void nextOne() {
next_One();
}
@Override
public void prev() {
prev_one();
}
}
}
布局文件
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.alleged.hybrid.MainActivity" >
<Button
android:id="@+id/button1"
android:text="startService"
android:onClick="startService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
<Button
android:id="@+id/button2"
android:onClick="bindService"
android:text="bindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/button3"
android:layout_alignParentLeft="true"
android:layout_marginBottom="58dp" />
<Button
android:id="@+id/button3"
android:onClick="unbindService"
android:text="unbindService"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button2"
android:layout_below="@+id/button1"
android:layout_marginTop="151dp" />
<Button
android:id="@+id/buttton4"
android:onClick="stopService"
android:text="stopService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/button2"
android:layout_alignParentLeft="true"
android:layout_marginBottom="30dp" />
<Button
android:id="@+id/stop_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/next"
android:layout_below="@+id/next"
android:onClick="stop_music"
android:text="暂停" />
<Button
android:id="@+id/prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/buttton4"
android:layout_below="@+id/button2"
android:layout_marginTop="42dp"
android:onClick="prevmusic"
android:text="上一首" />
<Button
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/prev"
android:layout_alignBottom="@+id/prev"
android:layout_marginLeft="31dp"
android:layout_toRightOf="@+id/prev"
android:onClick="nextmusic"
android:text="下一首" />
<Button
android:id="@+id/play_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/stop_music"
android:layout_alignBottom="@+id/stop_music"
android:layout_toLeftOf="@+id/next"
android:onClick="play_music"
android:text="播放" />
</RelativeLayout>
配置文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alleged.hybrid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.alleged.musicService.music_Service">
</service>
</application>
</manifest>