Perkhidmatan lanjutan


Pengenalan kepada bahagian ini

Dalam bahagian sebelumnya kita telah mempelajari tentang kitaran hayat Perkhidmatan dan dua kaedah memulakan Perkhidmatan. Bahagian ini terus mempunyai pemahaman yang mendalam tentang IntentService dalam Perkhidmatan dan contoh penggunaan Perkhidmatan: Pelaksanaan perkhidmatan latar depan dan tinjauan pendapat!


1 Penggunaan IntentService

Selepas bahagian sebelumnya, kami sudah tahu cara mentakrifkan dan memulakan Perkhidmatan, tetapi jika kami secara langsung. Letakkan benang yang memakan masa dalam kaedah onStart() dalam Perkhidmatan Walaupun anda boleh melakukan ini, ia adalah sangat mudah. Ia akan menyebabkan pengecualian ANR (Application Not Responding), dan rasmi Android diperkenalkan Perkhidmatan mempunyai petikan berikut: Terjemahan langsung:

1 Perkhidmatan bukanlah proses yang berasingan, ia berada dalam proses yang sama seperti penggunaannya
2 benang, yang bermaksud bahawa kita harus mengelak daripada melakukan operasi yang memakan masa dalam Perkhidmatan

Jadi, Android menyediakan kami alternatif untuk menyelesaikan masalah di atas, yang dibincangkan di bawahIntentService; IntentService ialah kelas yang mewarisi Perkhidmatan dan mengendalikan permintaan tak segerak Urutan pekerja mengendalikan operasi yang memakan masa dan rekod Niat yang diminta akan ditambahkan pada baris gilir

Aliran Kerja:

Pelanggan memulakan IntentService melalui startService (Niat) ; Kami tidak perlu mengawal IntentService secara manual Apabila tugasan selesai, IntentService akan berhenti secara automatik. IntentService boleh dimulakan beberapa kali dan setiap operasi yang memakan masa akan diproses dalam IntentService dalam bentuk baris gilir kerja. Dilaksanakan dalam kaedah panggil balik onHandleIntent, dan hanya satu urutan pekerja akan dilaksanakan pada satu masa, dan kemudian dua

Kemudian terdapat demonstrasi kod bandingkan Perkhidmatan dan IntentService, Tentukan masa tidur yang cukup lama, tunjukkan pengecualian ANR bagi Perkhidmatan, dan kemudian tunjukkan betapa baiknya IntentService! Saya tidak akan menunjukkan Perkhidmatan di sini Yang di Internet semuanya adalah Perkhidmatan tersuai, dan kemudian dalam kaedah onStart(). Thread.sleep(20000) kemudian mencetuskan pengecualian ANR Jika anda berminat, anda boleh cuba menulis kod itu sendiri. Di sini saya hanya menunjukkan penggunaan IntentService!

TestService3.java

testService3 kelas awam melanjutkan IntentService {
TAG String akhir peribadi = "hehe";
//Pembina kelas induk mesti dilaksanakan
TestService3() awam
{
super("TestService3");
}

//Kaedah teras yang mesti diatasi
@Override
protected void onHandleIntent(Intent intent) {
//Intent is daripada Activity Sent, membawa parameter pengenalan, melaksanakan tugas yang berbeza mengikut parameter yang berbeza
String action = intent.getExtras().getString("param"); ​​​​
if(action.equals("s1")) Log. i(TAG,"Mulakan perkhidmatan1");
else if(action.equals("s2"))Log.i(TAG,"Mulakan perkhidmatan2"); s3" ))Log.i(TAG,"Mulakan perkhidmatan3"); }catch(InterruptedException e } 🎜> Log.i(TAG,"onBind");
return super.onBind(intent);
}

@Override
public void onCreate() {
Log i(TAG,"onCreate");
super.onCreate();    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.i(TAG,"onStartCommand");  
        return super.onStartCommand(niat, bendera, startId);  
    }  
  
  
    @Override   
    public void setIntentRedelivery(boolean enabled) {  
         super.set  
        Log.i(TAG,"setIntentRedelivery");  
    }  
      
    @Override  
    public void onDestroy() {  
        Log.i(TAG,"onDestroy");  
        super.onDestroy();  
    }  
      
}

