Android线程

http://byandby.iteye.com/blog/825071

 

一、Android进程:

        当一个程序第一次启动的时候,Android会启动一个Linux进程和一个主线程。默认情况下,所有该程序的组件都将在该进程和线程中运行,同时,Android会为每个应用程序分配一个单独的Linux用户。

        Android会尽量保留一个正在运行的进程,只在内存资源不足的时候,Android会尝试停止一些进程从而释放足够的资源给其它新的进程使用,也能保证用户正在访问的当前进程有足够的资源去及时的响应用户的事件。

        Android会根据进程中运行的组件类型以及组件的状态来判断该进程的重要性,Android会首先停止那些不重要的进程。按照重要性从高到低一共有五个级别。

1.前台进程

   前台线程是用户正在使用的进程。

   只有一些前台线程

2.可见进程

3.服务进程

4.后台进程

5.空进程

 

二、单线程模型
    当一个程序第一次启动时,Android会同时启动一个对应的 主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事 件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线 程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。

    单线程模型会在没有考虑到它的影响的情况下引起Android应用程序性能低下,因为 所有的任务都在同一个线程中执行,如果执行一些耗时的操作,如访问网络或查询数据库,会阻塞整个用户界面。当在执行一些耗时的操作的时候,不能及时地分发 事件,包括用户界面重绘事件。从用户的角度来看,应用程序看上去像挂掉了。更糟糕的是,如果阻塞应用程序的时间过长(5秒钟)Android会向用户提示一些信息,即打开一个“应用程序没有相应(application not responding)”ANR 的对话框。

   其实单线程模型就是默认情况下android把所有操作都放在主线程也就是UI Thread线程中来执行 如果你想 O上边那段不是说它会阻塞用户界面嘛  那我可以另起一个线程来执行一些操作 没错你的想法非常good 。很给力。那么接下来 你就会尝试另起一个线程来 执行一些操作。OK 结果就有两种可能 一:你在另外开启的那个线程中执行了一些后台的操作 比如开启一个服务啊。神马的。那么恭喜你 你成功了。 二:第二种可能结果就是 你会收到一个华丽的异常 。这个例子很简单

 

下面我们就通过一个小例子来说明这个华丽的异常时怎么回事? 因为本篇文章的例子比较多所以我为了大家好找 给例子起了名称 这个例子的名称是: 异常测试



工程名:ThreadExceptionTest

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textview01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

    <Button
        android:id="@+id/myButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/textview01"
        android:text="@string/exception_test" />

    <TextView
        android:id="@+id/myTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/myButton"
        android:layout_toRightOf="@id/myButton"
        android:textColor="#FF0000"
        android:textSize="15pt" />

</RelativeLayout>


 

 

MainActivity.java

package com.cn.nj;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

	private Button myButton;
	private TextView myTextView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		myButton = (Button) findViewById(R.id.myButton);
		myTextView = (TextView) findViewById(R.id.myTextView);
		myButton.setOnClickListener(new MyButtonListener());
		
	}

	class MyButtonListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			new Thread() {
				@Override
				public void run() {
					// 我们在这里更新了UI 设置了TextView的值
					myTextView.setText("张三");
				}
			}.start();
		}
	}

}


运行后的效果为:点击按钮后会出现

 

看看LogCat提示:

 

 

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.就是这样一个异常 这个异常告诉我们不可以再子线程中更新UI元素 比如我们上边那个例子设置了一个TextView的值。所有与UI相关的操作都不可以在子线程中执行都必须在UI线程中执行。这个异常大家以后可能会经常遇到多加注意就是了。

 


三、MessageQueue        Handler             Looper  的详细分析

        我们继续,下面我们说说线程交互方面的东西。就比如我们想做点这些事情上边不是说了不能在子线程中更新UI 那比如我想在子线程中定义 一个字符串 然后通过发消息的方式 Message 把这个字符串 发送给主线程也就是UI线程 让UI线程来 设置这个TextView的值为我们刚刚在子线程中定义的字符串。 或者我想在子线程中开启音乐服务,或者把它停止该怎么做呢?  要知道怎么做先让我们了解 一下这几个对象吧!它们分别是MessageQueue、Handler、 Looper   下面对它们进行详细说明 。


