1. 程式人生 > >android之桌布機制

android之桌布機制

android之桌布機制 
1.涉及核心類: 
1>ImageWallpaper.java(IW):繼承WallpaperService主要負責靜態桌布的draw處理; 
2>WallpaperManager.java(WM):主要負責桌布的存取方法管理(可能會多個例項); 
3>WallpaperManagerService(WMS).java:主要是對WalllpaperManager一些核心方法提供,及一些初始引數的儲存(服務); 
4>iWallpaperManager.aidl(IWM):負責WallpaperManager與WallpaperManagerService之間的通訊; 

5>IWallpaperManagerCallback(IMC).aidl:負責WallpaperManager與WallpaperManagerService之間的通訊,這是一個回撥機制與前面不同; 
6>WallpaperService.java(WS):設定桌布的引擎機制(包括動態與靜態);//這類工作時沒有修改過,所以個人瞭解不是很清楚,希望有朋友補充. 
7>launcher.java(LC)設定桌布初始化值,帶到桌布機制的轉屏. 

2. 桌布從設定存到取流程: 
1>首先WM.setBitmap(bitmap) 

public void setBitmap(Bitmap bitmap) throws IOException { 
        try { 
            ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null); 
            if (fd == null) { 

                return; 
            } 
            FileOutputStream fos = null; 
            try { 
                fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd); 
                bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos); 
            } finally { 
                if (fos != null) { 
                    fos.close(); 
                } 
            } 
        } catch (RemoteException e) { 
        } 
    } 
2>然後WMS.setWallpaper(null),設定成功會寫入到桌布相應檔案裡,檔案監聽類此時會觸發 
private final FileObserver mWallpaperObserver = new FileObserver( 
            WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) { 
                @Override 
                public void onEvent(int event, String path) { 
                    if (path == null) { 
                        return; 
                    } 
                    synchronized (mLock) { 
                        // changing the wallpaper means we'll need to back up the new one 
                        long origId = Binder.clearCallingIdentity(); 
                        BackupManager bm = new BackupManager(mContext); 
                        bm.dataChanged(); 
                        Binder.restoreCallingIdentity(origId); 

                        File changedFile = new File(WALLPAPER_DIR, path); 
                        if (WALLPAPER_FILE.equals(changedFile)) { 
                            notifyCallbacksLocked();//會發出廣播與呼叫回撥方法 
                        } 
                    } 
                } 
            }; 

//notifyCallbacksLocked()做兩件事情 
   private void notifyCallbacksLocked() { 
        final int n = mCallbacks.beginBroadcast(); 
        for (int i = 0; i < n; i++) { 
            try { 
                mCallbacks.getBroadcastItem(i).onWallpaperChanged();//回撥機制在WM實現onWallpaperChanged() 
            } catch (RemoteException e) { 

                // The RemoteCallbackList will take care of removing 
                // the dead object for us. 
            } 
        } 
        mCallbacks.finishBroadcast(); 
        final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);//桌布變化的廣播意圖 
        mContext.sendBroadcast(intent);//IW會接收到此意圖,IW.updateWallpaper()去獲取新桌布. 
    } 

3>WM.onWallpaperChanged()通過handler機制清除桌布快取 
   private final Handler mHandler; 
        
        Globals(Looper looper) { 
            IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE); 
            mService = IWallpaperManager.Stub.asInterface(b); 
            mHandler = new Handler(looper) { 
                @Override 
                public void handleMessage(Message msg) { 
                    switch (msg.what) { 
                        case MSG_CLEAR_WALLPAPER: 
                            synchronized (this) { 
                                mWallpaper = null;//使用者自定義桌布 
                                mDefaultWallpaper = null;//系統預設桌布 
                            } 
                            break; 
                    } 
                } 
            }; 
        } 
        
        public void onWallpaperChanged() { 
            /* The wallpaper has changed but we shouldn't eagerly load the 
             * wallpaper as that would be inefficient. Reset the cached wallpaper 
             * to null so if the user requests the wallpaper again then we'll 
             * fetch it. 
             */ 
            mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER); 
        } 

