先進的なサービス


このセクションの概要

前のセクションでは、サービスのライフサイクルとサービスを開始する 2 つの方法について学びました。 このセクションでは、サービスの IntentService とサービスの使用例について引き続き詳しく説明します。 フロントエンド サービスとポーリングの実装


1. IntentService の使用

前のセクションの後、Service を定義して開始する方法はすでにわかりました。 時間のかかるスレッドを Service の onStart() メソッドに配置することもできますが、これは非常に簡単です。 ANR例外(Application Not Responding)が発生し、Android正式導入 サービスには次のような文章があります: 直訳:

1. サービスは別個のプロセスではなく、アプリケーションと同じプロセス内にあります。
2. サービスはスレッドではないため、時間のかかる実行は避けるべきです。 Service での操作

そこで、Android は上記の問題を解決するための代替手段を提供します。それが、以下で説明する IntentService です。 IntentServiceはServiceを継承して非同期リクエストを扱うクラスがあります。 ワーカー スレッドは時間のかかる操作を処理し、要求された Intent レコードがキューに追加されます

ワークフロー:

クライアントは startService(Intent) を通じて IntentService を開始します。 IntentService を手動で制御する必要はありません。タスクが完了すると、IntentService は自動的に停止します。 IntentService は複数回開始でき、時間のかかる各操作はワーク キューの形式で IntentService 内で処理されます。 これは onHandleIntent コールバック メソッドで実行され、一度に 1 つのワーカー スレッドのみが実行されます。次に、インターネット上のほとんどのコードで Service と IntentService を比較します。 。 十分な長さのスリープ時間を定義し、サービスの ANR 例外を実証し、IntentService がどれほど優れているかを示します。 ここではサービスのデモは行いません。インターネット上のサービスはすべてカスタマイズされたサービスであり、onStart() メソッド内にあります。 Thread.sleep(20000) は、ANR 例外をトリガーします。興味がある場合は、自分でコードを書いてみることができます。 ここでは、IntentService の使用法のみを説明します。

TestService3.java

public class TestService3 extends IntentService {
privatefinal String TAG = "hehe"
//親クラスのコンストラクターを実装する必要があります
public TestService3()
{
super("Test Service3") }

; //必須オーバーライドされたコアメソッド
@Override
protected void onHandleIntent(Intenttent) {
//インテントはアクティビティから送信され、識別パラメータを運び、異なるパラメータに従って異なるタスクを実行します
String action =tent.getExtras().getString ( "param"); if( "s1")log.i( "Start Service1"); ))Log.i(TAG,"サービスの開始 3");
(} Catch (InterruptedException E) {e.printstacktrace ();}}} // メソッドの呼び出し順序を書き換える
@
public ibinder Onbind G.I (TAG,
) をオーバーライドします。タグ、「onBind」); super.onCreate();
    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand");  
return super.onStartCommand(intent, flags, startId);  
}


@Override
public void setIntentRedelivery(boolean enabled) {
super.setIntentRedelivery(enabled);  
Log.i(TAG,"setIntentRedelivery");  
}

@Override
public void onDestroy() {
Log.i(TAG,"onDestroy");  
super.onDestroy();  
}

}

AndroidManifest.xml注册下Service

<service android:name=".TestService3" android:exported="false">  
<インテントフィルター >  
<action android:name="com.test.intentservice"/>  
</intent-filter>  
</サービス>

在MainActivity启アニメーション三次服务:

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);  
setContentView(R.layout.activity_main);  

Intent it1 = new Intent("com.test.intentservice");  
バンドル b1 = 新しい バンドル();  
b1.putString("param", "s1");  
it1.putExtras(b1);  

Intent it2 = new Intent("com.test.intentservice");  
バンドル b2 = 新しい バンドル();  
b2.putString("param", "s2");  
it2.putExtras(b2);  

Intent it3 = new Intent("com.test.intentservice");  
バンドル b3 = 新しい バンドル();  
b3.putString("param", "s3");  
it3.putExtras(b3);  

//次启アニメーション多次IntentService,每次启アニメーション, 都市新建一工作線程
//但開始终只有一个IntentService实例
startService(it1);  
startService(it2);  
startService(it3);  
}
}

実行中のスクリーンショット:

1.jpg

概要:

