当前位置:首页 > 测评资讯 > 正文内容

设备文件 分辨率 获取 android,获得Android手机分辨率

一、Android 屏幕分辨率适配

Android屏幕分辨率千奇百怪,怎么让app在不同的分辨率的设备上“看起来一样”呢?

你也许还有以下疑惑:

这篇文章将会针对以上问题一一解答。

Pixels我们看到屏幕上的图像由一个个像素组成,像素里包含色彩信息。

如常说的手机分辨率:1080 x 1920指的是手机宽度可展示1080像素,高度可展示1920像素。

Pixels Per Inch每英寸长度所具有的像素个数,单位面积内像素越多,图像显示越清晰。

ppi一般用在显示器、手机、平板等描述屏幕精细度。

Dots Per Inch每英寸长度所具有的点数。

dpi一般用来描述打印(书本、杂志、电报)的精细度

density-independent pixels(device-independent pixels我查了一下,**更多时候使用前者,有的时候也显示后者),dip是缩写,也可以更简单些称作dp。该单位的目的是屏蔽不同设备密度差异,后面细说。

Scalable pixels用于设置字体,在用户更改字体大小时候会适配。

澄清了基本概念,我们现在从一个例子开始说明以上单位之间的区别与联系。

布局文件里有个View,长宽都是200px,分别在分辨率为480(宽)x800(高)简称A设备、1080(宽)x1920(高)简称B设备,效果如下:

左边是A设备,右边是B设备。问题出来了,同样长宽都是200px,为啥A设备显示很大,B设备显示很小呢?你可能会说B设备的横向分辨率1080比A设备的480大,所以在B设备上看起来比较小。来看看A、B设备横向到底是多少英寸,怎么来计算呢?这时候就需要用到ppi了,既然知道横向的像素点个数,也知道每英寸能容纳的像素点,当然可以得知横向的尺寸了。

其中一种方式获取DisplayMetrics对象:

A设备宽度尺寸:480(px)/240(ppi)=2inch

B设备宽度尺寸:1080(px)/420(ppi)=2.5inch

可以看出,A、B设备尺寸差别不大。A设备ppi=240 B设备ppi=420,明显地看出B设备单位长度上比A设备能够容纳更多的像素,因此同样的200px,B设备只需要较小的尺寸就能够显示,因此在B设备上的view看起来比A设备小很多。

知道了问题的原因,然而显示的效果却不能接受。

我们总不能自己判断每个设备的ppi,然后计算实际需要多少像素,再动态设置view的大小吧,那layout里的静态布局大小就无法动态更改适应了。想当然的能有一个统一的地方替我们转换,没错!Android系统已经帮我们实现了转换。接下来就是dpi、dp出场了。

Android系统使用dpi来描述屏幕的密度,使用dp来描述密度与像素的关系。

A设备dpi=240

B设备dpi=420

Android系统终识别的单位是px,怎么将dpi和px关联起来呢?,答案是dp。

Android规定当dpi=160时,1dp=1px,当dpi=240时,1dp=1.5px,依此类推,并且给各个范围的dpi取了简易的名字加以直观的识别,如120<dpi<=160,称作为mdpi,120<dpi<=240称作hdpi,终形成如下规则:

现在知道了dp能够在不同dpi设备上对应不同px,相当于中间转换层,我们只需要将view长宽单位设置为合适的dp,就无需关注设备之间密度差异,系统会帮我们完成dp-px转换。将我们之前的例子稍微更改,再看看效果验证一下:

通过上面对dp的了解,我们知道在设定view大小、间距时使用dp能大限度地屏蔽设备密度之间的差异。可能你就会问了,那**tmap展示的时候如何适配不同密度的设备呢?

自定义view从磁盘上加载一张图片,并将之显示在view上,view的大小决定于**tmap大小。依旧以上述A、B设备为例,展示结果如下:

左边是A设备,右边是B设备。

明显地看出,在A设备显示比B设备大很多,实际上和我们之前用px来描述view的大小原理是一样的,**tmap的宽、高都是px在描述,而**tmap决定了view的宽、高,终导致A设备和B设备上的view大小(宽、高像素)是一样的,而它们屏幕密度又不相同,因此产生了差异。

那不会每次都需要我们自己根据屏幕密度来转换**tmap大小吧?幸运的是,Android已经为我们考虑到了。

生成不同密度的目录有什么作用?

A设备dpi=240,根据dpi范围,属于hdpi

B设备dpi=420,根据dpi范围,属于xxhdpi

图片原始尺寸:photo1.jpg(宽高 172px-172px)

当我们想要在不同密度设备上显示同一张图片并且想要“看起来一样大时”。假设设计的时候以hdpi为准,放置photo1.jpg为172*172,那么根据计算规则在xxhdpi上需要设置photo1.jpg为:

现在hdpi和xxhdpi目录下分别存放了同名图片:photo1.jpg,只是大小不同。当程序运行的时候:

来看看效果:

左边A设备,右边B设备

针对不同的密度设计不同的图片大小,大限度保证了同一图片在不同密度设备上表现“看起来差不多大”。

来看看A、B设备上图片占内存大小:

说明在B设备上显示photo1.jpg需要更多的内存。

上边只是列举了hdpi、xxhdipi,同理对于mdpi、xhdpi、xxxhdpi根据规则放入相应大小的图片,程序会根据不同的设备密度从对应的mipmap文件夹下加载资源。如此一来,我们无需关注**tmap在不同密度设备上显示问题了。

在mipmap各个文件夹下都放置同一套资源的不同尺寸文件似乎有点太占apk大小,能否只放某个密度下图片,其余的靠系统自己适配呢?

现在只保留hdpi下的photo1.jpg图片,看看在A、B设备上运行情况如何:

看起来和上张图差不多,说明系统会帮我们适配B设备上的图片。

再来看看A、B设备上图片占内存大小:

先看A设备:

对比photo1.jpg分别放在hdpi、xxhdpi和只放在hdpi下可以看出:B设备上图片所占内存变小了。为什么呢?接下来从源码里寻找答案。

A、B设备同样加载hdpi/photo1.jpg,返回的**tmap大小不相同,我们从这方法开始一探究竟。

上面涉及到的关键点是density,分别是TypedValue的density和Options的density。

先来看看TypedValue density:

再来看看Options density

现在分析B设备加载hdpi/photo1.jpg如何做的:

和我们之前调试的结果一致。

B设备是怎么决定使用hdpi下的图片资源呢?

根据实验(尝试找了源码,没怎么看懂,因此只是做了实验,可能在不同密度设备上找寻规则不一样):B设备先找属于自己密度范围文件夹下的图片,B设备属于xxhdpi,先查看xxhdpi有没有photo1.jpg,如果没有则往更高的密度找,比它高的密度是xxxhdpi,还是没有,则往低密度找,找xhdpi,没有再找hdpi,找到了则返回构造好的TypedValue,剩下的就是我们前面分析的。

既然我们只想放某个密度下的一份切图,该放哪个密度下呢?从系统寻找规则看,更推荐放置在更高密度下的,因为如果放在低密度下,那么当运行在高密度设备上时,图片会进行放大,可能导致不清晰。我一般习惯放在xxhdpi下。

Android Studio默认创建了不同密度的mipmap文件夹,默认放置了ic_launcher.png。我们普通的切图该放drawable还是mipmap下呢?对于这个问题网上也是众说纷纭,实际上对于我们来说,关注的重点是图片放在drawable或者mipmap,加载出来**tmap是否有差异,如果没有差异放在哪就看习惯了。通过实践,普通的切图放drawable和mipmap下加载出来的**tmap是没有差异的,只不过用drawable的话需要自己创建不同密度的文件夹。我习惯于放在drawable下(启动图标logo还是放在mipmap下)。

前边 [注1]留了个问题,我们使用dp来表示view的大小了,为啥两个看起来还是有些差距?下面我们更加直观地看一个例子。

A设备dpi=240密度1.5分辨率(宽高px):480* 800

B设备dpi=420密度2.625分辨率(宽高px):1080* 1794

换算成dp

A设备分辨率:320dp* 533dp

B设备分辨率:411dp* 683dp

依旧是上边的例子:

将view宽高分别设置为320dp,看看效果:

左边A设备,右边B设备

可以看出同样的320dp大小,A设备铺满了屏幕,而B设备没有。这效果显然是不能接受的,Android考虑到不同设备宽高不同,推出了"宽高限定符"。以A、B设备为例:

在res文件夹下创建文件夹:

假设设计师出图是按照800x480,那么我们创建dimen文件的时候

该文件放在values-800x480文件夹下。

根据分辨率比例算出1794x1080的dimen值

这样子,A、B设备加载资源的时候使用对应分辨率限定符下的px,如果找不到再找默认值,可以在一定程度上解决屏幕宽高碎片化适配问题。

但是这样子的限定比较严格,需要测试各种分辨率,后来Android又推出了"**allest-width"简称小宽度限制。

A设备宽320dp

B设备宽411dp

假设设计师切图标准屏幕宽是320dp(A设备),那么可以定义如下dimen.xml文件

该文件放在values-sw320dp文件夹下

根据规则,计算B设备dimen.xml

现在我们继续来看之前的view

通过对dimen引用,A设备寻找和自己宽度一样的dimen文件,找到values-sw320dp,dp320=320dp。B设备寻找和自己宽度一样的dimen文件,找到values-sw411dp,dp320=410dp。这样子同样的dp320,得出不同的值,就适配了屏幕宽度不同的问题。

看看效果:

这次B设备也铺满了屏宽。

综上,为了适配不同屏幕大小,推荐使用dp+**allest-width。

获取设备dpi终都是从这方法获取的,实际上就是读取系统的配置文件。因此我们也可以通过adb shell获取:

可以看出dpi是系统配置好的,当然有些手机是可以设置分辨率的,设置之后我们查看分辨率:

分辨率变低了,dpi也变小了。

二、android dip 对应多少像素

下面以480dip*800dip的WVGA(density=240)为例,详细列出不同density下屏幕分辨率信息:

当density=120时屏幕实际分辨率为240px*400px(两个点对应一个分辨率)

状态栏和标题栏高各19px或者25dip

