<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                **Android四大組件之Service** Android支持服務的概念,服務是在后臺運行的組件,沒有用戶界面,Android服務可用有與活動獨立的生命周期。Android支持兩種類型的服務: **本地服務:** 本地服務只能由承載該服務的應用程序訪問,無法供在設備上運行的其他應用程序訪問。客戶端調用Context.startService()啟動該服務。 **遠程服務:** 遠程服務除了可從承載服務的應用程序訪問,還可以從其他應用程序訪問。遠程服務使用AIDL向客戶端定義。服務支持onBind()方法,客戶端通過Context.bindService()進行調用。 **1)本地服務** **1.1、startService**? 本地服務可由Context.startService()啟動,啟動后這些服務將持續運行,直到客戶端調用Context.stopService()或服務自己調用stopSelf()。 注意:如果調用Context.startService()時還未創建服務,系統將實例化服務并調用服務的onStartCommand()方法。如果在調用Context.startService()時服務已經啟動,那么不會再創建一個實例,而是重新調用正在運行的服務的onStartCommand()方法。 Demo:我們在MainActivity中新建兩個兩個Button,一個用于啟動服務,另外一個用于停止服務。建立一個MyService類繼承于Service,當收到服務的時候在通知欄彈出通知,一直到我們的服務退出才清除通知,同時收到啟動服務的消息時我們建立一個線程sleep 10秒。當我們退出MainActivity的時候停止服務,同時清除通知欄的通知。 MainActivity.xml:就兩個Button用于啟動和停止服務。 ~~~ <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=".MainActivity" > <Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startService" > </Button> <Button android:id="@+id/btnStop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="stopService" android:layout_below="@id/btnStart"> </Button> </RelativeLayout> ~~~ 然后是MainActivity,用于響應Button的單擊事件: ~~~ public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity"; private int counter = 1; private Button btnStart, btnStop; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnStart = (Button)this.findViewById(R.id.btnStart); btnStop = (Button)this.findViewById(R.id.btnStop); btnStart.setOnClickListener(this); btnStop.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub Log.v(TAG, "id:"+v.getId() + "btn:"+R.id.btnStart); switch (v.getId()) { case R.id.btnStart: Log.v(TAG, "Starting Service...counter=" + counter); Intent intent = new Intent(MainActivity.this, MyService.class); intent.putExtra("counter", counter); startService(intent); break; case R.id.btnStop: Log.v(TAG, "Stopping Service..."); if( stopService(new Intent(MainActivity.this, MyService.class)) ) { Log.v(TAG, "stopService successful"); } else { Log.v(TAG, "stopService failed"); } break; default: break; } } @Override protected void onDestroy() { // TODO Auto-generated method stub stopService(new Intent(MainActivity.this, MyService.class)); super.onDestroy(); } } ~~~ 最后是我們的MyService,當收到服務的時候,在通知欄彈出通知,并啟動一個sleep 10秒的線程。 ~~~ public class MyService extends Service { private static final String TAG = "MyService"; private NotificationManager notificationMgr; private ThreadGroup threadGroup = new ThreadGroup("ServiceWorkder"); @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); Log.v(TAG, "in onCreate"); notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); Notification notification = new Notification(R.drawable.ic_launcher, "Service is running", System.currentTimeMillis()); notification.flags = Notification.FLAG_NO_CLEAR; PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0); notification.setLatestEventInfo(this, TAG, "Service is running", intent); notificationMgr.notify(0, notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub super.onStartCommand(intent, flags, startId); int counter = intent.getExtras().getInt("counter"); Log.v(TAG, "in onStartCommand, counter = "+counter+",startId = "+startId); new Thread(threadGroup, new ServiceWorker(counter)).start(); return START_STICKY; } class ServiceWorker implements Runnable { private int counter = -1; public ServiceWorker(int counter) { this.counter = counter; } public void run() { final String TAG = "ServiceWorker" + Thread.currentThread().getId(); try { Log.v(TAG, "Sleeping for 10 seconds.counter="+counter); Thread.sleep(10000); Log.v(TAG, "...waking up"); } catch (Exception e) { // TODO: handle exception Log.v(TAG, "...sleep interrupt"); } } } @Override public void onDestroy() { // TODO Auto-generated method stub Log.v(TAG, "in onDestroy. Interrupt threads and canceling notifications"); threadGroup.interrupt(); notificationMgr.cancelAll(); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } } ~~~ 最后不要忘了在AndroidManifest.xml中聲明我們的Service: ~~~ <service android:name=".MyService"> </service> ~~~ 最后通知欄運行效果如下: ![](https://box.kancloud.cn/2016-05-24_5743f83f25822.jpg) **1.2、bindService** 本地服務也可由Context.bindService()啟動,這樣調用者和服務綁在一起,調用者一旦退出,服務也就終止了。客戶端建立一個與Service連接,使用此連接與Service通信,通過Context.bindService()綁定服務,使用Context.unbindService()關閉服務。多個客戶端可以綁定同一個服務,如果Service未啟動,bindService()可以啟動服務。 注意:上面的startService()和bindService()是完全獨立的兩種模式,你可以綁定一個已經通過startService()啟動的服務。例如:一個后臺播放音樂的服務可以通過startService()啟動播放,然后activity可以通過調用bindService()方法建立于Service的聯系,執行切換歌曲等操作。這種情況下:stopService()不會停止服務,直到最后一個unbindService()調用。 當創建一個能夠提供綁定功能的服務時,我們必須提供一個IBinder對象,客戶端能夠使用這個對象與服務通信,Android中有三種方式: **(1)擴展Binder類** 一般用于服務和Activity屬于同一個進程的情況。類似上面的startService()我們在MainActivity中建立兩個Button,一個用于bindService,另外一個unbindService()。在獲得Service的IBinder接口之后就可以調用Service的內部方法了。 ~~~ public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity"; private boolean isBindFlag = false; private Button btnBind, btnUnbind; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnBind = (Button)this.findViewById(R.id.btnBind); btnUnbind = (Button)this.findViewById(R.id.btnUnbind); btnBind.setOnClickListener(this); btnUnbind.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.btnBind: Intent intent2 = new Intent(MainActivity.this, MyBindService.class); bindService(intent2, serviceConnection, Context.BIND_AUTO_CREATE); break; case R.id.btnUnbind: unbindService(serviceConnection); break; default: break; } } private ServiceConnection serviceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub isBindFlag = false; } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub MyBindService.MyBinder binder = (MyBinder)service; MyBindService bndService = binder.getService(); bndService.myMethod(); isBindFlag = true; } }; @Override protected void onDestroy() { // TODO Auto-generated method stub if(isBindFlag == true) { unbindService(serviceConnection); } super.onDestroy(); } } ~~~ 這里當綁定到MyBindService之后,就可以通過bndService實例調用其方法myMethod()了。下面MyBindService比較簡單就是繼承于Service,并實現其onBind()接口,返回一個MyBinder實例,客戶端拿到這個MyBinder之后可以通過它獲取到MyBindService實例,然后調用其提供的myMethod()方法了。 ~~~ public class MyBindService extends Service { private static final String TAG = "MyBindService"; public void myMethod() { Log.i(TAG, "myBindService->myMethod()"); } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return myBinder; } public class MyBinder extends Binder { public MyBindService getService() { return MyBindService.this; } } private MyBinder myBinder = new MyBinder(); } ~~~ 同理最后我們也需要在AndroidManifest.xml中聲明我們的服務。 **(2)使用Messenger** **(3)Remote Service**也就是我們下面要說的AIDL服務了。 2)AIDL服務? ? 2.1)構建遠程服務 上面介紹的各種服務只能由承載它的應用程序使用,如果想構建可由其他進程通過RPC使用的服務,需要使用IDL來定義向客戶端公開的接口,在Android中這個IDL就稱為AIDL。構建遠程服務的一般步驟為: 1、編寫一個AIDL文件用來向客戶端定義接口。AIDL文件使用Java語法擴展名為.aidl,其內部使用的包名和Android項目使用的包名相同。 首先在項目的src目錄下新建一個IStudentInfo.aidl文件,在AIDL文件中定義服務接口。提供了double getScore(String name)接口,根據給定的String類型的學生姓名,返回一個double類型的分數。 ? ?? ~~~ package com.myAndroid.aidlService; interface IStudentInfoService { double getScore(String name); } ~~~ ? ?? 2、將AIDL文件添加到Eclipse項目的src目錄下,Android Eclipse插件將調用AIDL編譯器從AIDL文件生成Java接口。 生成的java接口文件位于gen/com.myAndroid.aidlService下,名為IStudengInfoService.java: ~~~ /* * This file is auto-generated. DO NOT MODIFY. * Original file: C:\\Documents and Settings\\Administrator\\workspace\\Android使用AIDL創建Service\\src\\com\\myAndroid\\aidlService\\IStudentInfoService.aidl */ package com.myAndroid.aidlService; public interface IStudentInfoService extends android.os.IInterface { /**Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.myAndroid.aidlService.IStudentInfoService { private static final java.lang.String DESCRIPTOR = "com.myAndroid.aidlService.IStudentInfoService"; /**Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.myAndroid.aidlService.IStudentInfoService interface, * generating a proxy if needed. */ public static com.myAndroid.aidlService.IStudentInfoService asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.myAndroid.aidlService.IStudentInfoService))) { return ((com.myAndroid.aidlService.IStudentInfoService)iin); } return new com.myAndroid.aidlService.IStudentInfoService.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_getScore: { data.enforceInterface(DESCRIPTOR); java.lang.String _arg0; _arg0 = data.readString(); double _result = this.getScore(_arg0); reply.writeNoException(); reply.writeDouble(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.myAndroid.aidlService.IStudentInfoService { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public double getScore(java.lang.String name) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); double _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeString(name); mRemote.transact(Stub.TRANSACTION_getScore, _data, _reply, 0); _reply.readException(); _result = _reply.readDouble(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_getScore = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public double getScore(java.lang.String name) throws android.os.RemoteException; } ~~~ 對于所生成的類,注意幾點:在IStudentInfoService中有一個名為IStudentInfoService的接口,實現了IInterface接口。 內部有一個名為Stub的static final 抽象類擴展了android.os.Binder并實現了IStudentInfoService接口。 內部還有一個名為Proxy的static類,實現了IStudentInfoService接口,它是Stub類的代理。? ? ?? 3、實現一個服務并從onBind()方法返回所生成的接口。 要實現服務的接口,需要編寫一個類來擴展android.app.Service并實現IStudentInfoService接口,這個類需要提供onBind()方法將服務向客戶端公開。 ~~~ package com.myAndroid.aidlService; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; public class StudentInfoService extends Service { private static final String TAG = "StudentInfoService"; public class StudentInfoServiceImpl extends IStudentInfoService.Stub { @Override public double getScore(String name) throws RemoteException { // TODO Auto-generated method stub Log.v(TAG, "getScore() called for "+ name); return 85.0; } } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub Log.v(TAG, "onBind called"); return new StudentInfoServiceImpl(); } } ~~~ 從AIDL文件生成的Stub類是抽象類,且實現了IStudentInfoService接口。在我們的服務實現中內部類StudentInfoServiceIml擴展了Stub類,實現了getScore()方法,充當著遠程服務具體實現,當客戶端bind到服務時,返回一個此類的實例。 4、最后將服務配置添加到AndroidManifest.xml文件中 這次我們需要用一個Intent過濾器來公開服務。 ~~~ <service android:name="StudentInfoService"> <intent-filter > <action android:name="com.myAndroid.aidlService.IStudentInfoService"/> </intent-filter> </service> ~~~ 2.2)調用遠程服務 當客戶端與服務通信時,它們之間需要一個協議或契約,在Android中這個協議就是AIDL文件。所以客戶端調用服務的第一步就是獲取服務的AIDL文件并將其復制到客戶端項目中,同理AIDL編譯器會創建一個接口定義公開文件,這個文件與服務器中的文件一樣。 我們創建一個新的Android項目名為 StudentInfoClient,包名為com.myAndroid.studentInfoClient。然后在這個項目下新建一個Java包名為 com.myAndroid.aidlService,并將IStudentInfoService.aidl文件拷貝到當前包下面。 最后我們在MainActivity中通過bindService()獲取服務的引用,然后調用其getScore()方法,即可跟服務端通信。下面給出客戶端源碼: ~~~ package com.myAndroid.studentInfoClient; import com.myAndroid.aidlService.IStudengInfoService; import android.os.Bundle; import android.os.IBinder; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.support.v4.widget.SimpleCursorAdapter.ViewBinder; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import android.widget.ToggleButton; public class MainActivity extends Activity implements View.OnClickListener { private ToggleButton toggleButton; private Button callButton; private IStudengInfoService myService = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); toggleButton = (ToggleButton)this.findViewById(R.id.bindBtn); callButton = (Button)this.findViewById(R.id.callBtn); toggleButton.setOnClickListener(this); callButton.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.bindBtn: if(((ToggleButton)v).isChecked()) { bindService(new Intent(IStudengInfoService.class.getName()), conn, Context.BIND_AUTO_CREATE); } else { unbindService(conn); callButton.setEnabled(false); } break; case R.id.callBtn: callService(); break; default: break; } } private void callService() { try { double val = myService.getScore("Lucy"); Toast.makeText(MainActivity.this, "Value from service is "+ val, Toast.LENGTH_LONG).show(); } catch (Exception e) { // TODO: handle exception } } private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub myService = null; toggleButton.setChecked(false); callButton.setEnabled(false); } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub myService = IStudengInfoService.Stub.asInterface(service); toggleButton.setChecked(true); callButton.setEnabled(true); } }; protected void onDestroy() { if(callButton.isEnabled()) { unbindService(conn); } super.onDestroy(); } } ~~~ 代碼中對于AIDL服務我們需要提供ServiceConnection接口的實現,此接口定義兩個方法:一個供系統建立服務連接時調用,另一個在銷毀服務連接時調用。當建立服務時回調onServiceConnected()方法,我們根據參數service調用IStudengInfoService.Stub.asInterface()獲得服務端的代理,然后調用其相應方法getScore()。 注意:bindService()是異步調用,因為進程或服務可能沒有運行,但是我們不能在主線程上等待服務啟動。當從服務解除綁定時我們不會調用onServiceDisConnected(),只有在服務崩潰時才會調用它。如果調用了它,我們可能需要重寫調用bindService()。 2.3)向服務傳遞復雜類型 注意:AIDL對非原語的支持: 1、AIDL支持String和CharSequence。 2、AIDL支持傳遞其他AIDL接口,但你引用的每個AIDL接口都需要一個import語句。 3、AIDL支持傳遞實現android.os.Parcelable接口的復雜類型。需要在AIDL文件中包含針對這些類型的Import語句。 4、AIDL支持java.util.List和java.util.Map,但是具有一些限制,集合中的項允許數據類型包括Java原語、String、CharSequence和android.os.Parcelable。無需為List和Map提供import語句,但是需要為Parcelable提供。 5、除字符串外。非原語類型需要一個方向指示符。方向指示符包括in、out和inout。in表示由客戶端設置,out表示值由服務設置,inout表示客戶端和服務都設置了該值。 Parcelable接口告訴Android運行時在封送marshalling和解unmarshalling過程中如何序列化和反序列化對象。 ~~~ public class Person implements Parcelable { private int age; private String name; public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { public Person createFromParcel(Parcel in) { return new Person(in); } public Person[] newArray(int size) { return new Person[size]; } }; public Person() { } private Person(Parcel in) { readFromParcel(in); } @Override public int describeContents() { // TODO Auto-generated method stub return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // TODO Auto-generated method stub dest.writeInt(age); dest.writeString(name); } public void readFromParcel(Parcel in) { age = in.readInt(); name = in.readString(); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } } ~~~ Parcelable接口定義在封送/解封送過程中混合和分解對象的契約,Parcelable接口的底層是Parcel容器對象,Parcel類是一種最快的序列號和反序列化機制,專為Android中的進程間通信而設計。 要實現Parcelable接口,需要實現writeToParecl()和readFromParcel()方法。寫入對象到包裹和從包裹中讀取對象,注意:寫入屬性的順序和讀取屬性的順序必須相同。 向Person類添加一個名為CREATOR的static final屬性,該屬性需要實現android.os.Parcelable.Creator<T>接口。 為Parcelable提供一個構造函數,知道如何從Parcel創建對象。 在.aidl文件中我們需要導入該類:import com.myAndroid.aidlService.Person。 ~~~ interface IStudentInfoServie{ ??????????????? String getScore(in String name, in Person requester);??? // 后面非原語類型需要一個方向指示符。 ???? } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看