Blog of CodeJELLOW’S ENGINEERING NOTES
← 返回文章

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

Java安卓学习总结(三十二) 第二十八章 后台服务

第二十八章 后台服务

有关IntentService

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

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

有关后台网络连接安全

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

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

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

TEXT
@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)方法的调用:

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

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

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

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

AlarmManager定时

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

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

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

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

TEXT
alarmManager.cancel(pendingIntent);

有关通知信息

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

TEXT
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实例:

TEXT
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:

TEXT
@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中的菜单项目中选择使用的服务:

TEXT
@Overridepublic 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);        }    }}@Overridepublic 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);    }}
通过 RSS 订阅更新 →