博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android(4.0.3+): Service, AsyncTask, 定时任务和UI通信
阅读量:6673 次
发布时间:2019-06-25

本文共 10851 字,大约阅读时间需要 36 分钟。

Service使用AlarmManager实现后台定时任务

在Android 4.0.3版本中, 使用AlarmManager实现后台定时任务是比较好的方案, 其实现机制, 是利用Service的 onStartCommand() 方法, 在每次被AlarmManager唤醒后, 执行任务并注册下一次唤醒到AlarmManager. 涉及的代码

1. 新建DaemonService, 实现 onStartCommand() 方法, 在这个方法中新开线程执行任务, 并再次将AlarmReceiver注册到AlarmManager. 注: 同样的注册多次调用时, 不会注册多个, 而是会进行更新. 这个方法会在Activity中调用 startService(intent); 方法时被调用.

@Override    public int onStartCommand(Intent intent, int flags, int startId) {        new DaemonThread().start();        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);        long triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000;        Intent i = new Intent(this, AlarmReceiver.class);        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);        return super.onStartCommand(intent, flags, startId);    }

 2. onDestroy() 方法在调用 Activity stopService(intent) 时会被调用, 此时需要将AlarmReceiver从AlarmManager中cancel掉.

@Override    public void onDestroy() {        Log.d(TAG, "onDestroy");        AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);        Intent i = new Intent(this, AlarmReceiver.class);        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);        manager.cancel(pi);        super.onDestroy();    }

3. 新建Receiver, 用来注册到AlarmManager, 用于将来响应Alarm消息. 在内部的onReceive方法中, 启动DaemonService

public class AlarmReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        Intent i = new Intent(context, DaemonService.class);        context.startService(i);    }}

4. 在AndroidManifest.xml中添加Service和Receiver

5. 在Activity中, 对应控件的点击响应中添加service的启动, 停止代码

