谷歌电子市场开发流程(9)-线程,线程池
来源:互联网 发布:廖雪峰的javascript 编辑:程序博客网 时间:2024/06/08 02:29
1.异步任务的实例必须在UI线程中创建。
2.execute(Params... params)方法必须在UI线程中调用。
3.不要手动调用onPreExecute(),doInBackground(Params... params),onProgressUpdate(Progress... values),onPostExecute(Result result)这几个方法。
4.不能在doInBackground(Params... params)中更改UI组件的信息。
5.一个任务实例只能执行一次,如果执行第二次将会抛出异常。
下面,用一个例子来演示AsyncTask的使用,这个例子中,在MainActivity的Button点击事件中,调用了AsyncTask的execute方法,自定义了一个MyTask类继承了AsyncTask,在onPreExecute()中,对UI界面进行了一些设置,在doInBackground(Params... params)中执行了访问网页的任务,在onProgressUpdate(Progress... values)更新了UI中进度条的进度,在onPostExecute(Result result)中将访问的结果设置给了UI的TextView。
- public class MainActivity extends Activity {
- private static final String TAG = "ASYNC_TASK";
- private Button execute;
- private Button cancel;
- private ProgressBar progressBar;
- private TextView textView;
- private MyTask mTask;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- execute = (Button) findViewById(R.id.execute);
- execute.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //注意每次需new一个实例,新建的任务只能执行一次,否则会出现异常
- mTask = new MyTask();
- mTask.execute("http://www.baidu.com");
- execute.setEnabled(false);
- cancel.setEnabled(true);
- }
- });
- cancel = (Button) findViewById(R.id.cancel);
- cancel.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- //取消一个正在执行的任务,onCancelled方法将会被调用
- mTask.cancel(true);
- }
- });
- progressBar = (ProgressBar) findViewById(R.id.progress_bar);
- textView = (TextView) findViewById(R.id.text_view);
- }
- private class MyTask extends AsyncTask<String, Integer, String> {
- //onPreExecute方法用于在执行后台任务前做一些UI操作
- @Override
- protected void onPreExecute() {
- Log.i(TAG, "onPreExecute() called");
- textView.setText("loading...");
- }
- //doInBackground方法内部执行后台任务,不可在此方法内修改UI
- @Override
- protected String doInBackground(String... params) {
- Log.i(TAG, "doInBackground(Params... params) called");
- try {
- HttpClient client = new DefaultHttpClient();
- HttpGet get = new HttpGet(params[0]);
- HttpResponse response = client.execute(get);
- if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
- HttpEntity entity = response.getEntity();
- InputStream is = entity.getContent();
- long total = entity.getContentLength();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = new byte[1024];
- int count = 0;
- int length = -1;
- while ((length = is.read(buf)) != -1) {
- baos.write(buf, 0, length);
- count += length;
- //调用publishProgress公布进度,最后onProgressUpdate方法将被执行
- publishProgress((int) ((count / (float) total) * 100));
- //为了演示进度,休眠500毫秒
- Thread.sleep(500);
- }
- return new String(baos.toByteArray(), "gb2312");
- }
- } catch (Exception e) {
- Log.e(TAG, e.getMessage());
- }
- return null;
- }
- //onProgressUpdate方法用于更新进度信息
- @Override
- protected void onProgressUpdate(Integer... progresses) {
- Log.i(TAG, "onProgressUpdate(Progress... progresses) called");
- progressBar.setProgress(progresses[0]);
- textView.setText("loading..." + progresses[0] + "%");
- }
- //onPostExecute方法用于在执行完后台任务后更新UI,显示结果
- @Override
- protected void onPostExecute(String result) {
- Log.i(TAG, "onPostExecute(Result result) called");
- textView.setText(result);
- execute.setEnabled(true);
- cancel.setEnabled(false);
- }
- //onCancelled方法用于在取消执行中的任务时更改UI
- @Override
- protected void onCancelled() {
- Log.i(TAG, "onCancelled() called");
- textView.setText("cancelled");
- progressBar.setProgress(0);
- execute.setEnabled(true);
- cancel.setEnabled(false);
- }
- }
- }
至于AsyncTask的工作原理,概括来说,当我们调用execute(Params... params)方法后,execute方法会调用onPreExecute()方法,然后由ThreadPoolExecutor实例sExecutor执行一个FutureTask任务,这个过程中doInBackground(Params... params)将被调用,如果被开发者覆写的doInBackground(Params... params)方法中调用了publishProgress(Progress... values)方法,则通过InternalHandler实例sHandler发送一条MESSAGE_POST_PROGRESS消息,更新进度,sHandler处理消息时onProgressUpdate(Progress... values)方法将被调用;如果遇到异常,则发送一条MESSAGE_POST_CANCEL的消息,取消任务,sHandler处理消息时onCancelled()方法将被调用;如果执行成功,则发送一条MESSAGE_POST_RESULT的消息,显示结果,sHandler处理消息时onPostExecute(Result result)方法被调用。也就是对线程池和Handler的封装。
HandlerThread:
HandlerThread 继承自Thread,内部封装了Looper。
首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerThread与Activity不在同一个线程,而是别外新的线程中(Handler中不能做耗时的操作)。它的实现也很简单,就是在run方法中通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环。
从HandlerThread的实现来看,他和普通的Thread有显著地不同,普通的Thread主要在run方法中执行一个耗时的任务,而HandlerThread在内部创建了消息队列,外界需要通过Handler的消息机制来通知HandlerThread执行一个具体的任务。其具体的使用场景在IntentService,要注意的是,HandlerThread的run方法是一个无限循环,因此当明确不需要在使用HandlerThread时,可以通过它的quit或者quitSafely方法来终止线程的执行。
IntentService:
在Android的开发中,凡是遇到耗时的操作尽可能的会交给Service去做,比如我们上传多张图,上传的过程用户可能将应用置于后台,然后干别的去了,我们的Activity就很可能会被杀死,所以可以考虑将上传操作交给Service去做,如果担心Service被杀,还能通过设置startForeground(int, Notification)
方法提升其优先级。
那么,在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在android给我们提供了一个类,叫做IntentService,
IntentService是一种特殊的Service,他继承了Service并且是一个抽象类,它可以用于执行后台耗时的任务,执行后会自动停止,同时由于它是服务的原因,优先级会比单纯的线程要高很多,所以IntentService比较适合执行一些高优先级的后台任务,在实现上来看,IntentService封装了HandlerThread和Handler。我们使用了IntentService最起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。
IntentService的逻辑就是每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);就可以了。
那么我们具体看一下源码,果然是这样,onStartCommand中回调了onStart,onStart中通过mServiceHandler发送消息到该handler的handleMessage中去。最后handleMessage中回调onHandleIntent(intent)。
注意下:回调完成后回调用 stopSelf(msg.arg1),注意这个msg.arg1是个int值,相当于一个请求的唯一标识。每发送一个请求,会生成一个唯一的标识,然后将请求放入队列,当全部执行完成(最后一个请求也就相当于getLastStartId == startId),或者当前发送的标识是最近发出的那一个(getLastStartId == startId),则会销毁我们的Service.
如果传入的是-1则直接销毁。
那么,当任务完成销毁Service回调onDestory,可以看到在onDestroy中释放了我们的Looper:mServiceLooper.quit()。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
比如去火车站买票, 有10个售票窗口, 但只有5个窗口对外开放. 那么对外开放的5个窗口称为核心线程数,
而最大线程数是10个窗口.
如果5个窗口都被占用, 那么后来的人就必须在后面排队, 但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满.
这时候火车站站长下令, 把剩下的5个窗口也打开, 也就是目前已经有10个窗口同时运行. 后来又来了一批人,
10个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令封锁入口,不允许其他人再进来, 这就是线程异常处理策略.
而线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为.
- public static void main(String[] args) {
- ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
- for (int i = 0; i < 10; i++) {
- final int index = i;
- fixedThreadPool.execute(new Runnable() {
- public void run() {
- try {
- System.out.println(index);
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- public static void main(String[] args) {
- ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- for (int i = 0; i < 10; i++) {
- final int index = i;
- try {
- Thread.sleep(index * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- cachedThreadPool.execute(new Runnable() {
- public void run() {
- System.out.println(index);
- }
- });
- }
- }
- public static void main(String[] args) {
- ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
- scheduledThreadPool.schedule(new Runnable() {
- public void run() {
- System.out.println("delay 3 seconds");
- }
- }, 3, TimeUnit.SECONDS);
- }
- public static void main(String[] args) {
- ExecutorService singleThreadExecutor = Executors.newCachedThreadPool();
- for (int i = 0; i < 100; i++) {
- final int index = i;
- singleThreadExecutor.execute(new Runnable() {
- public void run() {
- try {
- while(true) {
- System.out.println(index);
- Thread.sleep(10 * 1000);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
public class ThreadPoolManager { private static ThreadPool mThreadPool = null; private static ThreadPoolExecutor executor; public static ThreadPool getmThreadPool() { if (mThreadPool == null) { synchronized (ThreadPoolManager.class) { if (mThreadPool == null) { int cpuCount=Runtime.getRuntime().availableProcessors(); System.out.println("=========Cpu个数======="+" "+cpuCount); mThreadPool = new ThreadPool(10,10,1L); } } } return mThreadPool; } public static class ThreadPool { private int corePoolSize;//核心线程数 private int maximumPoolSize;//最大线程数 private long keepAliveTime;//休息时间 private ThreadPool(int corePoolSize,int maximumPoolSize,long keepAliveTime) { this.corePoolSize=corePoolSize; this.maximumPoolSize=maximumPoolSize; this.keepAliveTime=keepAliveTime; } public void execute(Runnable r) { if (executor==null){ executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); } executor.execute(r); } public void cancle(Runnable r){ if (executor!=null){ //从线程队列中移除对象 executor.getQueue().remove(r); } } }}
- 谷歌电子市场开发流程(9)-线程,线程池
- 谷歌电子市场开发流程(6)-xutils的使用
- 谷歌电子市场开发流程(7)-单例模式
- 谷歌电子市场开发流程(6)-xutils的使用
- 谷歌电子市场开发流程(8)-自定义控件
- 谷歌电子市场开发流程(3)-关于加载界面的处理
- 谷歌电子市场开发流程(4)-listview的两层封装
- 谷歌电子市场开发流程(5)-关于加载更多页面的处理
- 谷歌电子市场开发流程(10)-回调与观察者模式
- app开发流程、线程池
- 谷歌电子市场开发记录(2)-框架搭建
- 谷歌电子市场
- 谷歌电子市场开发记录(1)-开发前的准备
- 线程流程
- 线程池任务执行流程
- 线程池ThreadPoolExecutor执行流程
- 线程池的执行流程
- 谷歌电子市场笔记1
- iOS时间转换当地时区
- web开发图表(ichartjs组件开发)
- 可自定义分页宽度的UIScrollView(Swift实现)
- 线性筛素数的欧拉筛法
- DBSCAN算法
- 谷歌电子市场开发流程(9)-线程,线程池
- mybatis之MapperFactoryBean源码解读
- 1008. 数组元素循环右移问题 --秒杀超简单方法
- 面向对象——异常RuntimeException
- Cloudera Manager 5和CDH5离线安装
- laravel
- webview 输入框无法调用键盘
- [LeetCode] String to Integer (atoi) Python
- 剑指offer-两个链表的第一个公共节点