Android

Java安卓学习总结(三十二)

第二十八章 后台服务

有关IntentService

IntentService服务能够按照顺序执行命令队列里面的命令,这些命令就是IntentService服务需要响应(onHandleIntent)的intent。需要声明这个元素节点:

<service android:name=".PollService"/>

有关后台网络连接安全

在后台连接网络时,需要使用ConnectivityManager确认网络连接是否可用,首先获取权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

然后根据网络服务是否可用(connectivityManager.getActiveNetworkInfo())、网络是否连得上(connectivityManager.getActiveNetworkInfo().isConnected())来确定是否应该启用服务:

@Override
protected void onHandleIntent(@Nullable Intent intent) {
    
    if (!isNetworkAvailableAndConnected())
    {
        return;
    }
   ...
}

private boolean isNetworkAvailableAndConnected()
{
    ConnectivityManager connectivityManager=(ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);

    boolean isNetWorkAvailable=connectivityManager.getActiveNetworkInfo()!=null;
    boolean isNetworkConnected=isNetWorkAvailable&&connectivityManager.getActiveNetworkInfo().isConnected();

    return isNetworkConnected;
}

有关使用AlarmManager延迟运行服务

PendingIntent打包

PendingIntent.getService()方法打包了一个Context.startService(Intent)方法的调用:

Intent i=PollService.newIntent(context);
PendingIntent pendingIntent=PendingIntent.getService(context,0,i,0);

这个方法有四个参数,第一个是用来发送intent的context,第二个是区分PendingIntent来源的请求码,第三个是待发送的Intent对象,第四个是如何创建PendingIntent的标识符。第四个参数的一个例子如下:

Intent intent=PollService.newIntent(context);
PendingIntent pendingIntent=PendingIntent.getService(context,0,intent, PendingIntent.FLAG_NO_CREATE);

PendingIntent.FLAG_NO_CREATE实际上并不做的发送这个任务,它只是用以判断定时器的启停状态。

AlarmManager定时

AlarmManager.setRepeating()方法是设置定时器,这个方法也有四个参数,第一个是描述定时器事件基准的常量,第二个是定时器启动的时间,第三个是定时器循环的时间间隔,第四个是要发送的PendingIntent。

AlarmManager alarmManager=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);

alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(),POLL_INTERVAL_MS,pendingIntent);

取消定时器是AlarmManager.cancel(),参数就是要取消的PendingIntent:

alarmManager.cancel(pendingIntent);

有关通知信息

想要发送通知消息,首先要创建Notification对象,可以用构造器来创建,完整的Notification需要有:tick text、图标、通知信息本身,待触发的PendingIntent。

Notification notification=new NotificationCompat.Builder(this)
.setTicker(resources.getString(R.string.new_pictures_titles))
.setSmallIcon(android.R.drawable.ic_menu_report_image)
.setContentTitle(resources.getString(R.string.new_pictures_titles))
.setContentText(resources.getString(R.string.new_picture_text))
.setContentIntent(pi)
.setAutoCancel(true)
.build();

发送通知信息需要调用NotificationManager的notify方法,构造NotificationManager的方式是从当前的context中取出有关NotificationManagerCompat实例:

Notification notification=new NotificationCompat.Builder(this)
.setTicker(resources.getString(R.string.new_pictures_titles))
.setSmallIcon(android.R.drawable.ic_menu_report_image)
.setContentTitle(resources.getString(R.string.new_pictures_titles))
.setContentText(resources.getString(R.string.new_picture_text))
.setContentIntent(pi)
.setAutoCancel(true)
.build();

NotificationManagerCompat notificationManager= NotificationManagerCompat.from(this);
notificationManager.notify(0,notification);

有关挑战练习 在Lollipop设备上使用JobService

我原先误解了这个题设的意思,我以为是在onStartJob方法中选择启动的方式,导致我卡了很长的时间都没有解决方案。参考了网上的解法之后,我发现挑战练习之前的介绍就是实现的这一题的过程。

