安卓权威编程指南 挑战练习(第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学习笔记 ...
随机推荐
- 四十一、LAMP与LNMP加速与缓存优化进阶实战下部
一.配置,在nginx和apache所在的服务器中: 1.配置:cd /application/php/lib/php.ini 1)extension_dir="/application/p ...
- ID3/C4.5/Gini Index
ID3/C4.5/Gini Index */--> ID3/C4.5/Gini Index 1 ID3 Select the attribute with the highest informa ...
- 吴裕雄--天生自然 PYTHON3开发学习:OS 文件/目录方法
import os, sys # 假定 /tmp/foo.txt 文件存在,并有读写权限 ret = os.access("/tmp/foo.txt", os.F_OK) prin ...
- HDU-4614 Vases and Flowers(线段树区间更新+二分查找)
http://acm.hdu.edu.cn/showproblem.php?pid=4614 Time Limit: 4000/2000 MS (Java/Others) Memory Limi ...
- 2019-2020-1 20199324《Linux内核原理与分析》第二周作业
一.知识点总结 1.冯诺依曼体系结构的要点: ①五大基本类型部件:运算器.控制器.存储器.输入设备.输出设备 ②用二进制来表示指令和数据 ③ 核心:存储程序计算机 2.常见的汇编指令 mov指令(l指 ...
- IO概念和五种IO模型
一.什么是IO? 我们都知道unix世界里.一切皆文件.而文件是什么呢?文件就是一串二进制流而已.不管socket.还是FIFO.管道.终端.对我们来说.一切都是文件.一切都是流.在信息交换的过程中. ...
- 网站爬取-案例三:今日头条抓取(ajax抓取JS数据)
今日头条这类的网站制作,从数据形式,CSS样式都是通过数据接口的样式来决定的,所以它的抓取方法和其他网页的抓取方法不太一样,对它的抓取需要抓取后台传来的JSON数据,先来看一下今日头条的源码结构:我们 ...
- C++语言堆栈的详细讲解
本文主要向大家介绍了C++语言堆栈的详细讲解,通过具体的内容向大家展示,希望对大家学习C++语言有所帮助. 一.预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区 ...
- Python opencv PIL numpy base64互相转化
PIL2numpy and numpy2PIL from PIL import Image import numpy image = Image.open('timg.jpeg')# image is ...
- VB.Net制作-历朝通俗演义
原先的回数,全是汉语数字,为此我先转换成了阿拉伯数字,遗憾的是阿拉伯数字100居然排在1和2之前!所以必须设置为3位数字才行!否则顺序是乱的. 以下是用VBA批量重命名的代码: Dim FSO As ...