Android Training学习笔记之适配不同的设备

Android是一个开源的开放的操作系统,世界上的任何人都可以基于这个系统进行适合自己的定制活动。Android的这样一个特点使得android世界的碎片化很严重,形形色色的android设备太多太多。这就给app开发带来了不小的困难,保证app在不同的设备上的使用体验是一致的是每一个开发者必须考虑,但是很头疼的问题。Google在这块也做了很多的工作,尤其是在最新的android 6.0中,多设备的支持和自适应做的已经非常好了。要想让你的app能够利用google提供的优良自适应特性,你必须要遵守一些google的基本规范。google在training中给出了他的规范:

https://developer.android.com/training/basics/supporting-devices/index.html

这个规范一共分为3个部分:

  1. 支持不同的语言
  2. 支持不同屏幕的设备
  3. 支持不同系统版本的设备

接下来我们就简单学习一下google的基本规范。

1. 支持不同的语言

Android作为一个全球化的操作系统,android会运行在世界上任何一个国家,那么android的用户所使用的语言就是非常多样的。为了支持不同国家的语言,android提供了string resource机制,具体的做法就是:你应该在你的项目源码目录下的res目录(也就是你的app的resource目录)中,新建上众多这样格式的目录:

values-<ISO 639-1 locale codes>

然后在这个目录下面新建名为strings.xml的文件,这个文件中所有的tag都是以string开始,然后指定一个名字,最后指定一个对应的值:

<string name="app_name">HelloWorld</string>

这里需要说明一下,上面提到的ISO 639-1 locale codes是国际之间关于国家地区语言代码的ISO全球统一规范,当然android就是遵守这个的。关于ISO 639-1 locale codes规范的简介可以查看维基百科的介绍:

https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes

全面的介绍可以查看ISO官网的spec:

http://www.iso.org/iso/home/standards/language_codes.htm

如果你的app支持多国语言的话,那么你的string资源目录可能有点像下面这个样子:

MyProject/
    res/
       values/
           strings.xml
       values-es/
           strings.xml
       values-fr/
           strings.xml

这个例子中支持了默认的语言支持(当找不到支持的语言资源的时候,默认使用这个,一般为英语),西班牙语支持,法语支持。以下是默认语言支持的示例:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">My Application</string>
    <string name="hello_world">Hello World!</string>
</resources>

这是西班牙语支持示例:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">Mi Aplicación</string>
    <string name="hello_world">Hola Mundo!</string>
</resources>

这是法语支持示例:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="title">Mon Application</string>
    <string name="hello_world">Bonjour le monde !</string>
</resources>

是的,就是这么简单,你只要在不同的目录下的strings.xml中定义上相同name不同语言翻译的string后,android系统就可以根据当前系统的语言来决定显示什么文字了!

我们使用这些string资源基本有两种方式:在java代码中使用和在xml等文件中使用,我们先看下再java代码中怎么使用:

来自google的例子

// Get a string resource from your app‘s Resources
String hello = getResources().getString(R.string.hello_world);

// Or supply a string resource to a method that requires a string
TextView textView = new TextView(this);
textView.setText(R.string.hello_world);

在xml文件中使用:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

2. 支持不同的屏幕

基于android系统的设备是如此之多,从小屏幕的智能手表到日常使用的智能手机,在从汽车上的智能车载到大屏幕的智能电视。屏幕的尺寸和分辨率是我们开发中必须要考虑的一个问题,同语言国际化一样,这块google也有自己的规范。

首先说明一下目前的屏幕尺寸和画面清晰度的分类:

四种屏幕尺寸:small(小), normal(中), large(大), xlarge(超大)

五种屏幕清晰度(细腻度):low(ldpi)低, medium(mdpi)中, high(hdpi)高, extra high(xhdpi)超高, extra extra high(xxhdpi)极高

这里需要额外说明一下,从android 3.2(api level 13)开始,上面4种屏幕尺寸已经不建议使用了,取而代之的是一种根据可用屏幕宽度管理屏幕尺寸的新技术。

