第15天Service高级
一.IntentService
1.IntentService介绍
IntentService,可以看做是Service和HandlerThread的结合体,在完成了使命之后会自动停止,适合需要在工作线程处理UI无关任务的场景。
- IntentService 是继承自 Service 并处理异步请求的一个类,在 IntentService
内有一个工作线程来处理耗时操作。 - 当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。
- 如果启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的
onHandleIntent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。
2.IntentService的优点:不用开启线程
3.IntentService的缺点:使用广播向activity传值
4.案例:使用IntentService网络请求json串,将json串使用广播发送给activity界面
思路:创建服务,注册服务 ,
(1)创建服务:MyIntentService.java
public class MyIntentService extends IntentService {
//TODO 注意:必须提供无参数构造,不然清单文件中注册报错
public MyIntentService(){
super("MyIntentService");
}
public MyIntentService(String name) {
super(name);
}
//TODO 将所有耗时操作都在该方法中完成,相当于开启线程
@Override
protected void onHandleIntent(@Nullable Intent intent) {
StringBuffer sb=new StringBuffer();
HttpURLConnection connection=null;
InputStream inputStream=null;
try {
URL url=new URL("http://www.qubaobei.com/ios/cf/dish_list.php?stage_id=1&limit=20&page=1");
connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(5*1000);
connection.setConnectTimeout(5*1000);
if(connection.getResponseCode()==200){
inputStream = connection.getInputStream();
byte[] b=new byte[1024];
int len=0;
while((len=inputStream.read(b))!=-1){
sb.append(new String(b,0,len));
}
//TODO 向Activity或Fragment发送json串
Intent intent1=new Intent();
intent1.setAction("com.bawei.intentservice");
Bundle bundle = new Bundle();
bundle.putString("json",sb.toString());
intent1.putExtras(bundle);
sendBroadcast(intent1);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(connection!=null){
connection.disconnect();
}
}
}
}
(2)清单文件注册服务
<service android:name=".Intentservice.MyIntentService" />
(3)Activity代码
public class MainActivity extends AppCompatActivity {
private MyReceiver myReceiver;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册广播
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.bawei.intentservice");
myReceiver=new MyReceiver();
registerReceiver(myReceiver,intentFilter);
//开启服务
intent=new Intent(this,MyIntentService.class);
startService(intent);
}
//解除广播+关闭服务
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
stopService(intent);
}
class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
if("com.bawei.intentservice".equals(action)){
Bundle bundle = intent.getExtras();
String json = bundle.getString("json", "");
//接续json串 展现在ListView 中
Toast.makeText(context, ""+json, Toast.LENGTH_SHORT).show();
}
}
}
}
二.前台服务Foreground Service
1.什么是前台服务
前台服务是那些被认为用户知道(用户所认可的)且在系统内存不足的时候不允许系统杀死的服务。前台服务必须给状态栏提供一个通知,它被放到正在运行(Ongoing)标题之下——这就意味着通知只有在这个服务被终止或从前台主动移除通知后才能被解除。
2.为什么使用
在一般情况下,Service几乎都是在后台运行,一直默默地做着辛苦的工作。但这种情况下,后台运行的Service系统优先级相对较低,当系统内存不足时,在后台运行的Service就有可能被回收。
那么,如果我们希望Service可以一直保持运行状态且不会在内存不足的情况下被回收时,可以选择将需要保持运行的Service设置为前台服务。
3.如何实现
本文按照做音乐播放器的思路,做一下相关的说明,如何使用前台服务。
(1)首先要创建一个服务:
public class MusicPlayerService extends Service {
private static final String TAG = MusicPlayerService.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind()");
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
(2)在Service的onStartCommand中添加如下代码
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
// 在API11之后构建Notification的方式
Notification.Builder builder = new Notification.Builder
(this.getApplicationContext()); //获取一个Notification构造器
Intent nfIntent = new Intent(this, MainActivity.class);
builder.setContentIntent(PendingIntent.
getActivity(this, 0, nfIntent, 0)) // 设置PendingIntent
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
R.mipmap.ic_large)) // 设置下拉列表中的图标(大图标)
.setContentTitle("下拉列表中的Title") // 设置下拉列表里的标题
.setSmallIcon(R.mipmap.ic_launcher) // 设置状态栏内的小图标
.setContentText("要显示的内容") // 设置上下文内容
.setWhen(System.currentTimeMillis()); // 设置该通知发生的时间
Notification notification = builder.build(); // 获取构建好的Notification
notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
}
(3)在完成Notification通知消息的构建后,在Service的onStartCommand中可以使用startForeground方法来让Android服务运行在前台
// 参数一:唯一的通知标识;参数二:通知消息。
startForeground(110, notification);// 开始前台服务
(4)如果需要停止前台服务,可以使用stopForeground来停止正在运行的前台服务。
@Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
stopForeground(true);// 停止前台服务--参数:表示是否移除之前的通知
super.onDestroy();
}