安卓权威编程指南 挑战练习(第26章 在 Lollipop 设备上使用 JobService)
26.11 挑战练习:在 Lollipop 设备上使用 JobService
请创建另一个 PollService 实现版本。新的 PollService 应该继承 JobService 并使用
JobScheduler 来运行。在 PollService 启动代码中,检查系统版本是否为Lollipop:如果是,就
使用 JobScheduler 计划运行 JobService ;如果不是,依然使用 AlarmManager 实现。
JobService类:
package com.bignerdranch.android.photogallery; import android.app.Notification;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log; import java.util.List; /**
* Created by Leo on 2017/7/22.
*/ public class JobService extends android.app.job.JobService { private static final String TAG = "PollService"; private PollTask mCurrentTask; @Override
public boolean onStartJob(JobParameters parms){ //服务启动后执行
mCurrentTask = new PollTask();
mCurrentTask.execute(parms); //开启AsyncTask
return true;
} @Override
public boolean onStopJob(JobParameters params) {
if(mCurrentTask != null){
mCurrentTask.cancel(true);
}
return false;
} public static void setServiceAlarm(Context context,Boolean shouldStartAlarm){ //Fragment中启动服务需要调用的方法.用于在Fragment启动JobService
final int JOB_ID = 1;
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
if(shouldStartAlarm){
scheduler.cancel(JOB_ID);
}else{
JobInfo jobInfo = new JobInfo.Builder(JOB_ID, new ComponentName(context, JobService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setPeriodic(1000 * 60)
.setPersisted(true)
.build();
scheduler.schedule(jobInfo);
} } //判断是否已经计划好了任务
public static boolean isHasBeenScheduled(Context context){ final int JOB_ID = 1; JobScheduler scheduler = (JobScheduler)context.getSystemService(JOB_SCHEDULER_SERVICE); boolean hasBeenScheduled = false; for (JobInfo jobInfo : scheduler.getAllPendingJobs()) {
if (jobInfo.getId() == JOB_ID) {
hasBeenScheduled = true;
}
} return hasBeenScheduled;
} public JobService(){
super();
} //用于执行
private class PollTask extends AsyncTask<JobParameters,Void ,List<GalleryItem>> {
//在doInBackground()方法中获取到最新的结果集。
@Override
protected List<GalleryItem> doInBackground(JobParameters... params) {
JobParameters jobParams = params[0]; //不需要手动判断网络连接状态了 String query = QueryPreferences.getStoredQuery(JobService.this); //获取查询值 List<GalleryItem> items; //获取最新结果集
if(query == null){
items = new FlickrFetcher().fetchRecentPhotos();
}else{
items = new FlickrFetcher().searchPhotos(query);
} jobFinished(jobParams,false); return items; //将items返回出去, onPostExcute()方法会接受到
} @Override
protected void onPostExecute(List<GalleryItem> items) {
String lastResultId = QueryPreferences.getLastResultId(JobService.this);
//获取第一条结果
String resultId = items.get(0).getId();
//确认是否不同于上一次结果ID ,不同的话弹出Notification。
if(resultId.equals(lastResultId)){
Log.i(TAG, "Got a old result" + resultId);
}else{
Log.i(TAG, "Got a new result" + resultId); Resources resources = getResources();
Intent i = PhotoGalleryActivity.newIntent(JobService.this);
PendingIntent pi = PendingIntent.getActivity(JobService.this,0,i,0); Notification notification = new NotificationCompat.Builder(JobService.this)
.setTicker(resources.getString(R.string.new_pictures_title))
.setSmallIcon(android.R.drawable.ic_menu_report_image)
.setContentTitle(resources.getString(R.string.new_pictures_title))
.setContentText(resources.getString(R.string.new_pictures_text))
.setContentIntent(pi)
.setAutoCancel(true)
.build(); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(JobService.this);
notificationManager.notify(0,notification);
}
//将第一条结果存入SharedPreferences
QueryPreferences.setLastResultId(JobService.this,resultId);
}
}
}
PhotoGalleryFragment类:
onOptionsSelected()方法:
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.menu_item_clear:
QueryPreferences.setStoredQuery(getActivity(),null);
updateItems();
return true;
case R.id.menu_item_toggle_polling:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
boolean shouldStartAlarm = JobService.isHasBeenScheduled(getActivity()); //启动服务
JobService.setServiceAlarm(getActivity(),shouldStartAlarm);
getActivity().invalidateOptionsMenu();
}else{
boolean shouldStartAlarm = !PollService.isServiceAlarmOn(getActivity());
PollService.setServiceAlarm(getActivity(),shouldStartAlarm);
getActivity().invalidateOptionsMenu(); //刷新菜单项 }
return true;
default:
return super.onOptionsItemSelected(item);
}
onCreateOptionsMenu()方法:
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater){
super.onCreateOptionsMenu(menu,menuInflater);
menuInflater.inflate(R.menu.fragment_photo_gallery,menu); MenuItem searchItem = menu.findItem(R.id.menu_item_search); //将MenuItem取出并保存在searchItem变量中。
mSearchView = (SearchView)searchItem.getActionView(); //取出SearchView对象。 //设置监听器
mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {//提交搜索查询时。这个方法执行。
Log.d(TAG, "onQueryTextSubmit: "+ s);
QueryPreferences.setStoredQuery(getActivity(),s); //存储用户提交的查询信息。
updateItems();
hintSoftInputAndSearchField(); //隐藏键盘的方法
return true;
} @Override
public boolean onQueryTextChange(String s) { //搜索框的文字有变化时,这个方法执行。
Log.d(TAG, "onQueryTextChange: " + s);
return false;
}
}); MenuItem toggleItem = menu.findItem(R.id.menu_item_toggle_polling);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
if(JobService.isHasBeenScheduled(getActivity())){
toggleItem.setTitle(R.string.stop_polling);
}else {
toggleItem.setTitle(R.string.start_polling);
}
}else{
if (PollService.isServiceAlarmOn(getActivity())) {
toggleItem.setTitle(R.string.stop_polling);
} else {
toggleItem.setTitle(R.string.start_polling);
}
} mSearchView.setOnSearchClickListener(new View.OnClickListener() { //设置点击按钮时,显示之前搜索过的值
@Override
public void onClick(View v) {
String query = QueryPreferences.getStoredQuery(getActivity());
mSearchView.setQuery(query,false);
}
}); }
安卓权威编程指南 挑战练习(第26章 在 Lollipop 设备上使用 JobService)的更多相关文章
- 安卓权威编程指南 挑战练习 25章 深度优化 PhotoGallery 应用
你可能已经注意到了,提交搜索时, RecyclerView 要等好一会才能刷新显示搜索结果.请接受挑战,让搜索过程更流畅一些.用户一提交搜索,就隐藏软键盘,收起 SearchView 视图(回到只显示 ...
- 安卓权威编程指南 挑战练习 13.8 用于RecyclerView的空视图
当前,CriminalIntent应用启动后,会显示一个空白列表.从用户体验上来讲,即使crime列表 是空的,也应展示提示或解释类信息. 请设置空视图展示类似“没有crime记录可以显示”的信息.再 ...
- 安卓权威编程指南 挑战练习:实现高效RecyclerView刷新
Adapter的notifyDataSetChanged方法会通知RecyclerView刷新全部的可见列表项. 在CriminalIntent应用里,这个方法不够高效,我们知道,返回CrimeLis ...
- 安卓权威编程指南-笔记(第23章 HTTP与后台任务)
1. 网络连接基本 //通过指定URL获取原始数据,并返回一个字节流数组. public byte[] getUrlBytes(String urlSpec)throws IOException{ / ...
- 安卓权威编程指南-笔记(第21章 XML drawable)
在Andorid的世界里,凡事要在屏幕上绘制的东西都可以叫drawable,比如抽象图形,Drawable的子类,位图图形等,我们之前用来封装图片的BitmapDrawable就是一种drawable ...
- 安卓权威编程指南-笔记(第27章 broadcast intent)
本章需求:首先,让应用轮询新结果并在有所发现时及时通知用户,即使用户重启设备后还没有打开过应用.其次,保证用户在使用应用时不出现新结果通知. 1. 一般intent和broadcast intent ...
- 安卓权威编程指南-笔记(第24章 Looper Handler 和 HandlerThread)
AsyncTask是执行后台线程的最简单方式,但它不适用于那些重复且长时间运行的任务. 1. Looper Android中,线程拥有一个消息队列(message queue),使用消息队列的线程叫做 ...
- 安卓权威编程指南-笔记(第22章 深入学习intent和任务)
本章,我们会使用隐式intent创建一个替换android默认启动器的应用.名为NerdLauncher. NerdLauncher应用能列出设备上的其他应用,点选任意列表项会启动相应应用. 1. 解 ...
- 安卓权威编程指南 - 第五章学习笔记(两个Activity)
学习安卓编程权威指南第五章的时候自己写了个简单的Demo来加深理解两个Activity互相传递数据的问题,然后将自己的学习笔记贴上来,如有错误还请指正. IntentActivityDemo学习笔记 ...
随机推荐
- iOS 一个新方法:- (void)makeObjectsPerformSelector:(SEL)aSelector;
NSArray 里面的一个方法, - (void)makeObjectsPerformSelector:(SEL)aSelector: 这是一个类似于执行for循环的方法,可以这样用,当需要删除一个v ...
- 《VSTO开发中级教程》刘永富 著 清华大学出版社 在线购买
现在可以和作者 刘永富 通过“二手书直卖”这个APP直接买书. 二手书直卖 的下载方法: 方法一:加QQ群61840693,群共享中搜索“二手书直卖”,下载后打开即可. 方法二:从本帖下载:二手书直卖 ...
- 迅为iTop开发板使用buildroot构建opencv文件系统
这次我们来介绍使用buildroot构建opencv开发环境,buildroot 是 Linux平台上一个构建嵌入式Linux系统的框架.整个buildroot是由 Makefile脚本和Kconfi ...
- 二十一、NFS服务
文件系统是基于存储设备的,比如硬盘,并且包含文件物理位置的维护.文件系统也可以说是虚拟数据或网络数据存储的方法,比如NFS.我是这样理解的:首先,什么是文件系统,这里我们已经明确了,就是组织的一种形式 ...
- ElasticSearch6 报错blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];
原文连接:https://blog.csdn.net/u013042707/article/details/84110531 方案:curl -XPUT -H "Content-Type: ...
- Excel-DNA自定义函数的参数智能提示功能:ExcelDna.IntelliSense1.1.0.rar
解压缩后,可以看到如下3个文件. ExcelDna.IntelliSense.xll 以及 ExcelDna.IntelliSense64.xll 是两个函数参数智能提示加载项,分别用于32和64位E ...
- android流式布局、待办事项应用、贝塞尔曲线、MVP+Rxjava+Retrofit、艺术图片应用等源码
Android精选源码 android模仿淘宝首页效果源码 一款艺术图片应用,采用T-MVVM打造 Android MVP + RxJava + Retrofit项目 android流式布局实现热门标 ...
- Kafka、RabbitMQ、RocketMQ、ActiveMQ
一.资料文档 Kafka:中.有kafka作者自己写的书,网上资料也有一些.rabbitmq:多.有一些不错的书,网上资料多.zeromq:少.没有专门写zeromq的书,网上的资料多是一些代码的实现 ...
- Springmvc+Mybatis+shiro整合
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序到最大的网络 ...
- jquery框架概览(二)
(function(window, undefined) { })(window) window对象作为参数传进闭包的好处 JavaScript 全局对象.函数以及变量均自动成为 window 对象的 ...