1. 程式人生 > >Android實戰開發:獲得螢幕物理尺寸、密度及解析度

Android實戰開發:獲得螢幕物理尺寸、密度及解析度

通過程式去了解硬體情況是一件十分有意思的事情。很早我就研究在WM6.5上獲得螢幕物理尺寸,但一直沒有成功。後來又想要在Android上有所突破,不過在今天之前得到的尺寸都不準確。雖然很多人認為沒必要這麼較真,因為貌似很多情況下用不到。不過我就當這是一件很有挑戰性的事,一定要做到。對,就是這麼任性。

原始碼中android.view包下的Display類提供了很多方法供程式設計師獲得顯示相關的資訊,通過此類讓我們開啟瞭解裝置螢幕之旅吧。

一、解析度

需要注意的原來經常使用的getHeight()與getWidth()已經不推薦使用了,建議使用getSize()來替代。

此方法原型如下:

public void getSize(Point outSize) {  
    synchronized (this) {  
        updateDisplayInfoLocked();  
        mDisplayInfo.getAppMetrics(mTempMetrics, mDisplayAdjustments);  
        outSize.x = mTempMetrics.widthPixels;  
        outSize.y = mTempMetrics.heightPixels;  
    }  
}  

引數是一個返回引數,用以返回解析度的Point,這個Point也比較簡單,我們只需要關注x和y這兩個成員就可以了。
用法如下:
private void getDisplayInfomation() {  
    Point point = new Point();  
    getWindowManager().getDefaultDisplay().getSize(point);  
    Log.d(TAG,"the screen size is "+point.toString());  
}  
結果如下:
D/MainActivity﹕ the screen size is Point(800, 1280)
此外Display又提供了一個getRealSize方法,原型如下:
public void getRealSize(Point outSize) {  
    synchronized (this) {  
        updateDisplayInfoLocked();  
        outSize.x = mDisplayInfo.logicalWidth;  
        outSize.y = mDisplayInfo.logicalHeight;  
    }  
}  
從兩個方法的實現上看是有區別的,但是在通常情況下二者的返回值相同。那麼差異究竟在哪裡,下面做一些實驗來驗證一下。

首先,我將Acitvity設定不同的theme,比如:
android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"  
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  
結果還是相同的。

接下來將我的Activity父類變成ActionBarActivity,如下:
public class MainActivity extends ActionBarActivity
期望ActionBar會佔用一些螢幕,並在程式中動態設定Listview的Item中的圖片大小。在機緣巧合之下,
結果驗證了在這種情況下,getSize返回的結果變了。
程式碼如下:
private void getDisplayInfomation() {  
    Point point = new Point();  
    getWindowManager().getDefaultDisplay().getSize(point);  
    Log.d(TAG,"the screen size is "+point.toString());  
    getWindowManager().getDefaultDisplay().getRealSize(point);  
    Log.d(TAG,"the screen real size is "+point.toString());  
}  

Log如下:
D/MainActivity﹕ the screen size is Point(800, 1202)  
D/MainActivity﹕ the screen real size is Point(800, 1280) 
如果你不能夠輕易復現也不用急,保險起見,為了得到相對正確的資訊還是使用getRealSize()吧。

二、螢幕尺寸

裝置的物理螢幕尺寸。與幾年前不同,目前的手機螢幕已經大到一隻手握不下了。標配早已經到了5寸屏時代。
所謂螢幕尺寸指的是螢幕對角線的長度,單位是英寸。
然而不同的螢幕尺寸是可以採用相同的解析度的,而它們之間的區別在與密度(density)不同。

下面先介紹一下密度的概念,DPI、PPI,最後講解一下如何根據獲得的Display資訊去求出螢幕尺寸。這是一個困擾我很久的問題了。

方法一:

WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
int height = wm.getDefaultDisplay().getHeight();
方法二:
WindowManager wm1 = this.getWindowManager();
int width1 = wm1.getDefaultDisplay().getWidth();
int height1 = wm1.getDefaultDisplay().getHeight();
方法三:
WindowManager manager = this.getWindowManager();
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
int width = outMetrics.widthPixels;
int height = outMetrics.heightPixels;
方法四:
Resources resources = this.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
float density = dm.density;
int width = dm.widthPixels;
int height = dm.heightPixels;

三、螢幕密度

螢幕密度與DPI這個概念緊密相連,DPI全拼是dots-per-inch,即每英寸的點數。也就是說,密度越大,每英寸內容納的點數就越多。
android.util包下有個DisplayMetrics類可以獲得密度相關的資訊。
最重要的是densityDpi這個成員,它有如下幾個常用值:
DENSITY_LOW = 120  
DENSITY_MEDIUM = 160  //預設值  
DENSITY_TV = 213      //TV專用  
DENSITY_HIGH = 240  
DENSITY_XHIGH = 320  
DENSITY_400 = 400  
DENSITY_XXHIGH = 480  
DENSITY_XXXHIGH = 640  
舉例如下:
private void getDensity() {  
    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();  
    Log.d(TAG,"Density is "+displayMetrics.density+" densityDpi is "+displayMetrics.densityDpi+" height: "+displayMetrics.heightPixels+  
        " width: "+displayMetrics.widthPixels);  
}  