Perkhidmatan AndroidManifest.xml注册下

<name="service. android TestService3" android:exported="false">  
    <penapis niat >  
        <action android:name="com.test.intentservice"/>  
    </intent-filter>  
</service>

在MainActivity启动三次服务:

kelas awam MainActivity memanjangkan Aktiviti {  
  
  <          

public class MainActivity melanjutkan Aktiviti {  
  <             <            ct reate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
         Intent it1 = new Intent("com.test.intentservice");  
        Himpunan b1 = Himpunan baharu();  
        b1.putString("param", "s1");  
        it1.putExtras(b1);  
          
         Intent it2 = new Intent("com.test.intentservice");  
        Bundle b2 = baharu Bundle();  
        b2.putString("param", "s2");  
        it2.putExtras(b2);  
          
        Intent it3 = new Intent("com.test.intentservice");  
        Bundle b3 = baharu Bundle();  
        b3.putString("param", "s3");  
        it3.putExtras(b3);  
          
        //接着启动多次IntentService,每次启动,都会新建一个工作 >   /作 罜始终只有一个IntentService实例  
        startService(it1);  
        startService(it2);  
        startService(it3);  
    }  
}
<🎜>

Jalankan tangkapan skrin:

1.jpg

Ringkasan:

Apabila tugas latar belakang perlu dibahagikan kepada beberapa subtugas, dan kemudian dilaksanakan mengikut urutan, subtugas (Ringkasnya, ia adalah operasi tak segerak Pada masa ini, jika kita masih mentakrifkan Perkhidmatan biasa dan kemudian Ia sangat menyusahkan untuk mencipta benang dalam kaedah onStart dan kemudian mengawal benang; Pada masa ini, anda harus menyesuaikan IntentService dan menyelesaikan tugas berkaitan dalam kaedah onHandleIntent()!


2 Aktiviti berkomunikasi dengan Perkhidmatan

Operasi kami sebelum ini adalah untuk memulakan dan menghentikan Perkhidmatan melalui Aktiviti Jika kami memulakan muat turun Perkhidmatan latar belakang, dan kami ingin mengetahui kemajuan tugas muat turun dalam Perkhidmatan! Maka ini pasti memerlukan Perkhidmatan Berkomunikasi dengan Aktiviti, dan medium komunikasi antara mereka ialah kaedah onBind() dalam Perkhidmatan! Kembalikan objek Pengikat tersuai!

Proses asas adalah seperti berikut:

  • 1 Dalam Perkhidmatan tersuai, sesuaikan kelas Binder, dan kemudian tulis semua kaedah yang perlu didedahkan ke dalam kelas ini!
  • 2. Dalam kelas Perkhidmatan, nyatakan kelas Binder tersuai ini, dan kemudian ganti kaedah onBind() untuk mengembalikan objek Binder ini!
  • 3 Semerta objek ServiceConnection dalam kelas Aktiviti, ganti kaedah onServiceConnected() dan kemudian Dapatkan objek Binder dan kemudian panggil kaedah yang berkaitan!

3 Pelaksanaan perkhidmatan bahagian hadapan yang ringkas

Selepas mengetahui sekarang, kita semua tahu bahawa Perkhidmatan biasanya dijalankan kemudian, tetapi keutamaan sistem Perkhidmatan Ia masih agak rendah Apabila memori sistem tidak mencukupi, adalah mungkin untuk mengitar semula Perkhidmatan yang berjalan di latar belakang. Untuk situasi ini, kami boleh menggunakan perkhidmatan latar depan untuk menjadikan Perkhidmatan kurang berkemungkinan dibunuh oleh sistem. Sudah tentu, ia masih boleh dibunuh... Perkhidmatan latar depan yang dipanggil ialah Pemberitahuan yang dipaparkan dalam bar status!

Ia juga sangat mudah untuk dilaksanakan Projek yang saya kerjakan baru-baru ini kebetulan menggunakan perkhidmatan bahagian hadapan ini, jadi saya mencungkil kod teras. Kongsi:

Dalam kelas Perkhidmatan tersuai, tulis semula onCreate(), dan kemudian sesuaikan Pemberitahuan mengikut keperluan anda sendiri; Selepas penyesuaian, hanya hubungi startForeground(1, objek pemberitahuan)! Kod teras adalah seperti berikut:

public void onCreate()
{
    super.onCreate();
    Notification.Builder localBuilder = new Notification.Builder(this);
          LocalBuilder (ini, 0, Niat baharu(ini, MainActivity.class), 0));
    localBuilder.setAutoCancel(false);
    localBuilder.setSmallIcon(R.mipmap.ic_cow_icon. );
(   Ticker. "Perkhidmatan Foreground Start");
    localBuilder.setContentTitle("Socket服务端");
    localBuilder.setContentText("正在运行...");
     start. ;
}