バックグラウンドタスクを複数のサブタスクに分割し、順番に実行する必要がある場合、サブタスクは (簡単に言えば、これは非同期操作です) この時点では、まだ通常の Service を定義しているとします。 onStart メソッドでスレッドを開いてからそのスレッドを制御するのは非常に面倒です。 現時点では、IntentService をカスタマイズし、onHandleIntent() メソッドで関連タスクを完了する必要があります。


2.アクティビティはサービスと通信します

これまでの操作は、ダウンロードを開始する場合、アクティビティを通じてサービスを開始および停止することです。 バックグラウンド サービス。サービス内のダウンロード タスクの進行状況を知りたいのです。それなら、これは間違いなくサービスが必要です Activity と通信します。Activity 間の通信媒体は、Service の onBind() メソッドです。 カスタム Binder オブジェクトを返します。

基本的なプロセスは次のとおりです:

  • 1. カスタム サービスで、Binder クラスをカスタマイズし、このクラスに公開する必要があるすべてのメソッドを記述します。
  • 2. Service クラスでカスタム Binder クラスをインスタンス化し、onBind() メソッドをオーバーライドして Binder オブジェクトを返します。
  • 3. Activity クラスで ServiceConnection オブジェクトをインスタンス化し、onServiceConnected() メソッドをオーバーライドします。 Binder オブジェクトを取得して、関連するメソッドを呼び出します。

3. 単純なフロントエンドサービスの実装

ここまでで、Service は一般に後で実行されることを誰もが知っていますが、Service のシステム優先度は システム メモリがまだ比較的少ない場合は、バックグラウンドで実行されているサービスを再利用することができます。 この状況では、フォアグラウンド サービスを使用して、サービスがシステムによって強制終了される可能性をわずかに低くすることができます。 もちろん、殺される可能性もあります...いわゆるフォアグラウンド サービスは、ステータス バーに表示される通知です。

実装も非常に簡単です。私が最近取り組んだプロジェクトではたまたまこのフロントエンド サービスを使用していたので、コア コードを掘り出しました。 共有:

カスタム Service クラスで、onCreate() を書き直し、独自のニーズに応じて通知をカスタマイズします。 カスタマイズ後は、startForeground(1, notification object) を呼び出すだけです。 コアコードは次のとおりです:

public void onCreate()
{
super.onCreate();
Notification.Builder localBuilder = new Notification.Builder(this);
localBuilder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity. class), 0));
localBuilder.setAutoCancel(false);
localBuilder.setSmallIcon(R.mipmap.ic_cow_icon);
localBuilder.setTicker("Foreground Service Start");
localBuilder.setContentTitle("Socketサービス务端") ;
localBuilder.setContentText("正在运行...");
startForeground(1, localBuilder.getNotification());
}

実行中のエフェクトのスクリーンショット:

2.png


4. スケジュールされた単純なバックグラウンド スレッドの実装

上記のフロントエンド サービスに加えて、実際の開発ではサービスの一般的な使用法もあります。つまり、スケジュールされたタスクを実行します。 たとえば、ポーリングとは、クライアントのステータスを確認したり、情報を更新したりするために、サーバーに時々要求することを意味します。 待って! Android には、Timer クラスと Alarm メカニズムを使用する 2 つのタイミング メソッドが提供されています。

前者は、CPU がスリープ状態になると、タイマーでスケジュールされたタスクが長時間バックグラウンドで実行される必要があるスケジュールされたタスクには適していません。 この状況ではアラームは実行できません。また、CPU をウェイクアップする機能もあります。 画面ウェイクアップで目覚めます!

使用プロセス:

  • ステップ 1: サービスの取得:AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
  • ステップ 2: set メソッドを通じてスケジュールされたタスクを設定しますint anHour = 2 * 1000; 長いtriggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent);
  • ステップ 3: サービスを定義します onStartCommand でトランザクション スレッドを開き、タイミング ロジックを処理します
  • ステップ 4: サービスの開始に使用されるブロードキャストを定義します最後に、Service と Boradcast を AndroidManifest.xml に登録することを忘れないでください。

パラメータの詳細: set(int type, long startTime, PendingIntent pi)