Log如下:
  1. the screen size is Point(1600, 2438)  
  2. the screen real size is Point(1600, 2560)  
  3. Density is 2.0 densityDpi is 320 height: 2438 width: 1600 

有了這些資訊,我們是不是就可以計算螢幕尺寸了呢?
首先求得對角線長,單位為畫素。
然後用其除以密度(densityDpi)就得出對角線的長度了。
程式碼如下:
private void getScreenSizeOfDevice() {  
    DisplayMetrics dm = getResources().getDisplayMetrics();  
    int width=dm.widthPixels;  
    int height=dm.heightPixels;  
    double x = Math.pow(width,2);  
    double y = Math.pow(height,2);  
    double diagonal = Math.sqrt(x+y);  
  
    int dens=dm.densityDpi;  
    double screenInches = diagonal/(double)dens;  
    Log.d(TAG,"The screenInches "+screenInches);  
} 

Log如下:
01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen size is Point(1600, 2438)  
01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ the screen real size is Point(1600, 2560)  
01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ Density is 2.0 densityDpi is 320 height: 2438 width: 1600 xdpi 338.666 ydpi 338.666  
01-13 16:35:03.026  16601-16601/com.linc.listviewanimation D/MainActivity﹕ The screenInches 9.112922229586951  
如Log所見,使用heightPixels得出的值是2483而不是正確的2560.從而使結果9.11反倒跟真實螢幕尺寸很接近。下面用正確的height再算一遍。
結果是9.43英寸,而真實值是8.91.如果再換一個裝置,那麼值差的更多。說明上面的計算是錯誤的。
那麼錯在哪裡呢?densityDpi是每英寸的點數(dots-per-inch)是印表機常用單位(因而也被稱為列印解析度),而不是每英寸的畫素數。下面引出PPI這個概念。

四、PPI

Pixels per inch,這才是我要的每英寸的畫素數(也被稱為影象的取樣率)。有了這個值,那麼根據上面的公式就可以求匯出螢幕的物理尺寸了。
還好DisplayMetrics有兩個成員是xdpi和ydpi,對其描述是:
//The exact physical pixels per inch of the screen in the X/Y dimension. 
螢幕X/Y軸上真正的物理PPI。
Yes!Got it!
為了保證獲得正確的解析度,我還是使用getRealSize去獲得螢幕寬和高畫素。所以,經過修改,程式碼如下:
private void getScreenSizeOfDevice2() {  
    Point point = new Point();  
    getWindowManager().getDefaultDisplay().getRealSize(point);  
    DisplayMetrics dm = getResources().getDisplayMetrics();  
    double x = Math.pow(point.x/ dm.xdpi, 2);  
    double y = Math.pow(point.y / dm.ydpi, 2);  
    double screenInches = Math.sqrt(x + y);  
    Log.d(TAG, "Screen inches : " + screenInches);  
}  
Log如下:
01-13 16:58:50.142  17249-17249/com.linc.listviewanimation D/MainActivity﹕ Screen inches : 8.914015757534717  

五、DIP

注意不要與上面的DPI混淆,這個DIP是Density Independent Pixel,直譯為密度無關的畫素。
我們在佈局檔案中使用的dp/dip就是它。官方推薦使用dp是因為它會根據你裝置的密度算出對應的畫素。
公式為:pixel = dip*density

需要注意的是,我們在Java程式碼中對控制元件設定寬高是不可以設定單位的,而其自帶的單位是畫素。所以如果動態修改控制元件大小時,
我們的任務就來了,那就是將畫素轉換為dp。
例項程式碼如下:
//pixel = dip*density;  
private int convertDpToPixel(int dp) {  
    DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
    return (int)(dp*displayMetrics.density);  
}  
  
private int convertPixelToDp(int pixel) {  
    DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();  
    return (int)(pixel/displayMetrics.density);  
}   




相關推薦

Android實戰開發:獲得螢幕物理尺寸密度解析度

通過程式去了解硬體情況是一件十分有意思的事情。很早我就研究在WM6.5上獲得螢幕物理尺寸,但一直沒有成功。後來又想要在Android上有所突破,不過在今天之前得到的尺寸都不準確。雖然很多人認為沒必要這麼較真,因為貌似很多情況下用不到。不過我就當這是一件很有挑戰性的事,一定要做

Android中獲取螢幕物理尺寸的方法

第一種方法 //獲取螢幕寬度 int screenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)

android獲取螢幕尺寸密度(判斷手機螢幕型別)

1. 概念介紹 解析度:橫縱2個方向的畫素點的數量,常見取值 480X800 ,320X480 螢幕大小: 例如我的是4.0 英寸, 就是指 從螢幕的左上角 到 螢幕的右下角 連線長度為4.0英寸(可以換成釐米) density : 直接翻譯的話貌似叫 密度

Android定位開發之百度定位高德定位騰訊定位,三足鼎立一起為我所用!