@Override    public boolean onOptionsItemSelected(MenuItem item) {        // ...        if (id == R.id.action_start) {            Intent intent = new Intent(this, DaemonService.class);            startService(intent);            return true;        }        if (id == R.id.action_stop) {            Intent intent = new Intent(this, DaemonService.class);            stopService(intent);            return true;        }        // ...        return super.onOptionsItemSelected(item);    }

定时任务中使用 AsyncTask和 httpUrlConnection访问网址, 使用Callback进行结果回调

1. 新建HttpAsyncCallback接口, 要接收AsyncTask返回数据的, 都要实现这个接口

public interface HttpAsyncCallback {    // This function will be called from inside of your AsyncTask when you are ready to callback to    // your controllers (like a fragment, for example) The object in the completionHandler will be    // whatever it is that you need to send to your controllers    void completionHandler(Boolean success, int type, Object object);}

2. 新建HttpAsyncTask类, 进行实际的HTTP访问

public class HttpAsyncTask extends AsyncTask
{ public static final int METHOD_GET = 0; public static final int METHOD_POST = 1; private static final String TAG = HttpAsyncTask.class.getSimpleName(); private String postData; private int method; private int connectTimeout; private int readTimeout; private String encoding; private int type; private HttpAsyncCallback callback; public HttpAsyncTask(int method, String encoding) { this(null, method, encoding, 10000, 10000, 0, null); } public HttpAsyncTask(int method, String encoding, int type, HttpAsyncCallback callback) { this(null, method, encoding, 10000, 10000, type, callback); } public HttpAsyncTask(String postData, int method, String encoding, int type, HttpAsyncCallback callback) { this(postData, method, encoding, 10000, 10000, type, callback); } public HttpAsyncTask(String postData, int method, String encoding, int connectTimeout, int readTimeout, int type, HttpAsyncCallback callback) { this.postData = postData; this.method = method; this.encoding = encoding; this.connectTimeout = connectTimeout; this.readTimeout = readTimeout; this.type = type; this.callback = callback; } @Override protected Void doInBackground(String... strings) { Log.d(TAG, "Timestamp:" + System.currentTimeMillis()); HttpURLConnection connection = null; try { connection = (HttpURLConnection) new URL(strings[0]).openConnection(); connection.setConnectTimeout(connectTimeout); connection.setReadTimeout(readTimeout); if (method == METHOD_GET) { connection.setRequestMethod("GET"); } else { // get请求的话默认就行了,post请求需要setDoOutput(true),这个默认是false的。 connection.setDoOutput(true); connection.setRequestMethod("POST"); if (this.postData != null) { OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); writer.write(postData); writer.flush(); } } int statusCode = connection.getResponseCode(); if (statusCode == 200) { InputStream in = connection.getInputStream(); byte[] bytes = getBytesByInputStream(in); String response = new String(bytes, encoding); Log.d(TAG, response); // From here you can convert the string to JSON with whatever JSON parser you like to use // After converting the string to JSON, I call my custom callback. You can follow this // process too, or you can implement the onPostExecute(Result) method // Use the response to create the object you need if (callback != null) { callback.completionHandler(true, type, "Timestamp:" + System.currentTimeMillis() + ", " + response); } } else { Log.d(TAG, statusCode+""); if (callback != null) { callback.completionHandler(false, type, statusCode); } } } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } finally { if (connection != null){ connection.disconnect(); } } return null; } private byte[] getBytesByInputStream(InputStream is) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; try { while ((length = is.read(buffer)) != -1) { bos.write(buffer, 0, length); } } catch (IOException e) { Log.e(TAG, e.getMessage()); } finally { try { bos.close(); } catch (IOException e) { Log.e(TAG, e.getMessage()); } } return bos.toByteArray(); } public static String formDataToString(Map
data, String encoding) { StringBuilder sb = new StringBuilder(); String con = ""; for (String key : data.keySet()) { String value = data.get(key); try { key = URLEncoder.encode(key, encoding); value = URLEncoder.encode(value, encoding); sb.append(con).append(key).append("=").append(value); con = "&"; } catch (UnsupportedEncodingException e) { Log.e(TAG, "UnsupportedEncodingException " + encoding + " in processing:" + key); } } return sb.toString(); } public static String formDataToJson(Map
data, String encoding) { if (data != null) { JSONObject jsonObject = new JSONObject(data); return jsonObject.toString(); } return null; }}

 

使用 Callback和BroadcastReceiver实现消息通信

1. 在DaemonService中实现HttpAsyncCallback接口, 用于接收HttpAsyncTask任务执行结果

public class DaemonService extends Service implements HttpAsyncCallback {    private static final String TAG = DaemonService.class.getSimpleName();    // ...    @Override    public void completionHandler(Boolean success, int type, Object object) {        Log.d(TAG, "completionHandler");    }}

2. 在DaemonService的onStartCommand()方法中, 将自己做为参数传给HttpAsyncTask. 1和2是为了将AsyncTask的结果传回Service

@Override    public int onStartCommand(Intent intent, int flags, int startId) {        Map
map = new HashMap<>(); map.put("phone", "13800138000"); HttpAsyncTask task = new HttpAsyncTask(HttpAsyncTask.formDataToString(map, "UTF-8"), HttpAsyncTask.METHOD_POST, "UTF-8", 0, this); task.execute("https://www.toutiao.com/api/pc/realtime_news/"); //new DaemonThread("").start(); AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE); long triggerAtTime = SystemClock.elapsedRealtime() + 5 * 1000; Intent i = new Intent(this, AlarmReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0); manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi); return super.onStartCommand(intent, flags, startId); }

3. 为了从Service将结果传回Fragment, 需要在Fragment中注册一个BroadcastReceiver, 实现onReceive方法, 在这个方法中将结果更新到TextView, 在onCreateView中初始化这个receiver, 在onStart和onStop方法中进行注册和取消. 注意: 从fragment中获取TextView时, 需要在onActivityCreated方法中才行, 在其他的事件方法(onCreateView, onAttach中, findViewById拿到的是null

public class MainActivityFragment extends Fragment {    private static final String TAG = MainActivityFragment.class.getSimpleName();    private BroadcastReceiver receiver;    private TextView tv;    ...    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        Log.d(TAG, "onCreateView");        receiver = new BroadcastReceiver() {            @Override            public void onReceive(Context context, Intent intent) {                String s = intent.getStringExtra("msg");                tv.setText(s);            }        };        return inflater.inflate(R.layout.fragment_main, container, false);    }    @Override    public void onAttach(Context context) {        Log.d(TAG, "onAttach");        super.onAttach(context);    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        Log.d(TAG, "onActivityCreated");        super.onActivityCreated(savedInstanceState);        tv = getActivity().findViewById(R.id.sample_text);    }    @Override    public void onStart() {        Log.d(TAG, "onStart");        super.onStart();        if (receiver != null) {            IntentFilter intentFilter = new IntentFilter(MainActivityFragment.class.getName() + ".TextView");            getActivity().registerReceiver(receiver, intentFilter);        }    }    @Override    public void onStop() {        Log.d(TAG, "onStop");        if (receiver != null) {            getActivity().unregisterReceiver(receiver);        }        super.onStop();    }}

 

代码在

 

转载地址:http://fugxo.baihongyu.com/

你可能感兴趣的文章
Java程序员在工作的同时应该具备什么样的能力?
查看>>
Dubbo深入分析之Cluster层
查看>>
分析Padavan源代码,二
查看>>
WordPress的WPML外挂出问题恐出现安全漏洞
查看>>
Django 调试技巧
查看>>
Spring Boot和thymeleaf , freemarker , jsp三个前端模块的运用
查看>>
phalcon-入门篇3(优美的URL与Config)
查看>>
单表60亿记录等大数据场景的MySQL优化和运维之道
查看>>
sql学习笔记
查看>>
maven编译时出现There are test failures
查看>>
SpringBoot | 第三十一章:MongoDB的集成和使用
查看>>
网络学习笔记2
查看>>
JPA--多对多关系
查看>>
配置sharepoint 2010错误:Microsoft.SharePoint.Upgrad...
查看>>
UUID 生成算法JS版
查看>>
JAVA中,Map转实体类、实体类转Map的方法
查看>>
获取n!的末尾有多少个0?
查看>>
使用递归遍历并转换树形数据(以 TypeScript 为例)
查看>>
windows下实现wamp与tomcat环境整合
查看>>
我的友情链接
查看>>