public class PollJobService extends JobService:

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PollJobService extends JobService {
private PollTask mCurrentTask;
private static final String TAG="PollJobService";



@Override
public boolean onStartJob(JobParameters jobParameters) {

mCurrentTask=new PollTask();
mCurrentTask.execute(jobParameters);
return true;
}

private class PollTask extends AsyncTask<JobParameters,Void,Void>
{
@Override
protected Void doInBackground(JobParameters... jobParameters) {
JobParameters jobParams=jobParameters[0];

PollFilckr();

jobFinished(jobParams,false);
return null;
}
}

@Override
public boolean onStopJob(JobParameters jobParameters) {
if (mCurrentTask!=null)
{
mCurrentTask.cancel(true);
}
return true;
}

public static void setServiceAlarm(Context context, boolean shouldStartAlarm)
{
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*15)
.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;
}


private void PollFilckr()
{
String query=QueryPreferences.getStoredQuery(PollJobService.this);
String lastResultId=QueryPreferences.getPrefLastResultId(PollJobService.this);
List<GalleryItem> items;

if (query==null)
{
items=new FlickrFetchr().fetchRecentPhotos(1);
}
else
{
items=new FlickrFetchr().searchPhotos(query);
}

if (items.size()==0)
{
return;
}

String resultId=items.get(0).getID();
if (resultId.equals(lastResultId))
{
Log.i(TAG,"Got an old result: "+resultId);
}
else {
Log.i(TAG,"Got a new result: "+resultId);

Resources resources=getResources();
Intent i=PhototGalleryActivity.newIntent(PollJobService.this);//就是一个context
PendingIntent pi=PendingIntent.getActivity(PollJobService.this,0,i,0);

Notification notification=new NotificationCompat.Builder(PollJobService.this)
.setTicker(resources.getString(R.string.new_pictures_titles))
.setSmallIcon(android.R.drawable.ic_menu_report_image)
.setContentTitle(resources.getString(R.string.new_pictures_titles))
.setContentText(resources.getString(R.string.new_picture_text))
.setContentIntent(pi)
.setAutoCancel(true)
.build();

NotificationManagerCompat notificationManager= NotificationManagerCompat.from(PollJobService.this);
notificationManager.notify(0,notification);
}

QueryPreferences.setPrefLastResultId(PollJobService.this,resultId);
}
}

在fragment中的菜单项目中选择使用的服务:

@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.fragment_photo_gallery,menu);

MenuItem searchItem=menu.findItem(R.id.menu_item_search);
final SearchView searchView=(SearchView)searchItem.getActionView();

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
Log.i(TAG,"QueryTextSumbit: "+s);
QueryPreferences.setStoredQuery(getActivity(),s);
updateItems();

searchView.onActionViewCollapsed();
return true;
}

@Override
public boolean onQueryTextChange(String s) {
Log.i(TAG,"QueryTextChange: "+s);
return false;
}
});

searchView.setOnSearchClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String query=QueryPreferences.getStoredQuery(getActivity());
searchView.setQuery(query,false);
}
});

MenuItem toggleItem =menu.findItem(R.id.menu_item_toggle_polling);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
if(PollJobService.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);
}
}

}

@Override
public boolean onOptionsItemSelected(@NonNull 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 = PollJobService.isHasBeenScheduled(getActivity()); //启动服务
PollJobService.setServiceAlarm(getActivity(),shouldStartAlarm);
getActivity().invalidateOptionsMenu();
}else{
boolean shouldStartAlarm = !PollService.isServiceAlarmOn(getActivity());
PollService.setServiceAlarm(getActivity(),shouldStartAlarm);
getActivity().invalidateOptionsMenu(); //刷新菜单项

}
return true;
default:
return super.onOptionsItemSelected(item);
}
}

发表评论