实验七 服务
一、实验目的
1.掌握Android服务的定义及类的写法。
2. 掌握Android启动服务、停止服务的方法。
3.掌握Android暂停服务的方法。
4.掌握Android音乐播放器的控制方法。
二、实验内容
1.完成使用后台Service进行音乐播放案例,主界面如下,包含4个按钮,播放按钮用来启动服务,播放音乐;暂停按钮暂停音乐播放;停止按钮停止音乐播放;退出按钮退出程序运行。
三、实验仪器、设备
硬件:PC 微型计算机、8G以上内存、500G以上硬盘。
软件:Windows 7/10、Android Studio (Eclipse)、JDK、Android SDK。
四、实验步骤
1.布局:
① 建立android项目。
② 编辑布局文件activity_main.xml。
<?xml version="1.0" encoding="utf-8"?>
<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">
<LinearLayout
android:id="@+id/linear1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:text="播放" />
<Button
android:id="@+id/pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:text="暂停" />
</LinearLayout>
<LinearLayout
android:id="@+id/linear2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_weight="1"
android:text="停止" />
<Button
android:id="@+id/exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_weight="1"
android:text="退出" />
</LinearLayout>
</LinearLayout>
③主界面控制的源文件java。
import androidx.appcompat.app.AppCompatActivity ;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements OnClickListener {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button playBtn = (Button) findViewById(R.id.play);
Button stopBtn = (Button) findViewById(R.id.stop);
Button pauseBtn = (Button) findViewById(R.id.pause);
Button exitBtn = (Button) findViewById(R.id.exit);
playBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
pauseBtn.setOnClickListener(this);
exitBtn.setOnClickListener(this);
}
public void onClick(View v) {
int num = -1;
intent = new Intent(this,MusicService.class);
switch (v.getId()) {
case R.id.play:
Toast.makeText(this, "play music...", Toast.LENGTH_SHORT).show();
num = 1;
break;
case R.id.stop:
Toast.makeText(this, "stop music...", Toast.LENGTH_SHORT).show();
num = 2;
break;
case R.id.pause:
Toast.makeText(this, "pause music...", Toast.LENGTH_SHORT).show();
num = 3;
break;
case R.id.exit:
Toast.makeText(this, "exit...", Toast.LENGTH_SHORT);
num = 4;
stopService(intent);
this.finish();
return;
}
Bundle bundle = new Bundle();
bundle.putInt("music", num);
intent.putExtras(bundle);
startService(intent);
}
@Override
public void onDestroy(){
super.onDestroy();
if(intent != null){
stopService(intent);
}
}
}
④后台Service服务源代码。
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class MusicService extends Service {
private static final String TAG = "MusicService";
private MediaPlayer mediaPlayer;
private boolean reset = false;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
Log.v(TAG, "onCreate");
if (mediaPlayer==null) {
mediaPlayer = MediaPlayer.create(this, R.raw.lake);
mediaPlayer.setLooping(false);
}
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
@Override
public void onStart(Intent intent, int startId) {
Log.v(TAG, "onStart");
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int num = bundle.getInt("music");
switch (num) {
case 1:
play();
break;
case 2:
stop();
break;
case 3:
pause();
break;
}
}
}
}
public void play() {
Log.v(TAG, "-----------" + reset + "----------");
if (mediaPlayer==null)
return;
if (reset==true)
mediaPlayer.seekTo(0);
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
public void pause() {
reset = false;
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
reset = true;
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
mediaPlayer.prepare(); // 在调用stop 后如果需要再次通过 start进行播放,需要之前调用 prepare函数
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
2.在res下创建raw文件夹,拷贝mp3文件lake.mp3到raw下。
3.清单文件AndroidManifest.xml。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.sun.ch7">
<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">
<service
android:name=".MusicService"
android:enabled="true"
android:exported="true"></service>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
4.运行,调试。
5.播放器播放方式改为“循环播放”
① 修改MusicServic.java文件
import java.io.IOException;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class MusicService extends Service {
private static final String TAG = "MusicService";
private MediaPlayer mediaPlayer;
private boolean reset = false;
public MusicService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
Log.v(TAG, "onCreate");
if (mediaPlayer==null) {
mediaPlayer = MediaPlayer.create(this, R.raw.lake);
mediaPlayer.setLooping(false);
}
}
@Override
public void onDestroy() {
Log.v(TAG, "onDestroy");
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
@Override
public void onStart(Intent intent, int startId) {
Log.v(TAG, "onStart");
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
int num = bundle.getInt("music");
switch (num) {
case 1:
play();
break;
case 2:
stop();
break;
case 3:
pause();
break;
}
}
}
}
public void play() {
Log.v(TAG, "-----------" + reset + "----------");
if (mediaPlayer==null)
return;
if (reset==true)
mediaPlayer.seekTo(0);
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
mediaPlayer.setLooping(true);
}
}
public void pause() {
reset = false;
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
public void stop() {
reset = true;
if (mediaPlayer != null) {
mediaPlayer.stop();
try {
mediaPlayer.prepare(); // 在调用stop 后如果需要再次通过 start进行播放,需要之前调用 prepare函数
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
②运行,调试。
五、实验思考题
1 说明服务Service函数的主要分类以及区别?
答:主要分类:按前后台、按远程服务与本地服务、按是否可以通信。
区别:
1.前后台: 前台服务执行一些用户能注意到的操作。后台服务执行用户不会直接注意到的操作
2.远程服务与本地服务:远程服务运行在独立进程,需要进行 IPC 通讯(AIDL, Messenger),服务后台运行, 不受Activity影响。本地服务跟主体应用同一进程,运行在主线程, 耗时任务需开子线程,主进程被杀死, 服务也会终止,单实例。
3.是否可以通信:startService()不可通信。bindService()通过 ServiceConnection 接收 Service 中 onBind() 函数 返回的 IBinder 对象 进行通讯
2 Service启动方式主要有两种startservice和bindservice,有何不同之处?
答:1.startService启动服务:Service会经历onCreate()------->onStartCommand()。当执行stopService时,直接调用onDestroy方法。调用者如果没有stopService,Service会一直在后台运行,下次调用者再次启动仍然可以stopService。多次调用startService,该Service只能被创建一次,即该Service的onCreate()只会被调用一次。但是每次调用startService,onStartCommand()都会被调用。
2.Service会经历onCreate()----->onBind()。这个时候调用者和Service捆绑在一起。调用者调用unbindService方法或者调用者Context不存在了(如Activity被finish(销毁)了),Service就会调用onUnbind()------>onDestroy()。第一次执行bindService时,onCreate()和onBind()会被调用,但是多次执行bindService时,onCreate()和onBind()方法并不会被多次调用,即并不会多次创建服务和绑定服务。