Tangkapan skrin kesan berjalan:

2.png


4. Pelaksanaan urutan latar belakang berjadual ringkas

Selain perkhidmatan bahagian hadapan yang disebutkan di atas, terdapat satu lagi penggunaan Perkhidmatan biasa dalam pembangunan sebenar, iaitu untuk melaksanakan tugas yang dijadualkan. Sebagai contoh, pengundian bermakna meminta pelayan sekali-sekala untuk mengesahkan status pelanggan atau mengemas kini maklumat. tunggu! Terdapat dua kaedah pemasaan yang diberikan kepada kami dalam Android, menggunakan kelas Pemasa dan mekanisme Penggera!

Yang pertama tidak sesuai untuk tugasan berjadual yang perlu dijalankan di latar belakang untuk masa yang lama Setelah CPU tidur, tugasan yang dijadualkan dalam Pemasa Ia tidak boleh dijalankan; Penggera tidak mempunyai keadaan ini. Ia mempunyai fungsi untuk membangunkan CPU. Bangun dengan skrin bangun!

Proses penggunaan:

  • Langkah 1: Dapatkan Perkhidmatan:Pengurus AlarmManager = (AlarmManager) getSystemService( ALARM_SERVICE);
  • Langkah 2: Tetapkan tugas yang dijadualkan melalui kaedah yang ditetapkanint anHour = 2 * 1000; long triggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent);
  • Langkah 3: Tentukan Perkhidmatan dan buka urutan transaksi dalam onStartCommand untuk memproses beberapa logik pemasaan
  • Langkah 4: Tentukan Siaran untuk memulakan PerkhidmatanAkhir sekali, jangan lupa untuk mendaftarkan Perkhidmatan dan Boradcast dalam AndroidManifest.xml!

Butiran parameter: set(jenis int, Masa mula panjang,Pi Intent Tertunda)

①jenis: mempunyai lima nilai pilihan:
AlarmManager.ELAPSED_REALTIME:Jam penggera tidak tersedia apabila telefon sedang tidur Dalam keadaan ini, jam penggera menggunakan masa relatif (berbanding dengan permulaan daripada permulaan sistem), status Nilainya ialah 3;
AlarmManager.ELAPSED_REALTIME_WAKEUPJam penggera akan membangunkan sistem dan melaksanakan fungsi segera dalam keadaan tidur. Dalam keadaan ini, jam penggera juga menggunakan relatif masa dan nilai status ialah 2;
AlarmManager .RTCJam penggera tidak tersedia dalam keadaan tidur Dalam keadaan ini, jam penggera menggunakan masa mutlak, iaitu masa sistem semasa , dan nilai status ialah 1;
AlarmManager.RTC_WAKEUP bermakna jam penggera akan berada dalam keadaan tidur dan melaksanakan fungsi gesaan masa mutlak dan nilai status ialah 0;
AlarmManager.POWER_OFF_WAKEUP bermakna jam penggera juga boleh melaksanakan fungsi gesaan secara normal apabila telefon dimatikan, jadi terdapat 5 Salah satu yang paling biasa digunakan negeri, Dalam keadaan ini, jam penggera juga menggunakan masa mutlak, dan nilai keadaan ialah 4 namun, keadaan ini nampaknya dipengaruhi oleh versi SDK, dan beberapa versi tidak menyokongnya; : Parameter pertama menentukan jenis parameter kedua, jika ia adalah REALTIME, gunakan: Kaedah SystemClock.elapsedRealtime() boleh mendapatkan bilangan milisaat yang telah berlalu sejak sistem dimulakan. Jika RTC, gunakan: System.currentTimeMillis() untuk mendapatkan masa dari 1970.1.1 0 hingga Bilangan milisaat berlalu sekarang