這幾天的專案不是很緊,於是想為未來可能要做的專案做一些技術儲備。 下一個專案很有可能是定位開發,需要用到手機定位功能,於是查了查現在比較流行的第三方定位,最火的基本上就是百度定位>高德定位>騰訊定位了。 想了想不如做一個DEMO把三種定位方式混合一下試試。 Ba

Android應用開發---SQLiteOpenHelper管理SQLite資料庫ListView

1、SQLiteOpenHelper的介紹: A helper class to manage database creation and version management. 也就是說SQLiteOpenHelper用來管理建立一個數據庫和管理資料庫的版本。 建立一

android進階4step4:Android實戰開發——事件分發機制

Android事件分發機制 為什麼需要事件分發機制? 比如:上圖 Button(View)的ViewGroup是FrameLayout2 FragmeLayout2的ViewGroup是FragmeLayout1 當點選Button時,所觸發的事件到底是交給誰來

Android WiFi開發 (一)掃描連線資訊

在平常開發中經常會涉及到wifi相關的內容,在此將之前所用到的整理一下,以免忘記。操作wifi的相關類,主要放在android.net.wifi包下面。使用wifi相關方法需要申請一些許可權: 申請許可權方式:在AndroidManifest.xml檔案中填寫<uses

Android實戰開發:自定義照相機

參考資料: 感謝以上大神們的的無私分享! 之前在公司寫了一個自定義CameraView,年代久遠,回頭看程式碼時居然有點看不懂了。。。 真是好記性不如爛筆頭啊~ 趁著年底不忙有時間,再次重寫下Camera,話不多說,開始擼程式碼。 1.許可

Android中獲取當前螢幕尺寸大小

<supports-screens android:smallScreens="true" android:normalScreens="t

Android Vendor Test Suite (VTS) 的概念作用測試方法--

Android Vendor Test Suite (VTS) 的概念、作用及測試方法 Qidi 2017.08.01 (Markdown & H

RK3128系統&驅動開發分享——(二)編譯燒錄

燒錄工具及文件:連結:https://pan.baidu.com/s/1jIvihSE 密碼:y67p本文主要講解三部分:一、編譯原理流程講解二、打包指令碼講解三、生成檔案及燒錄講解一、編譯原理流程講解. build/envsetup.sh 配置命令環境(執行原始碼目錄下的b

Android Vendor Test Suite (VTS) 的概念作用測試方法

轉載:http://blog.csdn.net/qidi_huang/article/details/76653677 注意:本文基於 Android 8.0 進行分析 1、前言 - Project Treble   Android 目前有一個比較明顯的缺點是裝置

Android降低UI渲染速度的檢測診斷修復

一. Slow rendering - jank 為了保證UI互動的流暢,必須保證每幀的渲染時間不超過16毫秒,保證60的FPS。 一旦介面有較慢的渲染,系統將強制跳幀,使用者就會感覺到卡頓。 We call this jank. 二. 定位jank

[開源地址] 放棄Flink,.NET5.0開發CSharpFlink,簡要設計部署二次開發說明。

github地址:https://github.com/wxzz/CSharpFlinkgitee地址:https://gitee.com/wxzz/CSharpFlink  1 概述及背景       我們有一個全國性質的面向工業的公

android開發螢幕尺寸問題

首先了解幾個常見尺寸單位的意義: px(Pixel):畫素點的個數,我們常說的1080*1920指的是橫向尺寸上有1080個畫素點,縱向尺寸上有1920個點。 螢幕尺寸:一般我們說的尺寸指的是手機對角線的長度。 DPI(Dots Per Inch):翻譯成中文就是每英寸的點數,意思就是每

iPhone螢幕尺寸邏輯解析度物理解析度畫素密度 (2018)

新增 iPhoneXs、iPhoneXR、iPhoneXs Max的螢幕尺寸 裝置 iPhone 寬 Width 高 Hei

android螢幕解析度密度尺寸pxdp等

1.什麼是螢幕尺寸、解析度和畫素密度? 螢幕尺寸 單位:英寸(inch) 1英寸 = 2.54釐米 目前市場上螢幕尺寸以5.5英寸為主(Android 2018年),資料由【友盟】提供。 推薦大家去看下,是一家資料統計網站,國內是比較知名的統計網站和工具。

iOS 螢幕尺寸邏輯解析度物理解析度之間的相互關係

型號 螢幕尺寸(inch) 邏輯解析度(point) 縮放因子(scale factor) 物理解析度(pixel) 畫素密度(PPI) iPhone3GS 3.5 320 * 480 @1x 320 * 48

android 獲取螢幕物理尺寸

計算方法:獲取到螢幕的解析度:point.x和point.y,再取出螢幕的DPI(每英寸的畫素數量),計算長和寬有多少英寸,即:point.x / dm.xdpi,point.y / dm.ydpi,螢幕的長和寬算出來了,再用勾股定理,計算出斜角邊的長度,即螢幕尺寸。/**

android獲得螢幕高度和寬度狀態列高度

android獲取螢幕的高度和寬度用到WindowManager這個類,兩種方法: WindowManager wm = (WindowManager) getContext()