//IW.updateWallpaper() 

  void updateWallpaper() { 
            synchronized (mLock) { 
                try { 
                    mBackground = mWallpaperManager.getFastDrawable();//WM去獲取桌布 
                } catch (RuntimeException e) { 
                    Log.w("ImageWallpaper", "Unable to load wallpaper!", e); 
                } 
            } 
        } 
//收到桌布變換廣播 
     class WallpaperObserver extends BroadcastReceiver { 
            public void onReceive(Context context, Intent intent) { 
                updateWallpaper();//呼叫 
                drawFrame(); 
                // Assume we are the only one using the wallpaper in this 
                // process, and force a GC now to release the old wallpaper. 
                System.gc(); 
            } 
        } 

        @Override 
        public void onCreate(SurfaceHolder surfaceHolder) { 
            super.onCreate(surfaceHolder); 
            IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);// 
            mReceiver = new WallpaperObserver(); 
            registerReceiver(mReceiver, filter);//註冊 
            updateWallpaper(); 
            surfaceHolder.setSizeFromLayout(); 
        } 

4>mWallpaperManager.getFastDrawable();//WM去獲取桌布 
a.  public Drawable getFastDrawable() { 
        Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);//獲取桌布總方法 
        if (bm != null) { 
            Drawable dr = new FastBitmapDrawable(bm); 
            return dr; 
        } 
        return null; 
    } 

b. public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) { 
            synchronized (this) { 
                if (mWallpaper != null) { 
                    return mWallpaper; 
                } 
                if (mDefaultWallpaper != null) { 
                    return mDefaultWallpaper; 
                } 
                mWallpaper = null; 
                try { 
                    mWallpaper = getCurrentWallpaperLocked(context);//呼叫獲取使用者自定義桌布方法 
                } catch (OutOfMemoryError e) { 
                    Log.w(TAG, "No memory load current wallpaper", e); 
                } 
                if (mWallpaper == null && returnDefault) { 
                    mDefaultWallpaper = getDefaultWallpaperLocked(context);呼叫預設桌布方法 
                    return mDefaultWallpaper; 
                } 
                return mWallpaper; 
            } 
        } 

