Android线程笔记

参考来源:

郭霖.第一行代码(Android)

https://www.gitbook.com/book/hzj163/android-thread/details

一.进程

进程是正在运行的程序的实例,操作系统中资源分配和保护的基本单位

二.线程

线程是进程中能够并发执行的实体,是进程的组成部分,也是处理器调度和分派的基本单位,一个进程可以同时包含多个线程,这些线程共享进程所获得的内存空间和资源,可以为完成某一项任务而协同工作,提高完成任务的速度和效率

三.创建线程

1.    继承Thread类

创建

class TestThread extends Thread{
    @Override
    public void run() {
        /*要在多线程里运行的代码*/
    }
}

  

启动

TestThread myThread=new TestThread;
myThread.start();//调用继承于Thread的start方法

  

2.    实现Runnable接口

使用继承的方式耦合性有点高,而且只能继承一个父类,而接口可以实现多个。所以我们可以使用接口的方式。

TestThread myTestThread=new TestThread();//生成一个Runnable接口实现对象
Thread ti=new Thread(myTestThread);//将这个对象作为构造函数参数传递给Thread对象
ti.start();

  

3.    使用匿名类

如过你不想麻烦的创建一个新类,可以使用匿名类的方法

new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
        }
}).start();

  

四.线程池//TODO

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。

使用线程池减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。而且可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

五.线程同步(线程安全)

多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性。

在Java里面,通过synchronized关键字保证线程同步。

Java中的每一个对象都有一个内部锁,如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。

public synchronized void method(){
    // method body
}

  

线程不安全

不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

六.Android中的UI主线程

当应用启动,系统会创建一个主线程(main thread)。这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件发生交互。所以main thread也叫UI thread也即UI线程。

如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程,导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。所有这部份工作最后用异步线程来完成。

  Andoid UI toolkit并不是线程安全的,所以你不能从非UI线程来操纵UI组件。你必须把所有的UI操作放在UI线程里,所有View和ViewGroup都只能在UI主线程中运行。如果View或者ViewGroup在次线程中运行,将会抛出【Only the original threadthat created a view hierarchy can touch its views】。

所以Android的单线程模型有两条原则:

1.   不要阻塞UI线程。

2.   不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:android.widget and android.view)。

七.线程和线程之间的通信:Android消息机制

但UI需要根据线程的执行情况来改变时(比如连接上网络后对UI内容加载),由于次线程不能直接修改UI,,它通过消息机制告诉主线程中的UI什么时候该修改。

Android中消息机制由以下部分组成:

1.  Message

Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。

Message 使用 what字段携带String类型,使用 arg1和 arg2字段来携带一些整型数据,使用 obj字段携带一个 Object对象。

2.  Handler

Handler顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用 Handler的 sendMessage()方法,而发出的消息经过一系列地处理后,最终会传递到 Handler的 handleMessage()方法中。

食用方法

首先需要在主线程当中创建一个 Handler 对象,并重写handleMessage()方法。

然后当子线程中需要进行 UI 操作时,就创建一个 Message 对象,通过 Handler 将这条消息发送出去。

之后这条消息会被添加到 MessageQueue 的队列中等待被处理,而 Looper 则会一直尝试从 MessageQueue 中取出待处理消息,最后分发回 Handler的 handleMessage()方法中。

由于 Handler 是在主线程中创建的,所以此时handleMessage()方法中的代码也会在主线程中运行,于是我们在这里就可以安心地进行 UI 操作了。

//在主线程中,创建Handler对象,重写handleMessage方法
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
               case UPDATE_TEXT:
//                在这里可以进行UI 操作
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
          }
        }
//在子线程中
new Thread(new Runnable() {
@Override
public void run() {
        Message message = new Message();//创建Message对象
        message.what = UPDATE_TEXT;
        handler.sendMessage(message); //  将Message 对象发送出去
        }
        }).start();

  

3.  MessageQueue

MessageQueue 是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个 MessageQueue对象。

4.  Looper

Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop()方法后,就会进入到一个无限循环当中,然后每当发现MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler的 handleMessage()方法中。每个线程中也只会有一个 Looper 对象。

八.多线程异步

异步

方法A对方法B调用后,不用管B是否运行,A继续运行。

AsyncTask

借助 AsyncTask,即使你对异步消息处理机制完全不了解,也可以十分简单地从子线程切换到主线程。当然,AsyncTask 背后的实现原理也是基于异步消息处理机制的,只是 Android 帮我们做了很好的封装而已。

基本用法

AsyncTask 是一个抽象类,所以如果我们想使用它,就必须要创建一个子类去继承它。在继承时我们可以为AsyncTask类指定三个泛型参数,这三个参数的用途如下。

1.  Params

初始化参数类型

2.  Progress

进度参数类型

3.  Result

返回值参数类型。

		因此,一个最简单的自定义 AsyncTask 就可以写成如下方式:
class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
    ……
}

  

一个栗子

