Androidサービスローカルリモート概要

41771 ワード

このサービスの総括は比較的に全面的で、悪くないandroidはサービスの入門を編纂します
Android SDKでは、*nixデーモンやwindowsのようなサービスを提供しています.
サービスには2つのタイプがあります.
  • ローカル・サービス(Local Service):アプリケーション内の
  • リモートサービス(Remote Sercie):androidシステム内部のアプリケーション間
  • 前者は、アプリケーションが属するスレッドなどのアプリケーションを占有するのではなく、単一のスレッドバックグラウンドで実行するなど、アップグレード情報のクエリーなど、アプリケーション独自の時間のかかるタスクを実現するために使用されます.これにより、ユーザー体験が向上します.
    後者は、天気予報サービスなどの他のアプリケーションに多重化され、他のアプリケーションはこのようなサービスを書く必要がなく、既存のものを呼び出すことができる.
    Activityと対話する必要のないローカル・サービスの例の作成
    ローカルサービスの作成は簡単です.まず、androidのサービスクラスを継承するサービスクラスを作成します.ここにはカウントサービスのクラスが書かれており、毎秒カウンタに1つ追加されています.サービスクラスの内部には、バックグラウンドで上記のビジネスロジックを実行するためのスレッドも作成されています.
    package com.easymorse;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    
    public class CountService extends Service {
    
        private boolean threadDisable;
    
        private int count;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (!threadDisable) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                        count++;
                        Log.v("CountService", "Count is " + count);
                    }
                }
            }).start();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            this.threadDisable = true;
            Log.v("CountService", "on destroy");
        }
    
        public int getCount() {
            return count;
        }
    
    }

    このサービスをプロファイルAndroidManifestに登録する必要がある.xmlでないと見つかりません:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.easymorse" android:versionCode="1" android:versionName="1.0">
        <application android:icon="@drawable/icon" android:label="@string/app_name">
            <activity android:name=".LocalServiceDemoActivity"
                android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <service android:name="CountService" />
        </application>
        <uses-sdk android:minSdkVersion="3" />
    </manifest> 

    Activityでローカル・サービスを開始および停止します.
    package com.easymorse;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    
    public class LocalServiceDemoActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            this.startService(new Intent(this, CountService.class));
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            this.stopService(new Intent(this, CountService.class));
        }
    }

    バックグラウンドスレッドで印刷されたカウント内容はログで表示できます.
    ローカル・サービスとActivityのインタラクションの作成例
    上記の例はstartServiceとstopServiceによってクローズサービスを開始したものです.サービスとactivityの間にインタラクションが呼び出されていない場合に適用されます.パラメータまたはメソッド呼び出しを渡す必要がある場合.bindメソッドとunbindメソッドを使用する必要があります.
    具体的には、ICountServiceなどのサービスクラスにインタフェースを追加する必要があります.また、サービスクラスには内部クラスが必要です.これにより、外部クラスのカプセル化データにアクセスしやすくなります.この内部クラスはBinderクラスを継承し、ICountServiceインタフェースを実現する必要があります.また、サービスを実現するためのonBindメソッドは、nullを1つだけ返すことはできません.
    これは新しく確立されたインタフェースコードです.
    package com.easymorse;
    
    public interface ICountService {
    
        public abstract int getCount();
    }

    修正後のCountServiceコード:
    package com.easymorse;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    import android.util.Log;
    
    public class CountService extends Service implements ICountService {
    
        private boolean threadDisable;
    
        private int count;
        
        private ServiceBinder serviceBinder=new ServiceBinder();
        
        public class ServiceBinder extends Binder implements ICountService{
            @Override
            public int getCount() {
                return count;
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return serviceBinder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (!threadDisable) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                        count++;
                        Log.v("CountService", "Count is " + count);
                    }
                }
            }).start();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            this.threadDisable = true;
            Log.v("CountService", "on destroy");
        }
    
        /* (non-Javadoc)
         * @see com.easymorse.ICountService#getCount()
         */
        public int getCount() {
            return count;
        }
    
    }

    サービスの登録も変更しなければなりませんAndroidManifest.xmlファイル:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.easymorse" android:versionCode="1" android:versionName="1.0">
        <application android:icon="@drawable/icon" android:label="@string/app_name">
            <activity android:name=".LocalServiceDemoActivity"
                android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <service android:name="CountService">
                <intent-filter>
                    <action android:name="com.easymorse.CountService"/>
                </intent-filter>
            </service>
        </application>
        <uses-sdk android:minSdkVersion="3" />
    </manifest> 

    ActivityコードはstartSerivceとstopServiceによってクローズサービスを開始しなくなりました.また、サービス接続の内部クラス実装によってサービスとActivityを接続する必要があります.
    package com.easymorse;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.util.Log;
    
    public class LocalServiceDemoActivity extends Activity {
    
        private ServiceConnection serviceConnection = new ServiceConnection() {
    
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                countService = (ICountService) service;
                Log.v("CountService", "on serivce connected, count is "
                        + countService.getCount());
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                countService = null;
            }
    
        };
    
        private ICountService countService;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            this.bindService(new Intent("com.easymorse.CountService"),
                    this.serviceConnection, BIND_AUTO_CREATE);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            this.unbindService(serviceConnection);
        }
    }

    基本的なデータを転送するリモート・サービスの作成
    上記の例では、他のアプリケーションがサービスを多重化するように拡張できます.このようなサービスはリモート(remote)サービスと呼ばれ、実際にはプロセス間通信(RPC)である.
    この場合、androidインタフェース記述言語(AIDL)を使用して、上述したような簡単なjavaインタフェースではなく、リモートサービスのインタフェースを定義する必要がある.拡張子はjavaではなくaidlです.上記のICountServiceを使用してICountSerivdeに変更できます.aidl,eclipseは関連javaファイルを自動的に生成します.
    package com.easymorse;
    
    interface ICountService {
        int getCount();
    }

    サービス(Service)クラスを記述するのは、主にbinderではリモートで取得され、杭(Stub)で取得する必要があります.杭オブジェクトは、リモートオブジェクトのローカルエージェントです.
    package com.easymorse;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.util.Log;
    
    public class CountService extends Service {
    
        private boolean threadDisable;
    
        private int count;
    
        private ICountService.Stub serviceBinder = new ICountService.Stub() {
    
            @Override
            public int getCount() throws RemoteException {
                return count;
            }
        };
    
        @Override
        public IBinder onBind(Intent intent) {
            return serviceBinder;
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (!threadDisable) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                        count++;
                        Log.v("CountService", "Count is " + count);
                    }
                }
            }).start();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            this.threadDisable = true;
            Log.v("CountService", "on destroy");
        }
    }
    

    プロファイルAndroidManifest.xmlは上記と似ていて、違いはありません.
    Activityでのサービス使用の違いは大きくなく、ServiceConnectionでリモート・サービスを呼び出す方法が必要な場合に例外をキャプチャします.
    private ServiceConnection serviceConnection = new ServiceConnection() {
    
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            countService = (ICountService) service;
            try {
                Log.v("CountService", "on serivce connected, count is "
                        + countService.getCount());
            } catch (RemoteException e) {
                throw new RuntimeException(e);
            }
        }
    
        @Override
        public void onServiceDisconnected(ComponentName name) {
            countService = null;
        }
    
    };

    これにより、同じアプリケーションでリモート・サービスを使用して、自分で定義したサービスと対話することができます.
    別のアプリケーションがリモートサービスを使用する場合は、上のaidlファイルと対応するパッケージをアプリケーションにコピーし、他の呼び出しなどは同じです.
    複雑なデータ型を転送するリモート・サービスの作成
    リモート・サービスはjavaの基本データ・タイプを渡すだけではありません.この場合androidのいくつかの制限と規定に注意する必要があります.
  • androidサポートStringおよびCharSequence
  • aidlで他のaidlインタフェースタイプを使用する必要がある場合は、同じパケット構造の下でもimportが必要です.
  • androidはParcelableインタフェースを実現するクラスを伝達することを許可し、importが必要である.
  • androidは集合インタフェースタイプListとMapをサポートするが、いくつかの制限があり、要素は基本型または上記の3つの状況でなければならず、import集合インタフェースクラスは必要ないが、要素に関連するタイプimportが必要である.
  • は基本データ型ではなく、StringやCharSequenceタイプでもないので、in、out、inoutを含む方向指示が必要です.inはクライアントによって設定され、outはサービス側によって設定され、inoutは両方とも設定できます.

  • ここでは、前の例で返されたintデータを複雑なデータ型に変更します.
    package com.easymorse;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class CountBean implements Parcelable {
    
        public static final Parcelable.Creator<CountBean> CREATOR = new Creator<CountBean>() {
    
            @Override
            public CountBean createFromParcel(Parcel source) {
                CountBean bean = new CountBean();
                bean.count = source.readInt();
                return bean;
            }
    
            @Override
            public CountBean[] newArray(int size) {
                return new CountBean[size];
            }
    
        };
    
        public int count;
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(this.count);
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
    }

    次に、androidが対応するアシストファイルを生成するために、同じパッケージの下に同じ名前のaidlファイルを作成する必要があります.
    package com.easymorse;
    
    parcelable CountBean;

    このステップはandroid 1.5後の変化であり、adtによってaidlを生成することはできず、例えばグローバルなprojectを使用することもできない.aidlファイル、具体的には:
    http://www.anddev.org/viewtopic.php?p=20991
    次に、サービスのaidlファイルで次のように変更する必要があります.
    package com.easymorse;
    
    import com.easymorse.CountBean;
    
    interface ICountService {
        CountBean getCount();
    }

    他の変更は小さく、CountServiceとCountServiceを呼び出す部分をCountBeanを使用するように変更するだけです.
    変換元:http://marshal.easymorse.com/archives/1564