Android中的进程和线程
——Android进程分类与进程优先级
——前台进程
——可见进程
——服务进程
——后台进程
——空进程:为了再次运行提高速度,不用开辟进程空间,只需将数据装载进来就可以了。
——进程的优先级
Android为了管理内存释放有限的空间,会根据优先级杀掉一些进程,进程优先级越低的优先被清除。从高到低依次为:
空进程—>后台进程—>服务进程—>可见进程—>前台进程
在Android中,每启动一个应用程序,就会启动一个与之匹配的进程(包含了一条线程(主线程)),
Demo:
我们在主线程中执行了一个非常耗时的操作
——Android线程
a)单线程模式
b)Android进程在启动时,会创建一个主线程(UI线程)去处理UI相关操作,为了效率考虑,主线程不是线程安全的.
c)子线程不能直接操作主线程内的控件,UI控件只能由UI线程去操作。
d)若要实现线程间通信,需要依赖于Android消息机制等技术
——消息机制:实现线程间通信
由于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity的UI组件。
如果子线程需要改变界面组件的属性值,需要借助于Handler的消息机制来实现了。
消息机制一共工作的几个组件:
MessageQueue,Handler,Looper, Message
(a)Message:Handler接收和处理的消息对象
(b)Message Queue:消息队列,它采用先进先出的方式来管理Message。
MessageQueue一般用于管理消息。
(c)Handler
功能:1)在新启动的线程中发送消息(把消息发送给Looper管理的messageQueue)
2)在主线程中获取,处理消息(负责处理Looper分给它的消息)
回调方法:但是新启动的线程何时发送消息?何时获取和处理消息?
通过回调函数去处理
处理消息:handleMessage(Message msg)处理消息的方法,一般用于被重写
创建方式:1)Handlerhandler = new Handler();
与当前线程的Looper关联
2)Handlerhandler = new Handler(Looper looper);
与指定Looper相关联
handler.sendEmptyMessage(start);
发送消息:1)sendEmptyMessage(intwhat);
发送只包含what标记的空消息
2)sendMessage(Message msg);
发送一个标准的Message对象
3)sendMessageDelayed(Message msg,longdelayMillis)
指定多少毫秒之后发送消息
4)sendEmptyMessageDelayed(int what,longdelayMillis)
指定多少毫秒之后发送只有what标记的空消息
(d)Looper
每一个线程只能拥有一个Looper.
它的loop方法负责不断读取MessageQueue中的消息,读到信息之后就把消息逐个发送给该消息对应的Handler进行处理。
获取Looper的方式:
1)Looper.getMainLooper 获取主线程Looper
2)Looper.myLooper 获取当前线程Looper
程序创建Looper对象时会在它的构造器中创建MessageQueue对象。
Looper提供的构造器源代码:
private Looper(){
mQueue=newMessageQueue();
mRun = true;
mThread=Thread.currentThread();
}
注:1)每条线程只能包含一个Looper与Message Queue
2)主线程在创建过程中,系统会自动为其添加Looper与Message Queue
子线程默认不会添加Looper与Message Queue
需要调用Looper.prepare()来创建Looper对象与Looper.loop()方法来启动它。loop方法使用一个死循环不断取出
MessageQueue中的消息,并将取出的消息分给该消息对应的handler进行处理。
3)Looper与MessageQueue之间是组合关系
4.使用Handler的步骤
都是在一个线程中完成的:
a)调用Looper的prepare()方法为当前线程创建Looper对象,
创建Looper对象时,能够在其会创建与之配套的MessageQueue,主线程就不需要了。
b)有了Looper之后,创建Handler子类的实例,重写handlerMessage()方法,该方法负责处理来自于其他线程的消息。
c)调用Looper的loop()方法启动Looper,主线程就不需要了。
《demo>
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class XianchengTest extends AppCompatActivity {
private Button button;
private static final int start =1;
private static final int go =2;
private static final int end =3;
private int anInt= 10;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case start:
button.setEnabled(false);
break;
case go:
int a= msg.arg1;
msg.what=go;
button.setText("还有"+a);
break;
case end:
button.setEnabled(true);
button.setText("开始测试");
break;
}
}
};
public void Start (View view){
new Thread(){
@Override
public void run() {
/* Looper.prepare();
Toast.makeText(getApplication(), "线程开启1", Toast.LENGTH_SHORT).show();
Looper.loop();*/
//第一次调用线程
handler.sendEmptyMessage(start);
//第二次调用线程
while (anInt>0){
anInt--;
Message message = Message.obtain();
message.what= go;
message.arg1=anInt;
handler.sendMessage(message);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//第一三调用线程
handler.sendEmptyMessage(end);
anInt= 10;
}
}.start();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xiancheng_test);
button = (Button) findViewById(R.id.btn);
}
}