通常来讲以上的几种屏幕尺寸和清晰度定义基本如下

更多关于屏幕尺寸和清晰度的信息请参考google的说明:

https://developer.android.com/guide/practices/screens_support.html

在支持屏幕大小的方面,基本有两个问题:一是界面布局,而是图片显示大小。先说说界面布局问题,界面的布局和屏幕的尺寸关系比较大,如一个比较的大的屏幕尺寸和一个小的屏幕尺寸每屏显示的内容肯定不一样,大一点的屏幕可以显示多一点的内容,布局可以更加自由一些,小一点的屏幕显示的内容就比较少,界面元素布局就会相对紧凑一些。和支持多语言一样,在支持多屏幕尺寸上,我们也可以使用不同目录,同样文件名,不同布局内容的策略让android系统根据实际情况决定布局。我们可以在res目录下的layout目录建立这样的目录:

layout-<screen size pattern>

这里的screen size pattern可以是这样的:

空
land(表示横屏)
large(表示大屏)
large-land(表示大屏横屏)

也就是说你的目录可能会像这个样子:

MyProject/
    res/
        layout/              # default (portrait)
            main.xml
        layout-land/         # landscape
            main.xml
        layout-large/        # large (portrait)
            main.xml
        layout-large-land/   # large landscape
            main.xml

但是,上面也提到了,这个技术在android 3.2之后就不需要使用了,因为android可以使用新技术来定义屏幕尺寸:

https://developer.android.com/guide/practices/screens_support.html#DeclaringTabletLayouts

除了界面布局的问题,还有的就是app中图片的显示问题。不同的分辨率,清晰度去显示同一张图片肯定会有问题的,图片通常会有变形的问题。同样地,这个问题我们可以按照不同目录,同一个文件名的方式来处理这个问题。我们可以在res目录下建立这样的目录:

drawable-<density>

这里的density就是上面提到了几种,因此如果你的app支持不同清晰度的显示,那么你的图片资源目录可能像这样:

MyProject/
    res/
        drawable-xhdpi/
            awesomeimage.png
        drawable-hdpi/
            awesomeimage.png
        drawable-mdpi/
            awesomeimage.png
        drawable-ldpi/
            awesomeimage.png

任何时候你都可以通过@drawable/awesomeimage的方式去使用这个图片,系统会根据当前设备的清晰度自动选择相应的图片显示。另外,不同清晰度之间的比例是这样的:

  1. xhdpi: 2.0
  2. hdpi: 1.5
  3. mdpi: 1.0 (baseline)
  4. ldpi: 0.75

也就是说,xhdpi是mdpi图片尺寸的2倍,如果xhdpi的尺寸是200*200的话,你的mdpi照片就是100*100.同时需要注意的是,低清晰度的图片不是必须的,当你制定了高清晰度的时候,如果设备是低清晰度的话,那么系统会自动按照这个比例缩放你的照片。不过,最好还是指定这样的图片,不然缩放的过程可能增加额外的内存和cpu消耗,并且缩放的效果不一定是你最想要的。图片资源中比较重要的可能就是app的icon的设计了,这个是app的门面,这部分的设计可以参考google的文档:

https://developer.android.com/design/style/iconography.html

3. 支持不同的系统版本

Android是一个快速演变的操作系统,可以看到google的发布更新频率是非常快的,android也在以一个非常快的速度进化着。在快速的版本演化中,有一个问题就是新旧的api版本兼容性的问题。老版本的api的可能早就废弃不用了,新版本的api提供了很好的特性但是很多设备部支持。在创建app的初始,就是决定app的目标平台和最低平台,google的建议是至少覆盖90%的设备用户。

为了让我们的app的能够正常良好地运行在不同版本上,我们需要在AndroidManifest中指定相应的版本问题。我们使用标签制定相应版本,目前可以制定的版本有:

minSdkVersion(最小版本)

