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)的更多相关文章

  1. 安卓权威编程指南 挑战练习 25章 深度优化 PhotoGallery 应用

    你可能已经注意到了,提交搜索时, RecyclerView 要等好一会才能刷新显示搜索结果.请接受挑战,让搜索过程更流畅一些.用户一提交搜索,就隐藏软键盘,收起 SearchView 视图(回到只显示 ...

  2. 安卓权威编程指南 挑战练习 13.8 用于RecyclerView的空视图

    当前,CriminalIntent应用启动后,会显示一个空白列表.从用户体验上来讲,即使crime列表 是空的,也应展示提示或解释类信息. 请设置空视图展示类似“没有crime记录可以显示”的信息.再 ...

  3. 安卓权威编程指南 挑战练习:实现高效RecyclerView刷新

    Adapter的notifyDataSetChanged方法会通知RecyclerView刷新全部的可见列表项. 在CriminalIntent应用里,这个方法不够高效,我们知道,返回CrimeLis ...

  4. 安卓权威编程指南-笔记(第23章 HTTP与后台任务)

    1. 网络连接基本 //通过指定URL获取原始数据,并返回一个字节流数组. public byte[] getUrlBytes(String urlSpec)throws IOException{ / ...

  5. 安卓权威编程指南-笔记(第21章 XML drawable)

    在Andorid的世界里,凡事要在屏幕上绘制的东西都可以叫drawable,比如抽象图形,Drawable的子类,位图图形等,我们之前用来封装图片的BitmapDrawable就是一种drawable ...

  6. 安卓权威编程指南-笔记(第27章 broadcast intent)

    本章需求:首先,让应用轮询新结果并在有所发现时及时通知用户,即使用户重启设备后还没有打开过应用.其次,保证用户在使用应用时不出现新结果通知. 1. 一般intent和broadcast intent ...

  7. 安卓权威编程指南-笔记(第24章 Looper Handler 和 HandlerThread)

    AsyncTask是执行后台线程的最简单方式,但它不适用于那些重复且长时间运行的任务. 1. Looper Android中,线程拥有一个消息队列(message queue),使用消息队列的线程叫做 ...

  8. 安卓权威编程指南-笔记(第22章 深入学习intent和任务)

    本章,我们会使用隐式intent创建一个替换android默认启动器的应用.名为NerdLauncher. NerdLauncher应用能列出设备上的其他应用,点选任意列表项会启动相应应用. 1. 解 ...

  9. 安卓权威编程指南 - 第五章学习笔记(两个Activity)

    学习安卓编程权威指南第五章的时候自己写了个简单的Demo来加深理解两个Activity互相传递数据的问题,然后将自己的学习笔记贴上来,如有错误还请指正. IntentActivityDemo学习笔记 ...

随机推荐

  1. Linux 使用rpm方式安装最新mysql(5.7)步骤以及常见问题解决

    第一步:下载rpm包 mysql官网下载:http://dev.mysql.com/downloads/mysql/ 但如果你的下载网速不好的话也可以点下面的链接下载自己想要的版本 http://mi ...

  2. Opencv笔记(二十)——直方图(二)

    直方图均衡化 原理: 想象一下如果一副图像中的大多是像素点的像素值都集中在一个像素值范围之内会怎样呢?例如,如果一幅图片整体很亮,那所有的像素值应该都会很高.但是一副高质量的图像的像素值分布应该很广泛 ...

  3. linux 添加常用长命令别名

    ## 设置linux下常用命令别名,提高效率 将要使用的命令别名写入到~/.bashrc文件,通过source ~/.bashrc命令使变更生效 alias sst='systemctl status ...

  4. [LC] 1048. Longest String Chain

    Given a list of words, each word consists of English lowercase letters. Let's say word1 is a predece ...

  5. AC和路由器

    无线AC控制器是一种网络设备,比如我曾接触过的丰润达的AC100和AC180等,用它们可以来集中控制和管理无线AP,比如下发配置.修改相关配置参数.射频智能管理.接入安全控制等. 路由器是一种连接多个 ...

  6. android studio 通过界面快速查看md5

    https://www.jianshu.com/p/989c0be557f0

  7. jsonConfig用法

    1.先编写jsonConfig的初始化代码 private JsonConfig jsonConfig; public action构造方法() { jsonConfig = new JsonConf ...

  8. SMTP错误码/建议解决方法

    SMTP错误码/建议解决方法 错误总表 420 1. Timeout Communication Problem Encountered During Transmission. Thie Is a ...

  9. [LC] 557. Reverse Words in a String III

    Given a string, you need to reverse the order of characters in each word within a sentence while sti ...

  10. 【Linux_Shell 脚本编程学习笔记六、shell的数值运算】

    1.bc 命令的用法(可以整数也可以小数): bc是 UNIX下的计算器,它也可以用在命令行下面: 例: 给自变量 i 加 1 [root@docker Demo_test]# i= [root@do ...