編輯:關於Android編程
一、Looper的兩點疑問
1) 問題一:Looper.loop()是處理消息,所有消息or部分消息?
2) 問題二:處理完消息後,結束or等待?
Android官方示例文檔代碼:
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
看看Looper的源碼就知道了:
public class Looper {
public static void prepare() {
…//初始化消息隊列
}
public static void loop() {
MessageQueue queue = me.mQueue;
while (true) {
Message msg = queue.next(); // might block
if (msg != null) {
if (msg.target == null) {
return;
}
//處理這條消息
msg.target.dispatchMessage(msg);
}
}
}
public void quit() {
Message msg = Message.obtain();
//發送一條消息。消息的內容為空。
mQueue.enqueueMessage(msg, 0);
//loop()在處理到空消息時,會結束自己。
}
}
分析源碼得知:
1) Looper. prepare()是初始化消息隊列。
2) Looper.loop()是處理所有消息。
while(true)是一個死循環,循環處理所有消息。處理完所有的消息後,依然是死循環,等待新消息的到來。
解鎖的唯一條件是:從隊列裡取出一條消息,消息的目標為空。
3) Looper.quit()是構造一個空內容的消息,放進隊列中。實質就是結束處理消息。
二、GLSurfaceView的隊列事件處理
問題一:GLSurfaceView一幀處理所有消息or部分消息?
問題二:事件隊列,對幀率有影響嗎?
看看GLSurfaceView的源碼:
public class GLSurfaceView extends SurfaceView
implements SurfaceHolder.Callback {
//插入事件隊列
public void queueEvent(Runnable r) {
mGLThread.queueEvent(r);
}
//線程中的循環邏輯
private void guardedRun(){
while (true) {//onDrawFrame的循環
while (true) {//處理消息的循環
if (! mEventQueue.isEmpty()) {
event = mEventQueue.remove(0);
break;
}
…
if (event != null) {
event.run();
event = null;
continue;
}
}//end 處理消息的循環
…
mRenderer.onDrawFrame(gl);
}
}
//內部類,線程
class GLThread extends Thread {
GLThread(Renderer renderer) {
}
@Override
public void run() {
guardedRun();
}
public void queueEvent(Runnable r) {
mEventQueue.add(r);
}
}
}
分析源碼得知:
1) 一次會處理所有消息。
2) 只要隊列裡存在消息,onDrawFrame()就得不到執行的機會。所以,消息隊列對幀率影響很大, 隨便一條新到的消息,優先級都比onDrawFrame高。
三、Java線程中的wait()和notify()
問題:有時會出現,線程之間互相等待的問題。有沒有好的解決方法?wait()?
結論:必須在同步的方法或區塊中才能調用wait()方法。所以,要進行合理的線程調度,必須編寫合理的調度邏輯,可以避免線程之間互相等待的問題(可以參考生產者-消費者模式)。
暫時不去改變801現有的線程邏輯。因為業務復雜,不方便再一個調度對象。加鎖也會降低效率。
下面給出經典的,生產者-消費者模式:
Clerk.java:
package onlyfun.caterpillar;
public class Clerk {
// -1 表示目前沒有產品
private int product = -1;
// 這個方法由生產者調用
public synchronized void setProduct(int product) {
if(this.product != -1) {
try {
// 目前店員沒有空間收產品,請稍候!
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
this.product = product;
System.out.printf("生產者設定 (%d)%n", this.product);
// 通知等待區中的一個消費者可以繼續工作了
notify();
}
// 這個方法由消費者調用
public synchronized int getProduct() {
if(this.product == -1) {
try {
// 缺貨了,請稍候!
wait();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
int p = this.product;
System.out.printf("消費者取走 (%d)%n", this.product);
this.product = -1; // 取走產品,-1表示目前店員手上無產品
// 通知等待區中的一個生產者可以繼續工作了
notify();
return p;
}
}
Producer.java:
package onlyfun.caterpillar;
public class Producer implements Runnable {
private Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("生產者開始生產整數......");
// 生產1到10的整數
for(int product = 1; product <= 10; product++) {
try {
// 暫停隨機時間
Thread.sleep((int) Math.random() * 3000);
}
catch(InterruptedException e) {
e.printStackTrace();
}
// 將產品交給店員
clerk.setProduct(product);
}
}
}
Consumer.java:
package onlyfun.caterpillar;
public class Consumer implements Runnable {
private Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
public void run() {
System.out.println("消費者開始消耗整數......");
// 消耗10個整數
for(int i = 1; i <= 10; i++) {
try {
// 等待隨機時間
Thread.sleep((int) (Math.random() * 3000));
}
catch(InterruptedException e) {
e.printStackTrace();
}
// 從店員處取走整數
clerk.getProduct();
}
}
}
概述此類是用於簡便調用系統拍照及打開相冊選擇圖片.通用於多種機型.(親測魅族MX4,三星note 2,三星note 3)前言在執行拍照和打開相冊之前,我們需要注意一下.由
最近項目上需要實現藍牙傳輸apk的一個功能,能夠搜索周圍的藍牙手機並分享文件。從需求上講android手機自帶的藍牙傳輸模塊就可以滿足需要了,實現也很簡單。不過讓人頭疼的
前言前段時間需要用到recyclerview,就想找個封裝好的下拉刷新,上拉加載的庫,結果愣是沒找到,便自己寫了一個。注意:我說的是“上拉加載”,不是滑到底部自動加載。
前言本篇博客給大家分享一個WebView的使用案例,實現Android調用JavaScript代碼來控制白天/夜間模式。關於WebView如何使用,官網有很好的說明,Bu