系统服务
用户编写的 Service 是后台应用服务程序,位于 Android 系统应用层。相对而言的系统服务(System Services)可以看作 Android 系统的内置软件,它是 Android 操作系统 Java 应用程序下层的,伴随操作系统启动而运行的系统后台服务程序。系统服务是 Android 系统运行的基石,它配合 binder、Dalvik 虚拟机和 Android 应用程序构成了一个多进程交互通信、交互服务的 Android 系统。
Android 的所有服务循环都建立在 System Server 之上,Service manager 是管理系统服务的进程,通过 ServerManager 的 add_service() 方法把服务加入到服务列表中,实现对服务的管理。Activity 中有一个重要的方法 getSystemService(),根据传入的 Name 来取得对应的 Object,然后转换成相应的服务对象。
public Object getSystemService(String name);
以下是常用的系统服务:
系统服务名 | 返回的对象 | 说明 |
---|---|---|
WINDOW_SERVICE | WindowManager | 管理打开的窗口程序 |
LAYOUT_INFLATER_SERVICE | LayoutInflater | 取得 xml 里定义的 View |
ACTIVITY_SERVICE | ActivityManager | 管理应用程序的系统状态 |
POWER_SERVICE | PowerManger | 电源服务 |
ALARM_SERVICE | AlarmManager | 闹钟服务 |
NOTIFICATION_SERVICE | NotificationManager | 状态栏服务 |
KEYGUARD_SERVICE | KeyguardManager | 键盘锁服务 |
LOCATION_SERVICE | LocationManager | 位置服务,如 GPS |
SEARCH_SERVICE | SearchManager | 搜索服务 |
VIBRATOR SERVICE | Vibrator手 | 机振动服务 |
CONNECTIVITY_SERVICE | Connectivity | 网络连接服务 |
WIFI_SERVICE | WifiManager | WiFi 服务 |
TELEPHONY_SERVICE | TeleponyManager | 电话服务 |
系统服务样例
程序需求
利用 Android APP 的系统服务,获取并设置系统音量。
功能设计
首先需要获取不同音量的最大值,保值音量的设置是正确的不会越界,接着再获取当前的音量作为拖动条的初始值。接着就是当用户点击“ok”的时候,根据拖动条的值使用 set 方法来设置系统音量。
代码编写
AdjustVolumeDialog.java
package com.example.yinlian;
import android.app.AlertDialog;
import android.content.Context;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
public class AdjustVolumeDialog extends AlertDialog {
private AudioManager audioManager;
private SeekBar seekbar1, seekbar2, seekbar3;
private int screenWidth;
private TextView textView1,textView2,textView3;
private CheckBox ch;
private Button ok, cancel;
private Context context;
protected AdjustVolumeDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
}
/**
* 在onCreate方法里面 setContentView() 否则dialog的自定义view 显示不出来
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
audioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
screenWidth = dm.widthPixels; // 屏幕宽度(像素)
initView();
}
/**
* 自定义dialog 的view
* 设置 位置
*/
private void initView() {
View root = LayoutInflater.from(getContext()).inflate(R.layout.dialog, null);
setContentView(root);
seekbar1 = root.findViewById(R.id.ringseekBar);
seekbar2 = root.findViewById(R.id.mediaseekBar);
seekbar3 = root.findViewById(R.id.alarmseekBar);
textView1 = (TextView) findViewById(R.id.ring);
textView2 = (TextView) findViewById(R.id.media);
textView3 = (TextView) findViewById(R.id.Alarm);
ch = (CheckBox)findViewById(R.id.choose);
ok = (Button)findViewById(R.id.ok);
cancel = (Button)findViewById(R.id.cancel);
seekbar1.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_RING));
seekbar2.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
seekbar3.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM));
int ringVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
int musicVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
int alarmVolume = audioManager.getStreamVolume(AudioManager.STREAM_ALARM);
seekbar1.setProgress(ringVolume);
seekbar2.setProgress(musicVolume);
seekbar3.setProgress(alarmVolume);
textView1.setText("铃声音量为:" + ringVolume);
textView2.setText("媒体音量为:" + musicVolume);
textView3.setText("闹钟音量为:" + alarmVolume);
/* 设置SeekBar 监听setOnSeekBarChangeListener */
seekbar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
/*拖动条停止拖动时调用 */
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
/*拖动条开始拖动时调用*/
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
/* 拖动条进度改变时调用*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView1.setText("铃声音量为:" + progress);
}
});
seekbar2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView2.setText("媒体音量为:" + progress);
}
});
seekbar3.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView3.setText("闹钟音量为:" + progress);
}
});
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int ringVolume = seekbar1.getProgress();
if(ch.isChecked()) {
audioManager.setStreamVolume(AudioManager.STREAM_RING, seekbar1.getProgress(), AudioManager.FLAG_PLAY_SOUND);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, seekbar1.getProgress(), AudioManager.FLAG_PLAY_SOUND);
seekbar2.setProgress(ringVolume);
textView2.setText("媒体音量为:" + ringVolume);
audioManager.setStreamVolume(AudioManager.STREAM_ALARM, seekbar1.getProgress(), AudioManager.FLAG_PLAY_SOUND);
seekbar3.setProgress(ringVolume);
textView3.setText("闹钟音量为:" + ringVolume);
}
else {
audioManager.setStreamVolume(AudioManager.STREAM_RING, seekbar1.getProgress(), AudioManager.FLAG_PLAY_SOUND);
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, seekbar2.getProgress(), AudioManager.FLAG_PLAY_SOUND);
audioManager.setStreamVolume(AudioManager.STREAM_ALARM, seekbar3.getProgress(), AudioManager.FLAG_PLAY_SOUND);
}
}
});
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
// 设置dialog中view的位置
Window window = getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.CENTER; //居中
window.setAttributes(lp);
}
/**
* dialog显示时回调
* 广播注册
*/
@Override
public void show() {
super.show();
IntentFilter filter = new IntentFilter() ;
filter.addAction("android.media.VOLUME_CHANGED_ACTION") ;
}
/**
* dialog消失时回调
* 广播反注册
*/
@Override
public void dismiss() {
super.dismiss();
}
}
Diglog.xml
接着就设置一个弹窗来实现这个功能即可。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/seekLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Volume"
android:textSize="40dp"></TextView>
<TextView
android:id="@+id/ring"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Ringtone"
android:textSize="20dp">
</TextView>
<SeekBar
android:id="@+id/ringseekBar"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:maxHeight="20dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/seekbar_thumb" />
<TextView
android:id="@+id/media"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Media"
android:textSize="20dp"></TextView>
<SeekBar
android:id="@+id/mediaseekBar"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:maxHeight="20dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/seekbar_thumb" />
<TextView
android:id="@+id/Alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="Alarm"
android:textSize="20dp"></TextView>
<SeekBar
android:id="@+id/alarmseekBar"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:maxHeight="20dp"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:progressDrawable="@drawable/po_seekbar"
android:thumb="@drawable/seekbar_thumb" />
<CheckBox
android:id="@+id/choose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="使用来电铃音音量进行通知"></CheckBox>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/ok"
android:layout_width="114.0dip"
android:layout_height="40.0dip"
android:gravity="center"
android:text="ok" />
<Button
android:id="@+id/cancel"
android:layout_width="114.0dip"
android:layout_height="40.0dip"
android:layout_marginLeft="20.0dip"
android:gravity="center"
android:text="cancel" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
MainActivity
package com.example.yinlian;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
Button btn;
AdjustVolumeDialog adjustVolumeDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 需要为 dialog 设置一个 style
adjustVolumeDialog = new AdjustVolumeDialog(this, R.style.Theme_Yinlian);
btn = findViewById(R.id.btn);
// 点击按钮弹出对话框
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
adjustVolumeDialog.show();
}
});
}
@Override
protected void onDestroy() {
if(adjustVolumeDialog!=null && adjustVolumeDialog.isShowing()) {
adjustVolumeDialog.dismiss();
}
super.onDestroy();
}
}
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"
tools:context="com.example.yinlian.MainActivity"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="音量调节"
android:layout_marginTop="50dp"
android:layout_gravity="center"
android:textSize="20dp"/>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_gravity="center"
android:textSize="20dp"
android:text="调节">
</Button>
</LinearLayout>
运行效果
打开弹窗。
设置新的音量。
使用来电音量来设置,媒体音量和闹钟音量会设置为来电音量。
参考资料
《Android 移动应用开发》,杨谊 主编、喻德旷 副主编,人民邮电出版社