[解決済み] サービスからAndroidのアクティビティUIを更新する
質問
常に新しいタスクがあるかどうかをチェックするサービスがあります。新しいタスクがある場合、その情報を表示するためにアクティビティUIを更新したいと思います。 私は見つけた https://github.com/commonsguy/cw-andtutorials/tree/master/18-LocalService/ この例を見つけました。これは良いアプローチですか?他の例は?
ありがとうございます。
どのように解決するのですか?
私の元の答えは以下をご覧ください。そのパターンはうまくいっていましたが、最近、私はService/Activityのコミュニケーションに別のアプローチを使い始めました。
- サービス/アクティビティ間の通信に バウンドサービス を使うことで、アクティビティが直接 アクティビティがサービスに対する直接の参照を取得できるようにします。 インテントを使用するのではなく、直接呼び出すことができます。
-
RxJavaを使用して非同期処理を実行します。
-
アクティビティが実行されていないときでも、サービスがバックグラウンドのオペレーションを継続する必要がある場合。 アクティビティが実行されていないときでもバックグラウンドのオペレーションを継続する必要がある場合、アプリケーションクラスからサービスを開始します。 クラスからサービスを開始します。
startService()/LocalBroadcastの手法と比較して、このアプローチで私が見つけた利点は以下の通りです。
- Parcelable を実装するためのデータ オブジェクトが不要 - これは、現在 Android と iOS の間でコードを共有している私にとっては特に重要です (RoboVM を使用)。
- RxJava は定型的な(そしてクロスプラットフォームな)スケジューリングと、シーケンシャルな非同期操作の容易な合成を提供します。
- これは、RxJava を使用するオーバーヘッドがそれを上回るかもしれませんが、LocalBroadcast を使用するよりも効率的であるべきです。
いくつかのサンプルコードです。まずサービスです。
public class AndroidBmService extends Service implements BmService {
private static final int PRESSURE_RATE = 500000; // microseconds between pressure updates
private SensorManager sensorManager;
private SensorEventListener pressureListener;
private ObservableEmitter<Float> pressureObserver;
private Observable<Float> pressureObservable;
public class LocalBinder extends Binder {
public AndroidBmService getService() {
return AndroidBmService.this;
}
}
private IBinder binder = new LocalBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
logMsg("Service bound");
return binder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_NOT_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
if(pressureSensor != null)
sensorManager.registerListener(pressureListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if(pressureObserver != null) {
float lastPressure = event.values[0];
float lastPressureAltitude = (float)((1 - Math.pow(lastPressure / 1013.25, 0.190284)) * 145366.45);
pressureObserver.onNext(lastPressureAltitude);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}, pressureSensor, PRESSURE_RATE);
}
@Override
public Observable<Float> observePressure() {
if(pressureObservable == null) {
pressureObservable = Observable.create(emitter -> pressureObserver = emitter);
pressureObservable = pressureObservable.share();
}
return pressureObservable;
}
@Override
public void onDestroy() {
if(pressureListener != null)
sensorManager.unregisterListener(pressureListener);
}
}
そして、サービスにバインドして気圧高度更新を受信するActivity。
public class TestActivity extends AppCompatActivity {
private ContentTestBinding binding;
private ServiceConnection serviceConnection;
private AndroidBmService service;
private Disposable disposable;
@Override
protected void onDestroy() {
if(disposable != null)
disposable.dispose();
unbindService(serviceConnection);
super.onDestroy();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.content_test);
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
logMsg("BlueMAX service bound");
service = ((AndroidBmService.LocalBinder)iBinder).getService();
disposable = service.observePressure()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(altitude ->
binding.altitude.setText(
String.format(Locale.US,
"Pressure Altitude %d feet",
altitude.intValue())));
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
logMsg("Service disconnected");
}
};
bindService(new Intent(
this, AndroidBmService.class),
serviceConnection, BIND_AUTO_CREATE);
}
}
このActivityのレイアウトは
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.controlj.mfgtest.TestActivity">
<TextView
tools:text="Pressure"
android:id="@+id/altitude"
android:gravity="center_horizontal"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</layout>
もしサービスが Activity に束縛されることなくバックグラウンドで実行される必要がある場合、Application クラスから同様に
OnCreate()
を使って
Context#startService()
.
私のオリジナル回答(2013年から)。
あなたのサービスでは。 (下記の例ではCOPAをサービスにしています)。
LocalBroadCastManagerを使用します。サービスのonCreateで、ブロードキャスターを設定します。
broadcaster = LocalBroadcastManager.getInstance(this);
UIに何かを通知したいとき。
static final public String COPA_RESULT = "com.controlj.copame.backend.COPAService.REQUEST_PROCESSED";
static final public String COPA_MESSAGE = "com.controlj.copame.backend.COPAService.COPA_MSG";
public void sendResult(String message) {
Intent intent = new Intent(COPA_RESULT);
if(message != null)
intent.putExtra(COPA_MESSAGE, message);
broadcaster.sendBroadcast(intent);
}
あなたのアクティビティで
onCreateのリスナーを作成します。
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.copa);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String s = intent.getStringExtra(COPAService.COPA_MESSAGE);
// do something here.
}
};
}
で、onStartに登録します。
@Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver((receiver),
new IntentFilter(COPAService.COPA_RESULT)
);
}
@Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
super.onStop();
}
関連
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] インスタンス状態の保存を使用してアクティビティ状態を保存するにはどうすればよいですか?
-
[解決済み] Androidの「コンテキスト」とは何ですか?
-
[解決済み] Androidのローテーションでアクティビティを再開する
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
-
[解決済み】AndroidサービスがActivityと通信する方法
-
[解決済み] Android - タイトルバーに戻るボタンが表示される
-
[解決済み] Android ConstraintLayout - あるビューを別のビューの上に配置する
-
[解決済み] 非推奨のandroid.support.v4.app.ActionBarDrawerToggleの置き換え方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] CardView layout_width="match_parent "が親のRecyclerViewの幅と一致しない。
-
[解決済み] Androidのソースコードにある@hideの意味とは?
-
[解決済み] EclipseのAndroidプロジェクトにライブラリ/JARを追加する
-
[解決済み] データベースでリサイクルビューを使用する
-
[解決済み] TabLayoutに対応したandroidデザインでタブテキストのフォントを変更する
-
[解決済み] アンドロイドでシェイクを検出するには?
-
[解決済み] AndroidでTextViewの下にアンダーラインを引くには
-
[解決済み] グリッドビューの高さが削減される
-
[解決済み] FABアイコンの色を設定する
-
[解決済み] Recyclerviewと異なるタイプの行のインフレーションの処理