安卓权威编程指南 挑战练习(第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学习笔记 ...
随机推荐
- 黑马eesy_15 Vue:04.Vue案例(ssm环境搭建)
黑马eesy_15 Vue:02.常用语法 黑马eesy_15 Vue:03.生命周期 黑马eesy_15 Vue:04.Vue案例(ssm环境搭建) 黑马eesy_15 Vue:04.综合案例(前端 ...
- 牛客-牛牛的Link Power II
题目传送门 sol:可以用线段树来维护,线段树的节点除了标配的$l$和$r$同时记录该区间$link$的个数记为$cnt$,该区间$link$点的和记为$sum$,该区间题目中所谓的能量记为$dis$ ...
- [USACO09OCT]谷仓里的回声Barn Echoes(hush、STL)
https://www.luogu.org/problem/P2957 题目描述 The cows enjoy mooing at the barn because their moos echo b ...
- 17)C++开始--命名空间
命名空间:就是区分同一个名字,在不同的作用域的变量 代码展示 #include<iostream> namespace spaceA{ ; namespace spaceB{ struct ...
- 网络流dinic板子
bool bfs(){ memset(deep,0,sizeof(deep)); queue<int>que; que.push(s); deep[s]=1; while(!que.emp ...
- vue点击复制文本粘贴
<template> <ul> <li> <input type="text" class="inpNone&quo ...
- Fire-Fighting Hero(多源最短路和单源最短路)
题:https://nanti.jisuanke.com/t/41349 分析:对于hero来说,走单源最短路,然后遍历dis数组中的最大值即可找到,对于消防员来说,走多源最短路,只需要建个超级起点连 ...
- js手机浏览器video标签会一直置顶,遮盖住弹出层问题
<video x5-playsinline="" playsinline="" webkit-playsinline="">&l ...
- ajax异步的加深理解
过去印象中的ajax的异步操作,一直还居然在$.ajax函数内部的异步,真是大错特错,实际的异步操作,是针对整个js文件来的. 今天总算意识到了,实际情况如下: $(function(){ //[弹框 ...
- Android开发之《RXJava的简单实现》
import android.util.Log; import rx.Observable; import rx.Subscriber; import rx.functions.Action1; pu ...