class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
    //这个方法会在后台任务开始执行之前调用,用于进行一些界面上的初始化操作
    @Override
    protected void onPreExecute() {
        progressDialog.show(); // 显示进度对话框
    }

    /*这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。
    任务一旦完成就可以通过 return 语句来将任务的执行结果返回,如果 AsyncTask的第三个泛型参数指定的是 Void,就可以不返回任务执行结果。
    注意,在这个方法中是不可以进行 UI操作,如果需要更新 UI元素,比如说反馈当前任务的执行进度,可以调用 publishProgress(Progress...)方法来完成。*/
    @Override
    protected Boolean doInBackground(Void... params) {//
        try {
            while (true) {
                int downloadPercent = doDownload(); // 这是一个虚构的方法
                publishProgress(downloadPercent);
                if (downloadPercent >= 100) {
                    break;
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    /* 当在后台任务中调用了 publishProgress(Progress...)方法后,这个方法就会很快被调用,
    方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对 UI 进行操作,利用参数中的数值就可以对界面元素进行相应地更新。*/
    @Override
    protected void onProgressUpdate(Integer... values) {
        // 在这里更新下载进度
        progressDialog.setMessage("Downloaded " + values[0] + "%");
    }
    /* 当后台任务执行完毕并通过 return语句进行返回时,这个方法就很快会被调用。
    返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些 UI 操作,比如
   说提醒任务执行的结果,以及关闭掉进度条对话框等。*/
    @Override
    protected void onPostExecute(Boolean result) {
        progressDialog.dismiss(); // 关闭进度对话框
// 在这里提示下载结果
        if (result) {
            Toast.makeText(context, "Download succeeded",
                    Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, " Download failed",
                    Toast.LENGTH_SHORT).show();
        }
    }
}

  

时间: 2024-09-29 00:52:23

Android线程笔记的相关文章

【转】 Pro Android学习笔记(七四):HTTP服务(8):使用后台线程AsyncTask

目录(?)[-] 5秒超时异常 AsyncTask 实现AsyncTask抽象类 对AsyncTask的调用 在哪里运行 其他重要method 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件,转载须注明出处:http://blog.csdn.net/flowingflying/ 之前,我们直接在activity中执行http通信,在通信过程中可能会出现连接超时.socket超时等情况,超时阈值一般是秒级,例如AndroidHttpClient中设置的20秒,如果出现超时,就

Android(java)学习笔记267:Android线程池

1. 线程池 (1)线程池的优点: 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销. 能有效控制线程池的最大并发数,避免大量的线程之间因相互抢占系统资源而导致的阻塞现象. 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能. (2)Android中的线程池: Android中的线程池的概念来源于Java中的Executor,Executor是一个借口,真正的线程池实现为ThreadPoolExecutor. ThreadPoolExecutor提供了一系列参数来配置

Android学习笔记_78_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>

Java(Android)线程池 总结

一种是使用Executors工厂生产线程池:另一种是直接使用ThreadPoolExecutor自定义. Executors工厂生产线程池 Java(Android)线程池 Trinea 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new Thread吗? Java 1 2 3 4 5 6 7 newThread(newRunnable(){ @Ove

Android学习笔记(四五):互联网通信-HttpClient、XML解析(W3C)

前几日Android发布了4.0 Icecream,昨天上网发现Begining Book中有Edition 3的版本,比对一下,还是有相当的改动,不仅仅增加了tablet的部分,对原有的章节有有一些修订,前后的调整等等.先按Edtion 2的顺序看,相同章节的看Edtion 3,然后回头看Edition 3的Chapter 24.25(E2的36).26.27.28.29.44.45.46.47几个新增章节.同时将模拟器改为Android 2.3的版本,已适应可能新增的改动. 访问Intern

Android学习笔记(四二):SQLite、ListView、ContextMenu

继续上一个例子,结合ListView中对SQLite进行操作. 通过CursorAdapter在ListView中的数据呈现 在上一个例子中,我们可以对SQLite中的数据库进行增删改查,将数据读到游标Cursor中,然后一一读出.在Android中可以通过CursorAdapter直接将数据映射到ListView中,如下处理: public class Chapter22Test1 extends ListActivity{    private SQLiteDatabase  db = nu

Android开发笔记(八十八)同步与加锁

同步synchronized 同步方法 synchronized可用来给方法或者代码块加锁,当它修饰一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.这就意味着,当两个并发线程同时访问synchronized代码块时,两个线程只能是排队做串行处理,另一个线程要等待前一个线程执行完该代码块后,才能再次执行synchronized代码块. 使用synchronized修饰某个方法,该方法便成为一个同步方法,在同一时刻只能有一个线程执行该方法.可是,synchronized的锁机制太

Android学习笔记(四六):互联网通信-文件下载

在Android 2.3引入了DownloadManager可以处理复杂的文件下载,包括检查用户是否有数据联系(WIFI或者移动数据),当用户从一个有数据连接的地方移动到无连接的地方(例如离开了wifi或者3G data的access point),确保设备在下载过程中保持awake状态.DownloadManager可以处理HTTP URLs,但是不能处理HTTPS(SSL) URLs. 设置下载文件条件许可 在这个例子,将学习通过DownloadManager从Internet下载文件,并存

九、Android学习笔记_ Android开发中使用软引用和弱引用防止内存溢出

在<Effective Java 2nd Edition>中,第6条"消除过期的对象引用"提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池.缓存中的过期对象都有可能引发内存泄露的问题.书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题.之前也确实遇到过类似问题,但是没有接触过"弱引用"相关的问题,于是查阅了一些资料. <Java 理论与实践: 用弱引用堵住内存泄漏>