Android多线程

原创 2016年08月28日 20:07:56

Android多线程

一个Android的应用程序运行在一个独立的进程中,运行在一个独立的虚拟机(dvk)上。(进程名为包名)
Android应用程序开启后,默认开启一个主线程(UI线程)
Activity,Service,BroadcastReceive组件运行在主线程中
Android 应用程序退出后,保留空UI线程,可以加快应用程序启动速度。
用户不能再UI主线程中做耗时的操作,一旦操作超过5s,应用程序抛出一个ANR(application not respond)

如何避免ANR错误?
将耗时的操作放入到子线程中。(耗时的操作包括:长时间的休眠,计数,联网,复杂的运算)
只有主线程才能操作Widget控件。
如果在子线程中出现操作Widget控件,系统抛出CalledFromWrongThreadException异常。
系统为什么要这么做?
避免出现同步问题。

Handler机制

作用
主要为了解决非UI线程中不能更新Widget控件的问题
Handler机制剖析
子线程发送消息给底层的消息队列。
handler.sendMessage(msg)
主线程查询消息队列,处理消息对象。
handlerMessage(msg)
MessageQueue 消息队列
负责存储消息对象
Looper
给UI线程安排代码,一个UI线程只能有一个Looper对象,否则多个Looper对象都在UI线程上安排代码,解决冲突就是个大问题。
Looper对象会线性安排在UI线程上执行的代码,它通过一个队列管理各个Handler对象提交的代码。
Message消息对象
//从消息池中获取消息对象
Message msg = handler.obtainMessage();
//在消息对象上绑定int类型数据
msg.arg1 = count;
//在消息对象上绑定其它类型数据
msg.setData(Bundle); //Bundler为数据集(类似于HashMap容器)

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
 * @author Administrator
 * 事件驱动的应用程序
 */
public class MainActivity extends Activity implements OnClickListener {
    Button btnStart;
    TextView tv;
    int count = 0;
    boolean isRun;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnStart = (Button) findViewById(R.id.button1);
        btnStart.setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        tv = (TextView) findViewById(R.id.textView1);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(v.getId() == R.id.button1){  
            btnStart.setEnabled(false);
            count = 0;
            isRun = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    // 修改Widget控件的值
                    // tv.setText(String.valueOf(count));
                    while (isRun) {
                        count++;
                        // 创建消息对象
                        Message msg = new Message();
                        msg.arg1 = count;
                        //设置消息类型
                        msg.what = 2;
                        // 发送消息 (发给底层的消息队列)
                        handler.sendMessage(msg);

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }

                    handler.sendEmptyMessage(1);
                }
            }).start();
        }else if(v.getId() == R.id.button2){    
            isRun = false;  
        }
    }
    Handler handler = new Handler(){

        //如果消息队列中有消息,系统自动调用该方法处理消息
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            if(msg.what == 2){
                int count = msg.arg1;
                tv.setText(String.valueOf(count));
            }else if(msg.what == 1){
                //修改按钮属性
                btnStart.setEnabled(true);
            }
        }
    };
}

向消息队列发送消息,1000毫秒后执行Runnable对象中的代码。

myHandler.postDelayed(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        Log.e("Test", "thread name = "+Thread.currentThread().getName());
    }
}, 1000);

异步任务(Async Task)

概念
封装多线程和Handler机制。给用户提供重写接口的方式,不需要用户手动创建子线程和Handler对象。
异步任务的优点
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI主线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但是也有缺点,代码臃肿,在多个任务同时执行时,不易对线程进行精确的控制。为了简化操作,Android1.5提供了一个工具类AsyncTask,它是创建异步任务变的更加简单,不再需要编写任务线程和Handler实例就可完成任务。
异步任务的局限性
多个异步任务不能同时执行,在某个时间内,只能执行一个异步任务。
执行异步任务的步骤:

  • 1 execute(Params … params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
  • 2 onPreExecute(),在execute(Params… params
    )被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
  • 3 doInBackground(Params…
    params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接受输入参数和返回计算结果在执行过程中可以调用publishProgress(Progress…values)来更新进度信息。作用在非UI线程上。
  • 4 onProgressUpdate(Progress… values),在调用publishProgress(Progress…
    values)时,此方法被执行,直接将进度信息更新到UI组件上。
  • 5 onPostExecute(Result
    result)当后台操作结束时,此方法将被调用,计算结果讲座为参数传递到方法中,直接将结果显示到UI组件上。
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

//Params 执行异步任务时,传入的参数
//Progress 异步任务的进度
//Result 结果
public class MyTask extends AsyncTask<Void, Integer, Void> {

    TextView tv;
    public MyTask(TextView tv) {
        // TODO Auto-generated constructor stub
        this.tv = tv;
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        Log.d("Test", "onPre");
    }
    //该方法运行在非UI线程中
    //该方法中放耗时操作
    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        int count = 0;
        while(!isCancelled() && count < 10){
            count++;
            //发布进度
            //触发系统自动调用onProgressUpdate
            //相当于handler.sendMessage()
            publishProgress(count);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }
    //相当于handlerMessage()
    //该方法运行在UI线程中
    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);

        if(isCancelled()){
            return;
        }
        //操作UI控件
        int count = values[0];
        tv.setText(String.valueOf(count));
    }

    //该放在在取消异步任务之后运行
    @Override
    protected void onCancelled() {
        // TODO Auto-generated method stub
        super.onCancelled();
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.d("Test", "onPost");
    }
}