①type:には5つのオプションの値があります:
AlarmManager.ELAPSED_REALTIME:電話がかかっているときは目覚まし時計は使用できませんスリープ状態です。この状態では、目覚まし時計は相対時間を使用し (システムの起動開始を基準とした)、状態値は 3;
AlarmManager.ELAPSED_REALTIME_WAKEUP 目覚まし時計はシステムをウェイクアップし、スリープ中にプロンプ​​ト機能を実行します。この状態では、目覚まし時計は相対時間を使用します。ステータス値は 2 です。この状態では、目覚まし時計は絶対時間を使用します。 、現在のシステム時刻。
AlarmManager.RTC_WAKEUP は、システムをウェイクアップしてプロンプト機能を実行することを意味します。時刻とステータス値が 0 の場合、
AlarmManager.POWER_OFF_WAKEUP は、電話の電源がオフのときにも目覚まし時計がプロンプト機能を正常に実行できることを意味するため、5 つの状態の中で最もよく使用されます。 この状態では、目覚まし時計も絶対時間を使用し、状態値は 4 ですが、この状態は SDK バージョンの影響を受けるようで、一部のバージョンはそれをサポートしていません。 2 番目のパラメータのタイプ (REALTIME の場合) その場合は、次を使用します。 SystemClock.elapsedRealtime() メソッドは、システムが起動してから経過したミリ秒数を取得できます。 RTC の場合は、System.currentTimeMillis() を使用して、1970.1.1 0 から 1970.1.1 までの時刻を取得します。 現在経過したミリ秒数

②startTime: 目覚まし時計の最初の実行時間 (ミリ秒単位) 時間はカスタマイズできますが、通常は現在の時間が使用されます。 この属性は、最初のパラメータに対応する目覚まし時計の場合、最初の属性 (タイプ) と密接に関連していることに注意してください。 相対時間が使用される場合 (ELAPSED_REALTIME および ELAPSED_REALTIME_WAKEUP)、このプロパティ たとえば、現在時刻は次のように表されます。 SystemClock.elapsedRealtime(); 最初のパラメータに対応する目覚まし時計が絶対時間を使用する場合 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP)、この属性は絶対時間を使用する必要があります。 たとえば、現在時刻は System.currentTimeMillis() のように表されます。

③PendingIntent:ブロードキャストの送信、リマインダーの提供など、目覚まし時計の実行アクションをバインドします。保留中の意図 Intentのカプセル化クラスです。
なお、サービスを起動してアラームリマインダーを実装した場合、 PendingIntent オブジェクトを取得するには、Pending.getService を使用する必要があります。 (Context c, int i, Intent 意図, int j) メソッド
アラームリマインダーがブロードキャストを通じて実装される場合、 PendingIntent オブジェクトを取得するには、PendingIntent.getBroadcast を使用する必要があります。 (Context c, int i, Intenttent, int j) メソッド
目覚まし時計プロンプトの実装に Activity メソッドが使用されている場合、PendingIntent オブジェクトの取得 PendingIntent.getActivity(Context c,int i,Intenttent,int j) を使用する必要があります。 方法。
これら 3 つの方法が間違って使用された場合、エラーは報告されませんが、アラーム プロンプトの効果は表示されません。

さらに:

バージョン4.4 (API 19) 以降、アラームタスクのトリガー時間が不正確になり、遅延する可能性があります。これはシステムによるものです。 消費電力を最適化するために、精度が必要な場合は setExtra() メソッドを呼び出すことができます~

コアコード:

publicクラスLongrunningServiceはサービスを拡張します{
@Override
Public Ibinder onbind(意図意図){
} @Override
Public Int onstartCommand(Intent Intent、Int Flags、Int Startid){特定の論理演算を実行します:
use use using using using use using using using using 's' using using using using using out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out out使用している 使用している 持っている 持っている 持っている 持っている 訴訟を起こしている に関して、
AlarmManager を開始します。マネージャー = (アラームマネージャー) getSystemService (Alarm_service);
// ここでは時間を計測し、2 秒ごとに時刻を出力するように設定します =-= 2 * 1000;
longtriggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this,AlarmReceiver) .class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i , 0);
manager. set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime, pi); 、インテント Intent) {
INTENT I = 新しいインテント (Context, LongrunningService.class) }

;

このセクションの概要:

このセクションでは、Service、IntentService、および Service について引き続き学習します。 実際の開発でよくある 2 つのケース: フロントエンド サービスの実装とサービスのバックグラウンド サービスの実現!次のセクションでは、Service の AIDL とクロスプロセス通信について引き続き学習していきます。 お楽しみに~


参考: 「The First Line of Code Android」 - Guo Lin: Android の非常に優れた入門書です!