c. 兩方法分析 
private Bitmap getCurrentWallpaperLocked(Context context) { 
            try { 
                Bundle params = new Bundle(); 
                ParcelFileDescriptor fd = mService.getWallpaper(this, params);//WMS.getWallpaper(this, params),params是out型表示引數傳送是從WMS傳到WM,是與平時java編碼不合適習慣的這android一特性也是aidl機制的一部分;這裡留個問題就WMS是如何獲取到的params引數呢? 
                if (fd != null) { 
                    int width = params.getInt("width", 0); 
                    int height = params.getInt("height", 0); 
                    
                    if (width <= 0 || height <= 0) { 
                        // Degenerate case: no size requested, just load 
                        // bitmap as-is. 
                        Bitmap bm = null; 
                        try { 
                            bm = BitmapFactory.decodeFileDescriptor( 
                                   fd.getFileDescriptor(), null, null); 
                        } catch (OutOfMemoryError e) { 
                            Log.w(TAG, "Can't decode file", e); 
                        } 
                        try { 
                            fd.close(); 
                        } catch (IOException e) { 
                        } 
                        if (bm != null) { 
                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE); 
                        } 
                        return bm; 
                    } 
                    
                    // Load the bitmap with full color depth, to preserve 
                    // quality for later processing. 
                    BitmapFactory.Options options = new BitmapFactory.Options(); 
                    options.inDither = false; 
                    options.inPreferredConfig = Bitmap.Config.ARGB_8888; 
                    Bitmap bm = BitmapFactory.decodeFileDescriptor( 
                            fd.getFileDescriptor(), null, options); 
                    try { 
                        fd.close(); 
                    } catch (IOException e) { 
                    } 
                    
                    return generateBitmap(context, bm, width, height); 
                } 
            } catch (RemoteException e) { 
            } 
            return null; 
        } 
        
        private Bitmap getDefaultWallpaperLocked(Context context) { 
            try { 
                InputStream is = context.getResources().openRawResource( 
                        com.android.internal.R.drawable.default_wallpaper); 
                if (is != null) { 
                    int width = mService.getWidthHint(); 
                    int height = mService.getHeightHint(); 
                    
                    if (width <= 0 || height <= 0) { 
                        // Degenerate case: no size requested, just load 
                        // bitmap as-is. 
                        Bitmap bm = null; 
                        try { 
                            bm = BitmapFactory.decodeStream(is, null, null); 
                        } catch (OutOfMemoryError e) { 
                            Log.w(TAG, "Can't decode stream", e); 
                        } 
                        try { 
                            is.close(); 
                        } catch (IOException e) { 
                        } 
                        if (bm != null) { 
                            bm.setDensity(DisplayMetrics.DENSITY_DEVICE); 
                        } 
                        return bm; 
                    } 
5>WMS.getWallpaper(this, params) 
    public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb, 
            Bundle outParams) { 
        synchronized (mLock) { 
            try { 
                if (outParams != null) { 
                    outParams.putInt("width", mWidth); 
                    outParams.putInt("height", mHeight); 
                } 
                mCallbacks.register(cb); 
                File f = WALLPAPER_FILE; 
                if (!f.exists()) { 
                    return null; 
                } 
                return ParcelFileDescriptor.open(f, MODE_READ_ONLY);//ParcelFileDescriptor是google自定義的控制代碼具有安全性,對它所屬的流具體保護性,否會影象丟失出現花屏情況.我對它瞭解也不深,不遇到類似的bug. 
            } catch (FileNotFoundException e) { 
                /* Shouldn't happen as we check to see if the file exists */ 
                Slog.w(TAG, "Error getting wallpaper", e); 
            } 
            return null; 
        } 
    } 

6>呵呵呵,該畫了IW.draw(),考慮有很多東西要跟大家分享下就把IW類粘貼出來 
package com.android.internal.service.wallpaper; 

import com.android.internal.view.WindowManagerPolicyThread; 

import android.app.WallpaperManager; 
import android.graphics.Canvas; 
import android.graphics.Rect; 
import android.graphics.Region.Op; 
import android.graphics.drawable.Drawable; 
import android.os.HandlerThread; 
import android.os.Looper; 
import android.os.Process; 
import android.service.wallpaper.WallpaperService; 

相關推薦

android桌布機制

android之桌布機制  1.涉及核心類:  1>ImageWallpaper.java(IW):繼承WallpaperService主要負責靜態桌布的draw處理;  2>WallpaperManager.java(WM):主要負

Android記憶體機制分析-Android堆和棧

  Java 的堆是一個執行時資料區,類的(物件從中分配空間。這些物件通過new、newarray、anewarray和multianewarray等指令建立,它們不需要程式程式碼來顯式的釋放。堆是由垃圾回收來負責的,堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,因為它是在執行時動態分配記憶

02.AndroidIPC機制問題

目錄介紹 2.0.0.1 什麼是Binder?為什麼要使用Binder?Binder中是如何進行執行緒管理的?總結binder講的是什麼? 2.0.0.2 Android中程序和執行緒的關係?什麼是IPC?為何需要進行IPC?多程序通訊可能會出現什麼問題? 2.0

Android廣播機制—本地廣播

本地廣播: 只在程式內部進行傳遞的廣播,傳送和接收都只在本程式有效。示例程式碼: public class MainActivity extends AppCompatActivity { p

06.Android訊息機制問題

目錄介紹 6.0.0.1 談談訊息機制Hander作用?有哪些要素?流程是怎樣的? 6.0.0.2 為什麼一個執行緒只有一個Looper、只有一個MessageQueue,可以有多個Handler? 6.0.0.3 可以在子執行緒直接new一個Handler嗎?會出現什麼問題,那該怎麼做?

Android Handler 機制(用法、錯誤、原理等等)

Handler跟應用程式互動的,從網路上取得圖片,怎麼更新我們UI上面呢?這裡就用到了Handler機制,如何不用直接從子執行緒給予一個圖片更新到UI當中,會得到calss異常,不能在非Ui執行緒中直接更新UI。handler是什麼handler怎麼用呢為什麼要用handle

Android安全機制

目前支援的“sharedUserId”屬性包括“com.android.cts.shareduid”、“com.android.cts.process.uidpid_test”、“android.uid.system”、“com.android.uid.test”、“android.uid.calendar”

Android廣播機制—靜態註冊

廣播機制: 通過當前Activity里加載的佈局內的控制元件繫結監聽器,監聽器內建立Intent物件, 並給Intent的action標籤賦值(一般選擇內建標籤), 並用當前activity的物件的sendBroadcast方法將這個帶有廣播的intent物件傳送出去。 然

androidIntent機制詳解

Intent是一種執行時繫結(run-time binding)機制,它能在程式執行過程中連線兩個不同的元件。如實現兩個activity之間的連線很資料通訊 Intent it = new Intent(Activity1.this, Activity2.class);

Androidwindow機制token驗證

## 前言 很高興遇見你~ 歡迎閱讀我的文章 這篇文章講解關於window token的問題,同時也是[Context機制](https://blog.csdn.net/weixin_43766753/article/details/109017196)和[Window機制](https://blog.c

Android 最火框架XUtils註解機制具體解釋

lean uci 修飾 row 多個 mes 數組 1.2 sans 在上一篇文章Android 最火的高速開發框架XUtils中簡介了xUtils的基本用法,這篇文章說一下xUtils裏面的註解原理。 先來看一下xUtils裏面demo的代碼

Android事件分發機制原始碼分析Activity篇

在之前的事件分發分析中,曾提及到View的事件是由ViewGroup分發的,然而ViewGroup的事件我們只是稍微帶過是由Activity分發的。而我們知道,事件產生於使用者按下螢幕的一瞬間,事件生成後,經過一系列的過程來到我們的Activity層,那麼事件是怎樣從Activity傳遞

Android DNS懲罰機制

資料結構 統計資訊同樣是基於網絡卡的,所以理所當然的,這些資訊儲存在了resolv_cache_info中,該結構中與統計有關的資訊如下: struct resolv_cache_info { struct __res_params pa

Android 技能圖譜學習路線系列-Java基礎反射機制

Java反射機制 一、什麼是反射機制   JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。    二、反射機

Android開發藝術探索》學習筆記Android的訊息機制.md

《Android開發藝術探索》學習筆記之Android的訊息機制 一、概述 1、Handler的主要作用是將某個任務切換到指定的執行緒中去執行 eg:子執行緒中無法更新UI,需切換到主執行緒 V

Android訊息處理機制(二)Handler的本質-Message和Looper到底是什麼?

目錄 Android之訊息處理機制(二) 以下皆為乾貨,比較幹,需要讀者細細理解。  前面(一)已經解釋了Handler的基本機制了,下面來概括一下本質。 一、MessageQueue        MessageQueue其實就

我所理解的Android元件化通訊機制

之前寫過一篇關於Android元件化的文章,《Android元件化框架設計與實踐》,之前沒看過的小夥伴可以先點選閱讀。那篇文章是從實戰中進行總結得來,是公司的一個真實專案進行元件化架構改造,粒度會分的更粗些,是對整體架構實踐進行相應的總結,裡面說了要打造一個元件化框架的話,需要從以下7個方面入手: 程式碼解

【朝花夕拾】Android效能篇(六)Android程序管理機制

一、Android程序管理的特殊設計        Linux系統對程序的管理方式是一旦程序活動停止,系統就會結束該程序。儘管Android基於Linux Kernel,但在程序管理上,卻採取了另外一種獨特的設計:當程序活動停止時,系統並不會立刻結束它,而是會盡可能地將該程序儲存在記憶體中,在以後的某個時間,

Android面試系列Handler機制

1.什麼是Handler?   Handler是可以通過傳送和處理Message和Runnable物件來關聯相應執行緒的MessageQueue。通常我們認為它是一種非同步機制。   a.可以讓對應的Message和Runnable在未來的某個時間點進行相應的處理。   

Android的訊息機制ThreadLocal的工作原理

                       提到訊息機制大家應該都不陌生,在日常開發中不可避免地要涉及到這方面的內容。從開發的角度來說,Handler是Android訊息機制的上層介面,這使得開發過程中只需要和Handler互動即可。Handler的使用過程很簡單,通過它可以輕鬆地將一個任務切換到Handl