横屏是屏幕宽度400px或者800dip,工作区域高度211px或者480dip

竖屏时屏幕宽度240px或者480dip,工作区域高度381px或者775dip

density=160时屏幕实际分辨率为320px*533px(3个点对应两个分辨率)

状态栏和标题栏高个25px或者25dip

横屏是屏幕宽度533px或者800dip,工作区域高度295px或者480dip

竖屏时屏幕宽度320px或者480dip,工作区域高度508px或者775dip

density=240时屏幕实际分辨率为480px*800px(一个点对于一个分辨率)

状态栏和标题栏高个38px或者25dip

横屏是屏幕宽度800px或者800dip,工作区域高度442px或者480dip

竖屏时屏幕宽度480px或者480dip,工作区域高度762px或者775dip

apk的资源包中,当屏幕density=240时使用hdpi标签的资源

当屏幕density=160时,使用mdpi标签的资源

当屏幕density=120时,使用ldpi标签的资源。

不加任何标签的资源是各种分辨率情况下共用的。

建议:布局时尽量使用单位dip,少使用px。

device independent pixels(设备独立像素).不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA推荐使用这个,不依赖像素。

import android.content.Context;

import android.util.DisplayMetrics;

//计算公式 pixels= dips*(density/ 160)

public class DensityUtil{

private static final String TAG= DensityUtil.class.getSimpleName();

//当前屏幕的densityDpi

private static float dmDensityDpi= 0.0f;

private static DisplayMetrics dm;

private static float scale= 0.0f;

public DensityUtil(Context context){

//获取当前屏幕

dm= new DisplayMetrics();

//返回当前资源对象的DispatchMetrics信息。

dm= context.getApplicationContext().getResources().getDisplayMetrics();

//设置DensityDpi

setDmDensityDpi(dm.densityDpi);

//密度因子

scale= getDmDensityDpi()/ 160;//等于 scale=dm.density;

Logger.i(TAG, toString());

}

public static float getDmDensityDpi(){

return dmDensityDpi;

}

public static void setDmDensityDpi(float dmDensityDpi){

DensityUtil.dmDensityDpi= dmDensityDpi;

}

public static int dip2px(float dipValue){

return(int)(dipValue* scale+ 0.5f);

}

public int px2dip(float pxValue){

return(int)(pxValue/ scale+ 0.5f);

}

@Override

public String toString(){

return" dmDensityDpi:"+ dmDensityDpi;

}

}

其它的:

//dip转像素

public static int DipToPixels(Context context,int dip){

final float SCALE= context.getResources().getDisplayMetrics().density;

float valueDips= dip;

int valuePixels=(int)(valueDips* SCALE+ 0.5f);

return valuePixels;

}

//像素转dip

public static float PixelsToDip(Context context,int Pixels){

final float SCALE= context.getResources().getDisplayMetrics().density;

float dips=Pixels/ SCALE;

return dips;

}

//指定图片长宽生成新图片

public static Bitmap decodeBitmap(Bitmap initialBitmap, int height, int weight){

int bmpHeight= initialBitmap.getHeight();

int bmpWeight= initialBitmap.getWidth();

float scale= Math.min(height/ bmpHeight, weight/ bmpWeight);

Bitmap mutableBitmap= Bitmap.createScaledBitmap(initialBitmap,(int)(bmpWeight* scale),(int)(bmpHeight* scale), true);//指定图片长宽,生成新图片

return mutableBitmap;

}

//将Bitmap另存为指定的JPG文件

public static void writePhotoJpg(Bitmap data, String pathName){

File file= new File(pathName);

try{

file.createNewFile();

// BufferedOutputStream os= new BufferedOutputStream(

// new FileOutputStream(file));

FileOutputStream os= new FileOutputStream(file);

datapress(Bitmap.CompressFormat.JPEG, 100, os);

os.flush();

os.close();

MyDebug.i("writePhotoJpg");

} catch(Exception e){

e.printStackTrace();

}

}

//将Bitmap另存为指定的PNG文件

public static void writePhotoPng(Bitmap data, String pathName){

File file= new File(pathName);

try{

file.createNewFile();

FileOutputStream os= new FileOutputStream(file);

// BufferedOutputStream os= new BufferedOutputStream(

// new FileOutputStream(file));

datapress(Bitmap.CompressFormat.PNG, 100, os);

os.flush();

os.close();

MyDebug.i("writePhotoPng");

} catch(Exception e){

e.printStackTrace();

}

}

三、如何用adb命令***获得Android手机分辨率

在命令行中输入“adb shell”;进入shell之后,再输入“cat/system/build.prop grep"product"”设备信息主要是存放在“/system/build.prop”文件,通过“cat”命令就可以查看了。

拓展资料:

adb的全称为Android Debug Bridge,就是起到调试桥的作用。通过adb我们可以在Eclipse中方便通过DDMS来调试Android程序,说白了就是debug工具。

它的主要功能有:

*运行设备的shell(命令行)

*管理模拟器或设备的端口映射

*计算机和设备之间上传/**文件

*将本地apk软件安装至模拟器或android设备

参考资料:adb驱动—百度百科

最新发布