Android入门之IntentService的使用教程详解
TGITCIC 人气:0开篇
在前一篇中我们讲了bindService的使用。并且我们留下了一个念想,即在bindService取值时故意阻塞30秒,引起了一次ANR并引出了今天的章节-IntentService。
IntentService的生命周期中有一个非常好的方法-onHandleIntent方法,它是一个abstract方法,开发者在实现IntentService时可以覆盖它来处理“长事务”。
IntentService
Android开发者官网说过:
- Service不是一个单独的进程,它和它的应用程序在同一个进程中
- Service不是一个线程,这样就意味着我们应该避免在Service中进行耗时操作
于是乎,Android给我们提供了解决上述问题的替代品,就是下面要讲的IntentService; IntentService是继承与Service并处理异步请求的一个类,在IntentService中有 一个工作线程来处理耗时操作,请求的Intent记录会加入队列。
这么神奇?
我们来看演示,如何来验证这个IntentService里的onHandleIntent处理这种长事务。
课程目标
设Service里有一个字符型数组:
private String[] stdNames = new String[]{"小王", "小明", "小张"};
在Activity里输入数组下标后、等待30秒、然后把相对应的数组下标所对应的StudentName显示在Toast里,看看是不是会发生ANR。
该点击动作可以反复点击,因为每次点击后都会执行unbindService。
代码核心设计
IntentService没什么特殊的,它只是extends 自 IntentService,同时它拥有一个可以被覆盖的:onHandleIntent方法。
- 我们这次使用CallBack模式来实现Service里长事务结束后回调activity里的handler实现数值传递;
- 我们使用intent.putExtra来实现activity里的数值传递到service中去;
service注册
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.DemoRealIntentService" tools:targetApi="31"> <service android:name=".LongWaitingService" android:exported="false"></service> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="" /> </activity> </application> </manifest>
Service类-LongWaitingService
package org.mk.android.demorealintentservice; import android.app.IntentService; import android.content.Intent; import android.content.Context; import android.os.IBinder; import android.util.Log; public class LongWaitingService extends IntentService { private final String TAG = "LongWaitingService"; private String[] stdNames = new String[]{"小王", "小明", "小张"}; private Callback callback; private int stdNo; public class StudentBinder extends android.os.Binder { public LongWaitingService getService() { return LongWaitingService.this; } } public void setCallback(Callback callback) { this.callback = callback; } public static interface Callback { void onDataChange(String data); } public LongWaitingService() { super("LongWaitingService"); } @Override public void onStart(Intent intent, int startId) { Log.i(TAG, ">>>>>>onStart"); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { Log.i(TAG, ">>>>>>onHandleIntent"); Log.i(TAG, ">>>>>>into a long waiting"); new Thread() { public void run() { try { Thread.sleep(30000); if (callback != null) { String stdName = stdNames[stdNo]; callback.onDataChange(stdName); } } catch (Exception e) { } } }.start(); } } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. Log.i(TAG, ">>>>>>onBind方法被调用"); this.stdNo = intent.getIntExtra("stdNo", -1); onHandleIntent(intent); return new StudentBinder(); } //Service被关闭前回调 @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, ">>>>>>onDestroyed方法被调用!"); } @Override public boolean onUnbind(Intent intent) { Log.i(TAG,">>>>>>onUnbind"); return false; } }
主类-MainActivity.java
package org.mk.android.demorealintentservice; import androidx.appcompat.app.AppCompatActivity; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private final String TAG = "LongWaitingService"; private Button buttonGetValueFromBinder; private Button buttonClose; private Context ctx; private Intent intent; private LongWaitingService.StudentBinder stdBinder; private EditText etStdNo; Handler stdHandler = new StudentHandler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); buttonGetValueFromBinder = (Button) findViewById(R.id.buttonGetValueFromBinder); etStdNo = (EditText) findViewById(R.id.etStdNo); ctx = MainActivity.this; intent = new Intent(ctx, LongWaitingService.class); buttonGetValueFromBinder.setOnClickListener(new OnClickListener()); } private ServiceConnection conn = new ServiceConnection() { //Activity与Service断开连接时回调该方法 @Override public void onServiceDisconnected(ComponentName name) { Log.i(TAG, ">>>>>>Service DisConnected"); } //Activity与Service连接成功时回调该方法 @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG, ">>>>>>Service Connected"); stdBinder = (LongWaitingService.StudentBinder) service; LongWaitingService stdService = stdBinder.getService(); stdService.setCallback(new LongWaitingService.Callback() { @Override public void onDataChange(String data) { Message msg = new Message(); msg.obj = data; stdHandler.sendMessage(msg); } }); } }; class OnClickListener implements View.OnClickListener { @Override public void onClick(View view) { Intent eIntent; switch (view.getId()) { case R.id.buttonGetValueFromBinder: int stdNo = Integer.valueOf(etStdNo.getText().toString()); intent.putExtra("stdNo", stdNo); bindService(intent, conn, Service.BIND_AUTO_CREATE); break; } } } class StudentHandler extends Handler { @Override public void handleMessage(Message msg) { Log.i(TAG,">>>>>>Service的count" + "的值为:" + msg.obj.toString()); Toast.makeText(getApplicationContext(), "Service的count" + "的值为:" + msg.obj.toString(), Toast.LENGTH_LONG).show(); unbindService(conn); } } }
运行效果
来看看运行效果吧
看,再也没有ANR了,结果成功通过CALL BACK回传Activity。
因此我们一般都会这么使用IntentService来实现一些资源异步加载、第三方API回调。
加载全部内容