Android中使用多线程的各种姿势

写在前面:内容主要为黄岳钊老师视频分享课的学习笔记。 1)为什么需要多线程处理? 解决耗时任务 文件IO、联网请求、数据库操作、RPC 提高并发能力 同一时间处理更多事情 防止ANR Input...
  • qq_32199531
  • qq_32199531
  • 2016年12月04日 15:49
  • 2756

Android 多线程编程的总结

前言 这几天在研究Android的多线程方面的知识,阅读了许多大牛的文章,发现Android的多线程方式挺多的,关于各种方式的优缺点也都各有看法,所以这部分的知识还是很容易令人觉得混乱的,所以自...
  • qq876704116
  • qq876704116
  • 2017年04月16日 15:57
  • 537

Android 多线程处理之多线程用法大集合

handler.post(r)其实这样并不会新起线程,只是执行的runnable里的run()方法,却没有执行start()方法,所以runnable走的还是UI线程。 1.如果像这样,是可以操作u...
  • jie1991liu
  • jie1991liu
  • 2013年11月26日 11:27
  • 47296

面试系列----谈谈你对android多线程的理解

多线程
  • qq_34358104
  • qq_34358104
  • 2017年04月19日 09:52
  • 1557

android多线程讲解与实例

本期的多线程主题与Android相关,侧重讲解在Android中如何用好多线程,需要你有Java的多线程基础。 首先我们思考几个问题,在Android应用中为什么要用多线程?为了解决哪些问题?或者为...
  • bailyzheng
  • bailyzheng
  • 2013年02月28日 16:37
  • 7567

Android进阶:实现多线程下载文件

多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件   首先看下效果图     创建工程 Threa...
  • it_guang
  • it_guang
  • 2016年12月02日 14:21
  • 357

Android之——多线程断点续传下载示例

在上一篇博文中,我们讲解了如何实现Android的多线程下载功能,通过将整个文件分成多个数据块,开启多个线程,让每个线程分别下载一个相应的数据块来实现多线程下载的功能。多线程下载中,可以将下载这个耗时...
  • l1028386804
  • l1028386804
  • 2015年07月15日 21:02
  • 2898

android sqlite多线程读写分析与优化

android 多线程数据库读写分析与优化 时间 2013-08-04 10:43:21 CSDN博客 原文  http://blog.csdn.net/lize1988/article/d...
  • u010205141
  • u010205141
  • 2015年03月10日 22:31
  • 2371

Android之多线程实现方式及并发与同步

前言:说到多线程,就不得不先说它和进程的关系,这里先简单解释一下,当一个app程序启动时系统默认有一个进程和主线程,在程序运行中想要异步操作,就会创建不止一个子线程即多线程。用多线程只有一个目的,那就...
  • csdn_aiyang
  • csdn_aiyang
  • 2017年03月23日 13:24
  • 4536

Java / Android 基于Http的多线程下载的实现

有个朋友需要个多线程现在的例子,就帮忙实现了,在此分享下~ 先说下原理,原理明白了,其实很简单: a、对于网络上的一个资源,首先发送一个请求,从返回的Content-Length中回去需要下载文件的大...
  • lmj623565791
  • lmj623565791
  • 2014年05月26日 00:07
  • 20881
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android多线程
举报原因:
原因补充:

(最多只允许输入30个字)