targetSdkVersion(目标版本)

maxSdkVersion(最大版本)

其中我们一般制定最小版本和目标版本,最小版本指定你的app必须运行的版本,目标版本指定你的app运行的最理想的版本。这个部分在AndroidManifest中指定方式如下:

<uses-sdk android:minSdkVersion="integer"
          android:targetSdkVersion="integer"
          android:maxSdkVersion="integer" />

每个值都是一个int型的无符号数字,这个数字是android的api level。关于android的api level可以参考下面这个表格(来自google)

我们要填写的就是这表格中的API level中的数字。更多信息,参考:

https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels

为了获得更加灵活的操作方式,我们还可以在运行时判断当前系统的版本,方式如下:

private void setUpActionBar() {
    // Make sure we‘re running on Honeycomb or higher to use ActionBar APIs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
    }
}

就是使用Build类的常量判断,Build类包含了当前系统中的众多信息,包括cpu类型,设备名称,制造商,序列号等等信息,更多信息参考Build的api doc:

https://developer.android.com/reference/android/os/Build.html

这里再啰嗦一句,当系统解析xml资源文件的时候,android会自动过滤掉不识别或者不支持的特性。比如说,你在xml文件中使用了ActionBar这个元素,但是这个元素是android 3.0以上的版本才能支持的,如果是一个低于3.0版本的设备来解析这个xml文件的话,会自动忽略这个元素,而不会产生任何错误。

除了以上提到的内容,android在界面效果上还有一些有关系统版本之间的内容。对于每个android版本,没有版本都会有自己的style和theme,也就是风格和主题。比如说2.3版本的风格和4.0的界面风格就是有很大的不同,4.0的风格更加时尚;5.0之后的风格和主题就发生更大的变化了,因为引入了“原质化设计(material design)”,使得界面更加自然淳朴。使用这些内置的风格和主题可以使得你的app再不同版本的系统中以一种和系统版本相适应的风格方式显示。目前google自定了很多风格和主题,可以在以下的链接中看到完整的内容:

风格和主题的介绍:

https://developer.android.com/guide/topics/ui/themes.html

系统内置风格:

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/styles.xml

系统内置主题:

https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/res/res/values/themes.xml

我们比较常见的有:

对话框主题:

<activity android:theme="@android:style/Theme.Dialog">

透明背景:

<activity android:theme="@android:style/Theme.Translucent">

当然,我们也可以仿造上面系统预定义的方式,自定义风格和主题,定义的内容一般写在res/values/styles.xml中,这里是一个例子:

<style name="CodeFont">
     <item name="android:layout_width">fill_parent</item>
     <item name="android:layout_height">wrap_content</item>
     <item name="android:textColor">#00FF00</item>
     <item name="android:typeface">monospace</item>
</style>

当然我们也可以继承自系统预定义的风格主题,使用parent关键字,比如:

<style name="CodeFont" parent="@android:style/TextAppearance.Medium">
        <item name="android:layout_width">fill_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textColor">#00FF00</item>
        <item name="android:typeface">monospace</item>
    </style>

我们把上面的CodeFont风格继承自系统的TextAppearance.Medium风格了。更多的信息可以参考:

https://developer.android.com/guide/topics/ui/themes.html#DefiningStyles

我们使用主题或者风格的方式比较简单,如果相对某个activity应用主题风格可以这样:

<activity android:theme="@style/CustomTheme">

如果想对整个应用也就是所有的activity应用的话,可以这样:

<application android:theme="@style/CustomTheme">

关于风格和主题更加详细的资料,可以看看这个,解释的还是比较到位的(英文的,嘿嘿):

http://docs.appcelerator.com/platform/latest/#!/guide/Android_Themes

时间: 2024-08-06 13:59:34

Android Training学习笔记之适配不同的设备的相关文章

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl

Android:日常学习笔记(8)———探究UI开发(5)

