Android系统服务
概述
本篇博文主要介紹的是Android中的Java服務。
這部分服務大部分都有一個Manager類,其實就是一個RPC調用,用戶通過調用xxxManager的方法,實際上被Binder給遷移到system_server進程中對應的xxxManagerService中對應的方法,并將結果再通過binder帶回。
常用的有如下幾個:
PowerManagerService –> PowerManager
| PowerManagerService –> PowerManager | Android 的電源管理 |
| ActivityManagerService->ActivityManager | 整個Android framework框架中最為核心的一個服務,管理整個框架中任務、進程管理, Intent解析等的核心實現。雖然名為Activity的Manager Service,但它管轄的范圍,不只是Activity,還有其他三大組件,和它們所在的進程。也就是說用戶應用程序的生命管理,都是由他負責的。 |
| TelephonyRegistry->TelephonyManager | 電話注冊、管理服務模塊,可以獲取電話的鏈接狀態、信號強度等等 |
| PackageManagerService -> PackageManager | 包括對軟件包的解包,驗證,安裝以及升級等等,對于我們現在不能安裝.so文件的問題,應該先從這塊著手分析原因。 |
| AccountManagerService -> AccountManager | 提供賬戶、密碼和authtoken管理設備上的賬戶 |
| ContentService -> ContentResolver | 內容服務,主要是數據庫等提供解決方法的服務。 |
| BatteryService | 監控電池充電及狀態的服務,當狀態改變時,會廣播Intent |
| WindowManagerService -> WindowManager -> PhoneWindowManager | 和ActivityManagerService高度粘合窗口管理,這里最核心的就是輸入事件的分發和管理。 |
| AlarmManagerService -> AlarmManager | 鬧鐘服務程序 |
| BluetoothService -> BluetoothDevice | 藍牙的后臺管理和服務程序 |
| ClipboardService -> ClipboardManager | 和其他系統的clipBoard服務類似,提供復制黏貼功過。 |
| InputMethodManagerService -> InputMethodManager | 輸入法的管理服務程序,包括何時使能輸入法,切換輸入法等等。 |
| NetStatService | 手機網絡服務 |
| ConnectivityService -> ConnectivityManager | 網絡連接狀態服務,可供其他應用查詢,當網絡狀態變化時,也可廣播改變。 |
| NotificationManagerService -> NotificationManager | 負責管理和通知后臺事件的發生等,這個和statusbar膠黏在一起,一般會在statusbar上添加響應圖標。用戶可以通過這知道系統后臺發生了什么 |
| WallpaperManagerService -> WallpaperManager | 管理桌面背景的服務,深度定制化桌面系統 |
| AppWidgetService -> AppWidgetManager | Android可以讓用戶寫的程序以widget的方式放在桌面上,這就是這套管理和服務的接口 |
| AudioService -> AudioManager | AudioFlinger的上層管理封裝,主要是音量、音效、聲道及鈴聲等的管理 |
TelephonyManager(電話管理器)
官方API
TelecomManager
獲得TelephonyManager的服務對象
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);示例
調用撥號器撥打電話號碼
Uri uri=Uri.parse("tel:"+電話號碼); Intent intent=new Intent(Intent.ACTION_DIAL,uri); startActivity(intent);獲取Sim卡信息與網絡信息
public class MainActivity extends AppCompatActivity {private TextView tv_phone1;private TextView tv_phone2;private TextView tv_phone3;private TextView tv_phone4;private TextView tv_phone5;private TextView tv_phone6;private TextView tv_phone7;private TextView tv_phone8;private TextView tv_phone9;private TelephonyManager tManager;private String[] phoneType = {"未知","2G","3G","4G"};private String[] simState = {"狀態未知","無SIM卡","被PIN加鎖","被PUK加鎖","被NetWork PIN加鎖","已準備好"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//①獲得系統提供的TelphonyManager對象的實例tManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);bindViews();}private void bindViews() {tv_phone1 = (TextView) findViewById(R.id.tv_phone1);tv_phone2 = (TextView) findViewById(R.id.tv_phone2);tv_phone3 = (TextView) findViewById(R.id.tv_phone3);tv_phone4 = (TextView) findViewById(R.id.tv_phone4);tv_phone5 = (TextView) findViewById(R.id.tv_phone5);tv_phone6 = (TextView) findViewById(R.id.tv_phone6);tv_phone7 = (TextView) findViewById(R.id.tv_phone7);tv_phone8 = (TextView) findViewById(R.id.tv_phone8);tv_phone9 = (TextView) findViewById(R.id.tv_phone9);tv_phone1.setText("設備編號:" + tManager.getDeviceId());tv_phone2.setText("軟件版本:" + (tManager.getDeviceSoftwareVersion()!= null?tManager.getDeviceSoftwareVersion():"未知"));tv_phone3.setText("運營商代號:" + tManager.getNetworkOperator());tv_phone4.setText("運營商名稱:" + tManager.getNetworkOperatorName());tv_phone5.setText("網絡類型:" + phoneType[tManager.getPhoneType()]);tv_phone6.setText("設備當前位置:" + (tManager.getCellLocation() != null ? tManager.getCellLocation().toString() : "未知位置"));tv_phone7.setText("SIM卡的國別:" + tManager.getSimCountryIso());tv_phone8.setText("SIM卡序列號:" + tManager.getSimSerialNumber());tv_phone9.setText("SIM卡狀態:" + simState[tManager.getSimState()]);} }訪問以上API,記得清單文件添加權限
<!-- 添加訪問手機位置的權限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <!-- 添加訪問手機狀態的權限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE"/>獲取手機的信號強度
網絡信號強度的單位是dBm(毫瓦分貝),一般用負數表示,正常手機信號變化范圍是從-110dBm (差)到-50dBm(好)之間,如果你比-50dBm還小的話,說明你就站在基站的附近。
另外2G,3G,4G獲得信號強度的方式都是重寫PhoneStateListener的onSignalStrengthsChanged() 方法,當信號強度發生改變的時候就會觸發這個事件,我們可以在這個事件里獲取信號強度!
手機獲取信號強度代碼示例:
dBm =-113+2*asu這是一個固定公式,asu(獨立信號單元)
getEvdoDbm():電信3G
getCdmaDbm():聯通3G
getLteDbm():4G
監聽手機的所有來電
詳見本人另外一篇博客來去電攔截
黑名單來電自動掛斷
詳見本人另外一篇博客AIDL與來去電自動掛斷
SmsManager(短信管理器)
官方API
不建議使用 android.telephony.gsm.SmsManager這個類
This class was deprecated in API level 4. Replaced by android.telephony.SmsManager that supports both GSM and CDMA.建議使用 android.telephony.SmsManager
SmsManager
調用系統發送短信功能
這樣發短信,app安裝的時候就可以少寫一條發短信的權限
核心代碼
public void SendSMSTo(String phoneNumber,String message){ //判斷輸入的phoneNumber是否為合法電話號碼 if(PhoneNumberUtils.isGlobalPhoneNumber(phoneNumber)){ //Uri.parse("smsto") 這里是轉換為指定Uri,固定寫法 Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"+phoneNumber)); intent.putExtra("sms_body", message); startActivity(intent); } }調用系統提供的短信接口發送短信
這個就需要發短信的權限啦
uses-permission android:name="android.permission.SEND_SMS"/>我們直接調用SmsManager為我們提供的短信接口發送短信:
sendTextMessage(destinationAddress, scAddress, text, sentIntent, deliverIntent);參數依次是:
- destinationAddress:收信人的電話號碼
- scAddress:短信中心的號碼,null的話使用當前默認的短信服務中心
- text:短信內容
- sentIntent:短信發送狀態的信息:(發送狀態的Intent) 如果不為null,當消息成功發送或失敗這個PendingIntent就廣播。結果代碼是Activity.RESULT_OK 表示成功,或RESULT_ERROR_GENERIC_FAILURE、RESULT_ERROR_RADIO_OFF、RESULT_ERROR_NULL_PDU 之一表示錯誤。對應RESULT_ERROR_GENERIC_FAILURE,sentIntent可能包括額外的”錯誤代碼”包含一 個無線電廣播技術特定的值,通常只在修復故障時有用。每一個基于SMS的應用程序控制檢測sentIntent。 如果sentIntent是空,調用者將檢測所有未知的應用程序,這將導致在檢測的時候發送較小數量的SMS。
- deliverIntent:短信是否被對方收到的狀態信息:(接收狀態的Intent) 如果不為null,當這個短信發送到接收者那里,這個PendtingIntent會被廣播, 狀態報告生成的pdu(指對等層次之間傳遞的數據單位)會拓展到數據(”pdu”)
核心代碼
public void sendSMS(String phoneNumber,String message){ //獲取短信管理器 android.telephony.SmsManager smsManager = android.telephony.SmsManager.getDefault(); //拆分短信內容(手機短信長度限制),貌似長度限制為140個字符,就是//只能發送70個漢字,多了要拆分成多條短信發送//第四五個參數,如果沒有需要監聽發送狀態與接收狀態的話可以寫null List<String> divideContents = smsManager.divideMessage(message); for (String text : divideContents) { smsManager.sendTextMessage(phoneNumber, null, text, sentPI, deliverPI); } }可能你還需要監聽短信是否發送成功,或者收信人是否接收到信息,就把下面的加上吧:
處理返回發送狀態的sentIntent:
//處理返回的發送狀態 String SENT_SMS_ACTION = "SENT_SMS_ACTION"; Intent sentIntent = new Intent(SENT_SMS_ACTION); PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, sentIntent, 0); //注冊發送信息的廣播接收者 context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context _context, Intent _intent) { switch (getResultCode()) { case Activity.RESULT_OK:Toast.makeText(context, "短信發送成功", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: //普通錯誤break;case SmsManager.RESULT_ERROR_RADIO_OFF: //無線廣播被明確地關閉break; case SmsManager.RESULT_ERROR_NULL_PDU: //沒有提供pdubreak; case SmsManager.RESULT_ERROR_NO_SERVICE: //服務當前不可用break; } } }, new IntentFilter(SENT_SMS_ACTION));處理返回接收狀態的deliverIntent:
//處理返回的接收狀態 String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION"; //創建接收返回的接收狀態的Intent Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION); PendingIntent deliverPI = PendingIntent.getBroadcast(context, 0,deliverIntent, 0); context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context _context, Intent _intent) { Toast.makeText(context,"收信人已經成功接收", Toast.LENGTH_SHORT).show(); } }, new IntentFilter(DELIVERED_SMS_ACTION));AudioManager(音頻管理器)
官方API
AudioManager
獲得AudioManager對象實例
AudioManager audiomanage = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);常用方法
示例
簡單的示例:使用Mediaplayer播放音樂,通過AudioManager調節音量大小與靜音!
對了,先在res下創建一個raw的文件夾,往里面丟一個MP3資源文件!
設置靜音的方法setStreamMute()在API 23版本過期, 可以使用另一個方法adjustStreamVolume(int, int, int),然后第三個屬性設置:
ADJUST_MUTE 或 ADJUST_UNMUTE!
對了,還有:
如果adjustStreamVolume()的第三個參數你設置了振動(Vibrator), 需要在AndroidManifest.xml中添加這個權限!
<uses-permission android:name=”android.permission.VIBRATE”/>
Vibrator(振動器)
官方API
Vibrator
獲得Vibrator實例:
Vibrator vb = (Vibrator)getSystemService(Service.VIBRATOR_SERVICE);相關方法:
- abstract void cancel():關閉或者停止振動器
- abstract boolean hasVibrator():判斷硬件是否有振動器
- void vibrate(long milliseconds):控制手機振動為milliseconds毫秒
- void vibrate(long[] pattern,int repeat):指定手機以pattern指定的模式振動! 比如:pattern為new int[200,400,600,800],就是讓他在200,400,600,800這個時間交替啟動與關閉振動器! 而第二個則是重復次數,如果是-1的只振動一次,如果是0的話則一直振動 還有其他兩個方法用得不多~ 對了,使用振動器還需要在AndroidManifest.xml中添加下述權限: <uses-permission android:name="android.permission.VIBRATE"/>
示例:設置頻率不同的震動器
對于Vibrator用的最廣泛的莫過于所謂的手機按摩器類的app
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/btn_hasVibrator"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="判斷是否有振動器" /><Buttonandroid:id="@+id/btn_short"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="短振動" /><Buttonandroid:id="@+id/btn_long"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="長振動" /><Buttonandroid:id="@+id/btn_rhythm"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="節奏振動" /><Buttonandroid:id="@+id/btn_cancle"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="取消振動" /> </LinearLayout> public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button btn_hasVibrator;private Button btn_short;private Button btn_long;private Button btn_rhythm;private Button btn_cancle;private Vibrator myVibrator;private Context mContext;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//獲得系統的Vibrator實例:myVibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);mContext = MainActivity.this;bindViews();}private void bindViews() {btn_hasVibrator = (Button) findViewById(R.id.btn_hasVibrator);btn_short = (Button) findViewById(R.id.btn_short);btn_long = (Button) findViewById(R.id.btn_long);btn_rhythm = (Button) findViewById(R.id.btn_rhythm);btn_cancle = (Button) findViewById(R.id.btn_cancle);btn_hasVibrator.setOnClickListener(this);btn_short.setOnClickListener(this);btn_long.setOnClickListener(this);btn_rhythm.setOnClickListener(this);btn_cancle.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btn_hasVibrator:Toast.makeText(mContext, myVibrator.hasVibrator() ? "當前設備有振動器" : "當前設備無振動器",Toast.LENGTH_SHORT).show();break;case R.id.btn_short:myVibrator.cancel();myVibrator.vibrate(new long[]{100, 200, 100, 200}, 0);Toast.makeText(mContext, "短振動", Toast.LENGTH_SHORT).show();break;case R.id.btn_long:myVibrator.cancel();myVibrator.vibrate(new long[]{100, 100, 100, 1000}, 0);Toast.makeText(mContext, "長振動", Toast.LENGTH_SHORT).show();break;case R.id.btn_rhythm:myVibrator.cancel();myVibrator.vibrate(new long[]{500, 100, 500, 100, 500, 100}, 0);Toast.makeText(mContext, "節奏振動", Toast.LENGTH_SHORT).show();break;case R.id.btn_cancle:myVibrator.cancel();Toast.makeText(mContext, "取消振動", Toast.LENGTH_SHORT).show();}} }清單文件權限
<uses-permission android:name="android.permission.VIBRATE"/>AlarmManager(鬧鐘服務)
官方API
AlarmManager
相關方法
關鍵參數說明:
示例:一個簡單的定時任務
要說的是,此例子只在Android 4.4以下的系統可行,5.0以上并不可行,后續如果有5.0 以上AlarmManager的解決方案,到時再補上!另外,這里用set方法可能有點不準,如果要 更精確的話可以使用setExtra()方法來設置AlarmManager!
首先一個簡單的布局文件:activity_main.xml,另外在res創建一個raw文件夾,把音頻文件丟進去! 另外創建一個只有外層布局的activity_clock.xml作為鬧鐘響時Activity的布局!
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/LinearLayout1"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><Buttonandroid:id="@+id/btn_set"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="設置鬧鐘" /><Buttonandroid:id="@+id/btn_cancel"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="關閉鬧鐘"android:visibility="gone" /></LinearLayout> public class MainActivity extends AppCompatActivity implements View.OnClickListener{private Button btn_set;private Button btn_cancel;private AlarmManager alarmManager;private PendingIntent pi;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bindViews();}private void bindViews() {btn_set = (Button) findViewById(R.id.btn_set);btn_cancel = (Button) findViewById(R.id.btn_cancel);alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);Intent intent = new Intent(MainActivity.this, ClockActivity.class);pi = PendingIntent.getActivity(MainActivity.this, 0, intent, 0);btn_set.setOnClickListener(this);btn_cancel.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_set:Calendar currentTime = Calendar.getInstance();new TimePickerDialog(MainActivity.this, 0,new TimePickerDialog.OnTimeSetListener() {@Overridepublic void onTimeSet(TimePicker view,int hourOfDay, int minute) {//設置當前時間Calendar c = Calendar.getInstance();c.setTimeInMillis(System.currentTimeMillis());// 根據用戶選擇的時間來設置Calendar對象c.set(Calendar.HOUR, hourOfDay);c.set(Calendar.MINUTE, minute);// ②設置AlarmManager在Calendar對應的時間啟動ActivityalarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), pi);Log.e("HEHE",c.getTimeInMillis()+""); //這里的時間是一個unix時間戳// 提示鬧鐘設置完畢:Toast.makeText(MainActivity.this, "鬧鐘設置完畢~"+ c.getTimeInMillis(),Toast.LENGTH_SHORT).show();}}, currentTime.get(Calendar.HOUR_OF_DAY), currentTime.get(Calendar.MINUTE), false).show();btn_cancel.setVisibility(View.VISIBLE);break;case R.id.btn_cancel:alarmManager.cancel(pi);btn_cancel.setVisibility(View.GONE);Toast.makeText(MainActivity.this, "鬧鐘已取消", Toast.LENGTH_SHORT).show();break;}} }鬧鈴頁面的ClockActivity.java
public class ClockActivity extends AppCompatActivity {private MediaPlayer mediaPlayer;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_clock);mediaPlayer = mediaPlayer.create(this,R.raw.pig);mediaPlayer.start();//創建一個鬧鐘提醒的對話框,點擊確定關閉鈴聲與頁面new AlertDialog.Builder(ClockActivity.this).setTitle("鬧鐘").setMessage("小豬小豬快起床~").setPositiveButton("關閉鬧鈴", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {mediaPlayer.stop();ClockActivity.this.finish();}}).show();} }核心流程
- AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 獲得系統提供的AlarmManager服務的對象
- Intent設置要啟動的組件: Intent intent = new Intent(MainActivity.this, ClockActivity.class);
- PendingIntent對象設置動作,啟動的是Activity還是Service,又或者是廣播! PendingIntent pi = =PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
- 調用AlarmManager的set( )方法設置單次鬧鐘的鬧鐘類型,啟動時間以及PendingIntent對象! alarmManager.set(AlarmManager.RTC_WAKEUP,c.getTimeInMillis(), pi);
另外假如出現鬧鈴無效的話,你可以從這些方面入手:
1.系統版本或者手機,5.0以上基本沒戲,小米,自行百度吧~ 2.ClockActivity有注冊沒?
3.假如你用的是alarmManager發送廣播,廣播再激活Activity的話,則需要為Intent設置一個flag: i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
4. PendingIntent,要寫成getActivity啟動鬧鈴頁面
PowerManager(電源服務)
powermanager
WindowManager(窗口管理服務)
windowmanager
LayoutInflater(布局服務)
layoutinflater
WallpaperManager(壁紙管理器)
wallpapermanager
總結
以上是生活随笔為你收集整理的Android系统服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WebView完全解读
- 下一篇: Activity启动模式完全解读-更新中