Android杂谈
本文章用自己的复习巩固,文章中的内容都是通过Android疯狂讲义整理
1.事件监听
三种对象:
- Event Source(事件源):发生事件的来源,一般的情况就是各个控件,比如:textview,button
- Event (事件):封裝了事件源上发生的特定的事情,比如textview按下激发onKeyDown()
- eventlistener(事件监听器):监听事件源发生的事件,并且对事件发生相应,比如按下textview时做一个跳转等
2.Configuration简介
在Activity中获取系统的Configuration对象:
Configuration con=getResources().getConfiguration();
Configurationde的属性 :
- public float fontScale:获取当前用户设置的字体的缩放因子
- public int keyboard:设备键盘的类型。KEYBOARD_NOKEYS,KEYBOARD_QWERTY(普通电脑键盘),KEYBOARD_12KEY(只有12键的小键盘).
- public int keyboardHidden:判断当前键盘是否可用。
- public Locale locale:获取当前用户的场所。
- public int mcc:获取移动信号的国家码。
- public int mnc:获取移动信号的网络码。
- public int navigation:判断方向导航设备的类型
- public int orientation:判断屏幕的横竖屏。
- public int touchscreen:获取系统触摸屏的方式。
- public int keyboardHidden:判断当前键盘是否可用。
重写onConfigurationChanged方法,可以监听系统设置的更改,常用的情况就是监听横竖屏的切换,从而进行相应的处理。
3.Handler,Looper,MessageQueue的关系
- Handler:用于消息的发送和接受,程序使用Handler发送消息,被Handler发送的消息必须被送到指定的MessageQueue。所以如果要Handler正常的使用,就需要在该线程中有一个指定的MessageQueue。而通过下面的代码可以看出MessageQueue是由Looper的构造函数创建的,所以如果希望Handler能够正常的发送和接受消息,就必须在当前的线程中有一个Looper对象。
- Message:handler接受和处理的消息对象
- Looper:每一个线程只能有一个looper,如果有第二个会报错。他的loop方法负责读取MessageQueue中的消息,读到的消息发送给该消息的handler进行处理
- MessageQueue:消息队列,他采用先进先出的方式管理Message,程序创建Looper对象的时候,会在Looper的构造函数中创建MessageQueue对象。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper得构造方法是私有的不能外部访问,所有looper的创建不是通过外部new方法创建。
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
翻译这段注释:实例化当前线程创建一个looper对象。
让你在循环这个loop之前有机会创建handlers,然后引用这个looper对象。在你确定引用这个方法之后你必须调用方法loop(),同时最后会调用quit()方法。
*/
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
//判断当前线程是否有looper对象,如果有就报错
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//判断looper对象是否创建成功,如果没有会抛出异常
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block 获取消息队列的下一个消息,如果没有就会阻塞在这里
if (msg == null) {
// No message indicates that the message queue is quitting.
//如果为空 表示消息队列正在退出
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
//确保在使用的过程中,线程的标识不会被损坏
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
通过上面的代码,可以总结出:每一个线程只能有一个Looper对象,通过他来管理MessageQueue,他会不断的从消息队列中获取消息,并将消息分给对应的handler;而MessageQueue则是通过先进先出的方式管理Message;最后Handler则是把消息发送给Looper管理的MessageQueue,并处理looper发送给他的消息。
我们要注意的是:Handler分两种:
- 主线程的Handler:也就是UI线程,在UI线程创建的时候,已经初始化了一个Looper对象,所有我们不需要在创建一个Looper对象,而是直接创建Handler就可以发送和接受消息
- 子线程的Handler:我们需要手动创建一个Looper对象,并启动他。
下面是子线程调用的示例代码:
public class MainActivity extends AppCompatActivity {
class MyThread extends Thread
{
public Handler handler;
@Override
public void run() {
super.run();
//创建一个Looper对象
Looper.prepare();
//创建一个Handler对象在这里接受并处理消息
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==0)
{
Toast.makeText(MainActivity.this,"测试是否有用!",Toast.LENGTH_LONG).show();
}
}
};
//启动这个Looper中消息队列的循环机制
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
final MyThread thread=new MyThread();
thread.start();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message= new Message();
message.what=0;
message.obj=10;
//调用子线程中的handler对象发送消息
thread.handler.sendMessage(message);
}
});
}
}