1.Message Queue

        在单线程模型下,为 了解决类似的问题,Android设 计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组 件进行信息交换。 

        Message Queue是一个消息队列,用来存放通过Handler发 布的消息。消息队列通常附属于某一个创建它的线程,可以通过Looper.myQueue()得 到当前线程的消息队列。如果没有消息队列对象则会抛出空指针异常 。

        Android在 第一次启动程序时会默认会为UI thread创建一个关联的消息队列,用来管理程序的一些上层组件,activities,broadcast receivers 等等。你可以在自己的子线程中创建Handler与UI thread通讯。也就是说我们程序一启动我们的UI线程也就是主线程就会有一个消息队列 ,而如果我们自己另外开启的一个子线程就不会有MessageQueue(消息队列)对象。这一点大家务必知道。 

 

2.Handler

     通过Handler你 可以发布或者处理一个消息或者是一个Runnable的 实例。每个Handler都 会与唯一的一个线程以及该线程的消息队列关联。当你创建一个新的Handler时候,默认情况下,它将关联到创建它的这个线程和该线程的消息队列。也就是说,如果你通过Handler发 布消息的话,消息将只会发送到与它关联的这个消息队列,当然也只能处理该消息队列中的消息。这里大家就得理解一下了 也就是说我们 一个Handler对应一个线程以及附属于该线程的消息队列。就比如 我们现在有一个Handler对象这个Handler在UI线程中创建 叫xh_Handler 那么我们根据上边的说明 应该可以告诉我 这个xh_Handler是和那个线程关联的?  如果我用这个Handler发消息的话它将发给那个线程的消息队列? 如果你知道了 我想一般情况下你肯定是知道的。说明你很懂。我们继续。这时我们用这个Handler对象发送消息
Handler对象也可以发送消息哦,它有发送消息的方法。下面就说到了 待会大家看示例程序也会发现 主要就是看它怎么使用。

Handler的主要的方法有:

1)   public final boolean sendMessage(Message msg)

把消息放入该Handler所 关联的消息队列,放置在消息队列尾部。
这里请允许我多说一句就是 我们把消息放进去的一端 消息不会阻塞但是处理消息的一端就有可能会阻塞。欢迎收看 看图频道。


2)   public void handleMessage(Message msg)

    关联该消息队列的线 程将通过调用Handler的handleMessage方 法来接收和处理消息,通常需要子类化Handler来 实现handleMessage。

3.Looper

        Looper扮演着一个Handler和 消息队列之间通讯桥梁的角色。程序组件首先通过Handler把 消息传递给Looper,Looper把 消息放入队列。Looper也 把消息队列里的消息广播给所有的Handler,Handler接 受到消息后调用handleMessage进 行处理。

1)   可以通过Looper类 的静态方法Looper.myLooper得 到当前线程的Looper实 例,如果当前线程未关联一个Looper实 例,该方法将返回空(null)它不会抛空指针异常。

2)   可以通过静态方法Looper. getMainLooper方法得到主线程的Looper实 例 这里需要注意一下 主线程默认是有一个Looper对象的。但是我们自己定义的子线程没有的。那么我们怎么在子线程中得到Looper对象呢?如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以再其他的线程中通过 Handle来做,但前提是我们的Hanle知道这个子线程的Looper,但是你如果不是在子线程运行 Looper.myLooper(),一般是得不到子线程的looper的。

好了示例演示时间到了。示例名称:线程交互

        这个例子主要向大家说明线程之间是如何进行交互的。请大家静下心来好好看看。如果你也是android新手的话。先说一下我们具体要实现什么功能,一共有三个按钮 第一个按钮用来设置一个 TextView上显示的值。当我们第一次点击它的时候它就会把值显示在TextView当我们在一点一下 就会把这个值清空。 什么也不显示了。这个按钮的 的背景图片我做了点处理。就是默认情况下这个按钮一张图片,按下按钮又会换成另外一张图片,松开按钮又会换一张图片。这是怎么做到的说完这个例子会给大家解释。至于线程之间是怎么传递消息的 大家就看代码吧。 另外2个按钮时用来 开启和关闭音乐服务的 ,注意当我们点击开始按钮的时候 就会开始播放音乐 并且把歌曲的名称显示在一个TextView上。当我们点击关闭按钮的时候就会停止音乐的播放,好了废话不多说了大家看代码吧。




 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值