②startTime: Masa pelaksanaan pertama jam penggera, dalam milisaat, masa boleh disesuaikan, tetapi masa semasa biasanya digunakan. Perlu diingatkan bahawa atribut ini berkait rapat dengan atribut pertama (jenis Jika jam penggera sepadan dengan parameter pertama Masa relatif digunakan (ELAPSED_REALTIME dan ELAPSED_REALTIME_WAKEUP), kemudian sifat ini Anda perlu menggunakan masa relatif (berbanding dengan masa permulaan sistem Sebagai contoh, masa semasa dinyatakan sebagai: SystemClock.elapsedRealtime(); Jika jam penggera yang sepadan dengan parameter pertama menggunakan masa mutlak (RTC, RTC_WAKEUP, POWER_OFF_WAKEUP), maka atribut ini mesti menggunakan masa mutlak. Sebagai contoh, masa semasa dinyatakan sebagai: System.currentTimeMillis().

③PendingIntent:Mengikat tindakan pelaksanaan jam penggera, seperti menghantar siaran, memberi peringatan, dsb. PendingIntent Ia ialah kelas enkapsulasi Niat.
Perlu diingat bahawa jika peringatan penggera dilaksanakan dengan memulakan perkhidmatan, Untuk mendapatkan objek PendingIntent, Pending.getService harus digunakan (Konteks c, int i, Intent intent, int j) kaedah
Jika peringatan penggera dilaksanakan melalui penyiaran, Untuk mendapatkan objek PendingIntent, PendingIntent.getBroadcast harus digunakan (Konteks c, int i, Niat niat, int j) kaedah
Jika kaedah Aktiviti digunakan untuk melaksanakan gesaan jam penggera, pemerolehan objek PendingIntent; Anda harus menggunakan PendingIntent.getActivity(Context c,int i,Intent intent,int j) kaedah.
Jika ketiga-tiga kaedah ini digunakan secara tidak betul, walaupun tiada ralat akan dilaporkan, kesan gesaan penggera tidak akan kelihatan.

Selain itu:

Daripada versi 4.4 (API 19), masa mencetuskan tugas Penggera mungkin menjadi tidak tepat dan mungkin tertunda sistem Ya Untuk pengoptimuman penggunaan kuasa, jika anda memerlukan ketepatan, anda boleh memanggil kaedah setExtra()~

Kod teras:

LongRunningService kelas awam melanjutkan Perkhidmatan {
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
​ //Buka thread di sini untuk melaksanakan operasi logik tertentu: public void run() {
Log.d("BackService", new Date() .toString());
}
}).start();
AlarmManager manager = (Alarm Manager) getSystemService(ALARM_SERVICE);
//Ini ditetapkan masa di sini ialah cetak setiap dua saat =-=, tukar sendiri
int anHour = 2 * 1000;
long triggerAtTime = SystemClock() + anHour;
Intent i = new Intent(this,AlarmReceiver.class) ;
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager. ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId) ;
}
}


AlarmReceiver.java

kelas awam AlarmReceiver memanjangkan BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,LongRunningService.class) ;
context.startService(i);
}
}


Ringkasan bahagian ini:

Dalam bahagian ini kami terus mengetahui lebih lanjut tentang Perkhidmatan, IntentService dan Perkhidmatan Dua kes biasa dalam pembangunan sebenar: pelaksanaan Perkhidmatan bahagian hadapan dan latar belakang Perkhidmatan Realisasi Perkhidmatan! Dalam bahagian seterusnya, kami akan terus mengkaji AIDL Perkhidmatan dan komunikasi silang proses. Sila nantikan~


Rujukan: "Barisan Pertama Kod Android" - Guo Lin: Buku pengenalan yang sangat bagus untuk Android!