Android:日常学习笔记(8)---探究UI开发(5) ListView控件的使用 ListView的简单用法 public class MainActivity extends AppCompatActivity { private String[] data={"Apple","Banana","Orange","Watermelon","Pear","Grape","

java/android 设计模式学习笔记(6)---适配器模式

这篇来介绍一下适配器模式(Adapter Pattern),适配器模式在开发中使用的频率也是很高的,像 ListView 和 RecyclerView 的 Adapter 等都是使用的适配器模式.在我们的实际生活中也有很多类似于适配器的例子,比如香港的插座和大陆的插座就是两种格式的,为了能够成功适配,一般会在中间加上一个电源适配器,形如: 这样就能够将原来不符合的现有系统和目标系统通过适配器成功连接. 说到底,适配器模式是将原来不兼容的两个类融合在一起,它有点类似于粘合剂,将不同的东西通过一种转

java/android 设计模式学习笔记(10)---建造者模式

这篇博客我们来介绍一下建造者模式(Builder Pattern),建造者模式又被称为生成器模式,是创造性模式之一,与工厂方法模式和抽象工厂模式不同,后两者的目的是为了实现多态性,而 Builder 模式的目的则是为了将对象的构建与展示分离.Builder 模式是一步一步创建一个复杂对象的创建型模式,它允许用户在不知道内部构建细节的情况下,可以更精细地控制对象的构造流程.一个复杂的对象有大量的组成部分,比如汽车它有车轮.方向盘.发动机.以及各种各样的小零件,要将这些部件装配成一辆汽车,这个装配过

java/android 设计模式学习笔记(一)---单例模式

前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使用的时候也会有一些坑. PS:对技术感兴趣的同鞋加群544645972一起交流 设计模式总目录 java/android 设计模式学习笔记目录 特点 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 单例模式的使用很广泛,比如:线程池(threadpool).缓存(cache).对

Android NDK学习笔记(一) 为什么要用NDK?

NDK是什么 NDK是Native Development Kit的简称,即本地开发工具包.通过NDK,Android允许开发人员使用本地代码语言(例如C/C++)来完成应用的部分(甚至全部)功能.注意:由于翻译原因,有些地方也把Native翻译为"原生". NDK是SDK的一个补充,可以帮助你做这些事情: 生成可以在ARM CPU,Android 1.5(及以上)平台运行的JNI兼容的共享库. 将生成的共享库放置在应用程序项目路径的合适位置,使其能自动地添加进你最终的(和经过签名的)

java/android 设计模式学习笔记(7)---装饰者模式

这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是继承关系的一种替代方案之一,但比继承更加灵活.在现实生活中也可以看到很多装饰者模式的例子,或者可以大胆的说装饰者模式无处不在,就拿一件东西来说,可以给它披上无数层不一样的外壳,但是这件东西还是这件东西,外壳不过是用来扩展这个东西的功能而已,这就是装饰者模式,装饰者的这个角色也许各不相同但是被装饰的对

疯狂Android讲义 - 学习笔记(四)

Android应用通常有多个Activity,多个Activity组成Activity栈,当前活动的Activity位于栈顶.Activity相当于Java Web开发的Servlet.当Activity处于Android应用运行时,同样受系统控制.有生命周期. 4.1 建立.配置和使用Activity 4.1.1 Activity 建立自己的Activity需要集成Activity基类,在不同的应用场景,有时也能集成Activity的子类. Activity间接或直接继承了Context.Co

Android:日常学习笔记(10)———使用LitePal操作数据库

Android:日常学习笔记(10)---使用LitePal操作数据库 引入LitePal 什么是LitePal LitePal是一款开源的Android数据库框架,采用了对象关系映射(ORM)的模式,将平时开发时最常用的一些数据库功能进行了封装,使得开发者不用编写一行SQL语句就可以完成各种建表.増删改查的操作.并且LitePal很"轻",jar包大小不到100k,而且近乎零配置,这一点和Hibernate这类的框架有很大区别.目前LitePal的源码已经托管到了GitHub上. 关