现在的Android手机屏幕越来越多,工作面试的时候很多同学都不是很清楚屏幕适配的问题, 网上其实有很多类似的说明,其实大同小异都是翻译google 官方贵的说明,希望大家有时间多学习官方api,这里我也做一下笔记:
屏幕的实际大小,用屏幕对角线长度来衡量(比如3.4寸,3.8寸,4.3寸,5寸,7寸等)。
android把屏幕分为以下4种:small,normal,large,extra large等。
一块实际的屏幕区域有多少个像素,一般用dpi衡量(每英寸有多少个点)。
android把屏幕密度分为4种:low,medium,high,extra high。 手机可以有相同的分辨率,但屏幕尺寸可以不相同, Diagonal pixel表示对角线的像素值(=),DPI=933/3.7=252 android将实际的屏幕密度分为四个通用尺寸(low,medium,high,and extra high) 一般情况下的普通屏幕:ldpi是120dpi,mdpi是160dpi,hdpi是240dpi,xhdpi是320dpi 对于屏幕来说,dpi越大,屏幕的精细度越高,屏幕看起来就越清楚 。
屏幕方向分为landscape(横屏)和portrait(竖屏)。
屏幕上的总实际像素数。对屏幕进行适配时,一般不关注它的分辨率,只关注它的屏幕大小和密度。与密度无关的像素(Density-independent pixel,dp或dip) - 为了保证你的UI适合不同的屏幕密度,建议你采用dp来定义程序UI。它的计算方法为:px = dp * (dpi / 160)。
sp(scale-independent pixel)
如何分辨一个屏幕是ldpi、mdpi、hdpi的方法:
在manifest里定义你的程序支持的屏幕类型,相应代码如下:
<supports-screens android:resizeable=["true"| "false"] android:smallScreens=["true" | "false"] //是否支持小屏 android:normalScreens=["true" | "false"] //是否支持中屏 android:largeScreens=["true" | "false"] //是否支持大屏 android:xlargeScreens=["true" | "false"] //是否支持超大屏 android:anyDensity=["true" | "false"] //是否支持多种不同密度的屏幕 android:requiresSmallestWidthDp=”integer” android:compatibleWidthLimitDp=”integer” android:largestWidthLimitDp=”integer”/>
android:anyDensity=["true" | "false"]
如果android:anyDensity="true"
指应用程序支持不同密度,会根据屏幕的分辨率自动去匹配。
如果android:anyDensity="false"
应用程序支持不同密度,系统自动缩放图片尺寸和这个图片的坐标。具体解释一下系统是如何自动缩放资源的。
例如我们在hdpi,mdpi,ldpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源,这种情况都是出现在高密度,以及低密度的手机上,比如说一部240×320像素的手机,
如果设置android:anyDensity="false",Android系统会将240 x 320(低密度)转换为 320×480(中密度),这样的话,应用就会在小密度手机上加载mdpi文件中的资源。
android:largeScreens=["true" | "false"]
如果在声明不支持的大屏幕,而这个屏幕尺寸是larger的话,系统使用尺寸为("normal")和密度为("medium)显示, 不过会出现一层黑色的背景。
android:smallScreens=["true" | "false"]
如果在声明不支持的小屏幕,而当前屏幕尺寸是smaller的话,系统也使用尺寸为("normal")和密度为("medium)显示 .
如果应用程序能在小屏幕上正确缩放(最低是small尺寸或最小宽度320dp),那就不需要用到本属性。否则,就应该为最小屏幕宽度标识符设置本属性
来匹配应用程序所需的最小尺寸。
比如,如果需要对大小为large的屏幕提供支持,需要在res目录下新建一个文件夹layout-large/并提供layout。当然,也可以在res目录下建立layout-port和layout-land两个目录,里面分别放置竖屏和横屏两种布局文件,以适应对横屏竖屏自动切换。
res/layout
res/layout-small res/layout-normal res/layout-large res/layout-xlarge
android 新版本支持: res/layout-mdpi res/layout-hdpi res/layout-xhdpi
Android 4.0版本 之后支持layout-mdpi、layout-hdpi 这种写法。
1) 应尽量使用点9格式的图片,使用draw9图片则不需要适配,会自动进行拉伸。
2) 使用位图则需要针对不同的屏幕放置合适大小的图,在res目录下建立对应的包,Android有个自动匹配机制去选择对应的布局和图片资源。
3) Android平台中支持一系列你所提供的指定大小(size-specific),指定密度(density-specific)的合适资源。指定大小(size-specific)的合适资源是指small, normal, large, and xlarge。指定密度(density-specific)的合适资源,是指ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high).
drawable drawable-ldpi drawable-mdpi drawable-hdpi drawable-xhdpi drawable-nodpi drawable-nodpi-1024×600 drawable-nodpi-1280×800 drawable-nodpi-800×480
4) 图片大小的确定:low:medium:high:extra high比例为3:4:6:8。举例来说,对于中等密度(medium)的屏幕你的图片像素大小为48×48,那么低密度(low)屏幕的图片大小应为36×36,高(high)的为72×72,extra high为96×96。
通常情况下从开发角度讲,应用程序会根据3类Android手机屏幕提供3套UI布局文件,但是相应界面图标也需要提供3套:
Icon Type
Standard Asset Sizes (in Pixels), for Generalized Screen Densities
App
ldpi
mdpi
hdpi
xhdpi
Launcher
36 x 36 px
48 x 48 px
72 x 72 px
96 x96 px
Menu
36 x 36 px
48 x 48 px
72 x 72 px
96 x96 px
Status Bar
24 x 24 px
32x32 px
48 x 48 px
72 x 72 px
Tab
24 x 24 px
32x32 px
48 x 48 px
72 x 72 px
Dialog
24 x 24 px
32x32 px
48 x 48 px
72 x 72 px
List View
24 x 24 px
32x32 px
48 x 48 px
72 x 72 px
在layout文件中设置控件尺寸时应采用wrap_content,fill_parent,match_parent和dp。
为了使文字大小更好的适应屏幕应该使用sp来定义文字大小。
layout_weight属性尽量不要嵌套使用。如父节点已经使用了weight属性,则子节点尽量避免使用。
为了使代码简单,android内部使用pix为单位表示控件的尺寸,但这是基于当前屏幕基础上的。为了适应多种屏幕,android建议开发者不要使用具体的像素来表示控件尺寸。
布局文件中的所有文字大小以及控件大小都必须申明在xml配置文件中,values/dimens.xml,不同的屏幕定义不同的大小,可以很好的适配。
values values-ldpi values-mdpi values-hdpi values-xhdpi values-nodpi values-nodpi-1024×600 values-nodpi-1280×800 values-nodpi-800×480
1)不要使用AbsoluteLayout(android1.5已废弃) 。
2)尽量使用RelativeLayout,如果必须使用权重则可以考虑RelativeLayout和LinearLayout混合使用。
3)需要根据物理尺寸的大小准备多套布局:
layout(放一些通用布局xml文件,比如界面中顶部和底部的布局,不会随着屏幕大小变化。
layout-mdpi (屏幕尺寸小于3.5英寸左右的布局)
layout-hdpi (屏幕尺寸小于4英寸左右)
layout-xhdpi(4.5英寸-7英寸之间)
3.5 根据屏幕大小计算
如果有些时候需要自定义控件,空间大小特别严格的话,可以考虑获取当前屏幕大小进行计算分割。
DisplayMetrics metric = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metric); int width = metric.widthPixels; // 屏幕宽度(像素) int height = metric.heightPixels; // 屏幕高度(像素) float density = metric.density; // 屏幕密度(0.75 / 1.0 / 1.5) int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240)
可以在配置Activity的地方进行如下的配置
android:screenOrientation="portrait"
android:screenOrientation="landscape"
或者 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
这样就可以保证是竖屏总是竖屏了,或者横屏总是横屏。
若要软件在横竖屏之间切换,由于横竖屏的高宽会发生转换,有可能会要求不同的布局。可以通过以下方法来切换布局:
1)layout-land和layout-port
在res目录下建立layout-land(横屏的layout)和layout-port(竖屏的layout)目录,相应的layout文件不变,比如main.xml。其他的不用管,模拟器会自动寻找。
2)onCreate()中判断横竖屏
通过this.getResources().getConfiguration().orientation判断当前是横屏还是竖屏,然后加载相应的xml布局文件。因为当屏幕变为横屏的时候,系统会重新呼叫当前Activity的OnCreate方法,你可以把以下方法放在你的OnCreate中来检查当前的方向,然后可以让你的SetContentView来载入不同的Layout xml.
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.i("info", "landscape");
}
else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
Log.i("info", "portrait");
}
这种方法缺点是动态适应差。比如横竖屏切换时需要你自己写代码来使用不同的layout等resource,语言设置的动态改变等.
首先要在配置Activity的时候进行如下的配置:
<activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="@string/app_name">
另外需要重写Activity的onConfigurationChanged方法。实现方式如下,不需要做太多的内容:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
1.http用gzip压缩,设置连接超时时间和响应超时时间
http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读。
2.listview 性能优化
1).复用convertView
在getItemView中,判断convertView是否为空,如果不为空,可复用。如果couvertview中的view需要添加listerner,代码一定要在if(convertView==null){}之外。
2).异步加载图片
item中如果包含有webimage,那么最好异步加载
3).快速滑动时不显示图片
当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来
3.使用线程池,分为核心线程池和普通线程池,下载图片等耗时任务放置在普通线程池,避免耗时任务阻塞线程池后,导致所有异步任务都必须等待
4.异步任务,分为核心任务和普通任务,只有核心任务中出现的系统级错误才会报错,异步任务的ui操作需要判断原activity是否处于激活状态
5.尽量避免static成员变量引用资源耗费过多的实例,比如Context
6.使用WeakReference代替强引用,弱引用可以让您保持对对象的引用,同时允许GC在必要时释放对象,回收内存。对于那些创建便宜但耗费大量内存的对象,即希望保持该对象,又要在应用程序需要时使用,同时希望GC必要时回收时,可以考虑使用弱引用。
7.超级大胖子Bitmap
及时的销毁(Activity的onDestroy时,将bitmap回收)
设置一定的采样率
巧妙的运用软引用
drawable对应resid的资源,bitmap对应其他资源
8.保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android明显是倾向于编 程者手动的将Cursor close掉
9.线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程 生命周期的不可控
10.如果ImageView的图片是来自网络,进行异步加载
11.应用开发中自定义View的时候,交互部分,千万不要写成线程不断刷新界面显示,而是根据TouchListener事件主动触发界面的更新