シンプルなAndroid情報のActivityListを持つアプリケーションを作成しようとしています。アプリケーションが起動すると、常にデータを計算する(変更される)サービスを開始する予定です。 ActivityListを、サービスがアプリの存続期間中に計算しているデータと同期させたい。
サービスをリッスンするようにアクティビティを設定するにはどうすればよいですか?これはこの問題に取り組む最良の方法ですか?
たとえば、株価のリストを想像すると、データは定期的に変更され、データを絶えず計算/フェッチしている(私の場合)サービスと同期する必要があります。
前もって感謝します
サービスをリッスンするようにアクティビティを設定するにはどうすればよいですか?これはこの問題に取り組む最良の方法ですか?
私が見るように、あなたには3つの主要な選択肢があります。
ポーリング。 Activity
は定期的にService
に最新のデータを要求します。私見、このオプションはうんざりですが、それは確かに可能です。
コールバック。 jaxの回答に従って、Activity
はService
にコールバックオブジェクト( "observer")を登録します。 Service
は、データが変更されるとコールバックでメソッドを呼び出し、UIを更新します。 Service
here での使用例を見ることができます。
ブロードキャストIntents
。 Service
は、データ変更時にsendBroadcast()
を介してIntent
をブロードキャストします。 Activity
はregisterReceiver()
を使用してBroadcastReceiver
を登録し、そのBroadcastReceiver
に着信ブロードキャストが通知されます。これによりActivity
がトリガーされ、Service
から最新のデータが読み込まれるか、ブロードキャストIntent
のエクストラから最新のデータが取得される可能性があります。 Service
here でこの手法を使用する例を見ることができます。
これはObserverパターンの良い候補のように思えます。基本的に、アクティビティ(The Observer)はバックグラウンドサービス(The Observable)に登録され、アクティビティからデータをプッシュまたはプルできます。この場合のオブザーバーはアクティビティになり、オブザーバブルはサービスになります。
デザインパターンについて何も知らない場合、「Head First Design Patterns」を購入すると、読みやすく、優れた情報が満載です。
PS:私は今それを読んでいます。
どのようなライブラリでも、EventBusを使用した簡単なアプローチについて誰も言及しなかったのはなぜでしょうか。もちろん、これはRXを使用していない場合です。私の個人的なお気に入りは、GreenRobotによるEventBusです。 https://github.com/greenrobot/EventBus
ほんの数行のコードで、インターフェースはありません。イベントを起動して、どこでも好きな場所で聞いてください。分離されており、スレッドセーフであり、アプリをクラッシュさせません。
BindService()を使用して、アクティビティを実行中のサービスにバインドし、通信する必要があります。
public class BindingActivity extends Activity {
YourService mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Bind to Your Service
Intent intent = new Intent(this, YourService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the Android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from your Service.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to the running Service, cast the IBinder and get instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
そしてあなたのサービスのような:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
リストの変更を計算するバックグラウンドスレッドが実行されます。このスレッドには、リストが更新されたことをGUIに通知する機能が必要になりました。
何らかの ArrayAdapter を使用して、データをListViewに取得できます。 ArrayAdapterには adpater.notifyDataSetChanged() というメソッドがあり、このメソッドを呼び出すたびに、アダプターは対応するデータが変更されたことを確認し、次の可能性でリストビューに更新するよう通知します。