Android文档笔记

一. Application Fundamentals

  1. 四大组件的声明:
    (1)activity:<activity>
    (2)service:<service>
    (3)broadcast receiver:<receiver>
    (4)content provider:<provider>
    activity,service,content provider必须在manifest中声明系统才能调用,但是broadcast receiver也可以在代码中调用registerReceiver()方法来动态声明;
  2. 四大组件的启动:
    (1)activity:Intent:startActivity()、startActivityForResult()
    (2)service:Intent:startService()、bindService()
    (3)broadcast receiver:Intent:sendOrderedBroadcast()、sendStickyBroadcast()
    (4)content provider:ContentResolver的query()
  3. service使用显式intent比使用隐式更加安全,隐式不确定会把什么看不到的service启动起来;
  4. resources和代码分开的一大意义在于,可以为不同设备配置提供不同的resource,例如:切换语言,不同分辨率的手机;

二. App resources

资源外置化,且通过将文件名将资源文件分组,针对不同的设备配置,可以读取不同的文件下的资源。Android系统在运行时,根据当前配置获取合适的资源文件,系统会对不同文件在项目工程的R文件(aapt工具自动生成)下生产资源ID,系统通过资源ID获取相应的资源。

(一)资源分组
  1. assets目录下的文件不会生成资源ID,所以必须使用AssetManager来读取;
  2. 资源分组:格式:<resources_name>-<config_qualifier>,其中config_qualifier可以是多个,中间用-分隔,但要注意,当有多个config_qualifier时,需要按照官网有顺序限制,否则系统无法识别会被认为是无效的资源;
  3. 如果没有找到匹配系统设置的资源文件,则系统会使用默认的资源(不包含qualifier的资源集);
    提供默认资源非常重要,原因有二:
  • App可能在一个我们没有配置相应参数设置的手机上,如果没有默认配置,则会因为找不到资源而crash;
  • Android的新版本有时会增加新的配置参数,可能会导致老的配置方式不支持,也会导致crash;
  1. 资源别名:当不同的配置需要同一个资源时,本办法是,在两个不同的资源目录下拷贝两份相同的资源;但更好的做法是,使用资源别名,即将资源在res/drawable/下拷贝一份如icon_<qualifier>.png,然后分别两个资源目录下创建xml文件,如icon.xml,并在该xml文件中用<bitmap>指向icon_<qualifier>.png。这样,只需要一份存储较大的png文件,和两份存储较小的xml文件,就可以做到上面的需求了。
  • Drawable
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <drawable name="icon">@drawable/icon_ca</drawable>
</resources>
  • Layout
<?xml version="1.0" encoding="utf-8"?>
<merge>
    <include layout="@layout/main_ltr"/>
</merge>
(二)访问资源

在App中个,可以通过资源ID访问资源,资源ID都存放在工程的R文件中,R文件是由aapt工具在编译时自动生成的。每一类资源在R文件中都是一个子类,例如R.drawable存放所有的drawable资源ID。虽然资源是由资源ID指定的,但我们不需要去R文件中寻找其ID值,因为资源ID总是由两部分组成:(1)资源类型,(2)资源名称;

  1. 从代码中访问:如R.string.hello,语法:
[<package_name>.]R.<resource_type>.<resource_name>

可以通过Context.getResource()来获取资源;

  1. 从XML文件中访问:如@string/hello,语法:
@[<package_name>:]<resource_type>/<resource_name>

注意:

  • 当xml文件与R文件在同一个package时,可以忽略不写,但使用系统资源时,需要包括包名,如android:textColor="@android:color/secondary_text_dark"
  • 引用当前theme的style属性:如:android:textColor="?android:textColorSecondary",语法:
?[<package_name>:][<resource_type>/]<resource_name>
  1. 访问原始文件:
  • /assets目录下:存放在/res下的文件都需要通过资源ID来访问;因此,存放在/assets下的文件无法通过R文件或者XML来访问其资源ID,而需要将其看做通常的文件系统,并通过AssetManager来读取原始文件;eg:读取apk文件并安装内置插件;
  • res/raw/目录下:例如音频、视频文件等;可以通过openRawResource()方法来读取byte流;
  1. 访问系统资源
    例如,设置布局文件(在activity的oncreate方法中),系统theme主题(在AndroidManifest文件中)等;
(三)系统如何通过文件名匹配最match的资源

见官网

(四)处理配置变化

有时App可能会在运行时系统配置发生变化(例如:系统语言、横竖屏等),当配置发生变化时,Android系统会重新开启start(杀死进程,并重新启动),并在重启过程中自动重新load匹配的资源文件;我们需要做的是,在系统重启过程中,做好资源保存和重载的过程,可以使用onSaveInstanceState()ViewModel、持久存储等方式:

  • 更改配置时保留对象:系统自动重启进程,使用onSaveInstanceState()无法保存较大的对象,会使用大量内存并影响性能,推荐使用[ViewModel];(https://developer.android.com/topic/libraries/architecture/viewmodel)
  • 手动处理系统配置变化:有时,App由于特殊需求要避免重启操作,此时需要我们来手动处理系统配置变化,但这种方式不推荐,尽量使用第一种方式:

(1)在manifest中声明activity自己处理配置变化:

android:configChanges="<config_change_name>"

(2)当声明的配置发生变化时,声明的activity会调用方法onConfigurationChanged(Configuration newConfig),并通过传递的Configuration对象来对新的配置做出相应的处理:

@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();
    }
}
(五) Localization
  1. 当在/res文件中有多种后缀符合设备配置时,大部分情况优先匹配语言;
  2. 标记不需要翻译的部分:使用标签<xliff:g>
  • 全称是XML Localization Interchange File Format,中文名是XML本地化数据交换格式,用来标记不应翻译的消息部分;
  • 属性id说明此占位符的用途,可任意命名
<string name="app_homeurl">
    Visit us at <xliff:g id="application_homepage">http://my/app/home.html</xliff:g>
</string>
  1. 在adb上设置Locale:主要用于在模拟器上测试,具体内容见官网
  2. pseudolocales测试App:(暂时没有见过使用的场景),具体内容见官网
  3. Unicode和国际化:Android支持使用 ICU libraryCLDR project
    来提供Unicode和国际化的支持,但使用该库时要分Android6.0(API23)以下和Android7.0(API24)以上来讨论,例如,具体介绍见官网
String skeleton = DateFormat.is24HourFormat(context) ? "Hm" : "hm";
String formattedTime = android.icu.text.DateFormat.getInstanceForSkeleton(skeleton, Locale.getDefault()).format(new Date());
  1. XML文件中的<aapt:attr >标签:将复杂的xml资源inline
(六) 动画
  1. 分类:
    (1)属性动画(Property Animation):通过Animation类改变对象的属性值;
    (2)视图动画(View Animation):分为两种:
    -- 补间动画(Tween animations):通过Animation类对单个图片执行一系列转换;
    -- 帧动画(Frame animations):通过AnimationDrawable类展示一系列图片;
  2. 动画资源文件存放位置:
  • 属性动画(Property Animation):在res/animator/,使用R.animator类访问;
  • 补间动画(Tween animations):在res/anim/,使用R.anim类访问;
  • 帧动画(Frame animations):在res/drawable/,使用R.drawable类访问;
I. 属性动画(Property Animation)
  1. 位置:res/animator/filename.xml,使用资源ID来访问;
  2. 获取资源:
    (1)Java:R.animator.filename
    (2)XML:@[package:]animator/filename
  3. 元素:<objectAnimator>(ObjectAnimator)、<set>(AnimatorSet)、<animator>(ValueAnimator)
  4. 语法:
<set
  android:ordering=["together" | "sequentially"]>

    <objectAnimator
        android:propertyName="string"
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <animator
        android:duration="int"
        android:valueFrom="float | int | color"
        android:valueTo="float | int | color"
        android:startOffset="int"
        android:repeatCount="int"
        android:repeatMode=["repeat" | "reverse"]
        android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>
  1. 使用
    (1)Java代码:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();

(2)XML文件:

android:stateListAnimator = "@[package:]animator/filename"
II. 补间动画(Tween animations)
  1. 位置:res/anim/filename.xml, 使用资源ID来访问;
  2. 获取资源:
    (1)Java:R.anim.filename
    (2)XML:@[package:]anim/filename
  3. 元素:Animation
  4. 语法:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>
  1. 使用
ImageView image = (ImageView) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(hyperspaceJump);
III. 帧动画(Frame animations)
  1. 位置:res/drawable/filename.xml,使用资源ID来访问;
  2. 获取资源:
    (1)Java:R.drawable.filename
    (2)XML:@[package:]drawable.filename
  3. 元素:AnimationDrawable
  4. 语法:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot=["true" | "false"] >
    <item
        android:drawable="@[package:]drawable/drawable_resource_name"
        android:duration="integer" />
</animation-list>
  1. 使用
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);

rocketAnimation = rocketImage.getBackground();
if (rocketAnimation instanceof Animatable) {
    ((Animatable)rocketAnimation).start();
}
动画总结
Android 动画结构
(七) Drawable
  1. Bitmap
    (1)三种格式:.png(preferred)、.jpg(acceptable)、.gif(discouraged);
    (2)在编译过程中,aapt工具会使用无损图像压缩自动优化Bitmap文件,这样可以使该图片文件在同等质量的同时使用更少的内存;所以注意,如果在res/drawable/下的图像文件的二进制码可能在编译器改变,如果想要通过读取bit流再转成bitmap文件,建议放在不会被优化的res/raw/目录下;
    (3)XML bitmap:<bitmap>用作<item>的一个子元素可以用在state listlayer list中;
  2. Layer list
    LayerDrawable是一个能够管理其他多个drawable的drawable对象。每个drawable(<item>)按照顺序在list<layer-list>中绘制,顺序是:最后一个drawable在最上面;
<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:id="@[+][package:]id/resource_name"
        android:top="dimension"
        android:right="dimension"
        android:bottom="dimension"
        android:left="dimension" />
</layer-list>
  1. 通过drawable的当前level值来裁剪另一个drawable,可以通过gravity来控制裁剪方向,最常见的应用是实现自定义进度条;
    (1)语法:
<?xml version="1.0" encoding="utf-8"?>
<clip
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/drawable_resource"
    android:clipOrientation=["horizontal" | "vertical"]
    android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |
                     "fill_vertical" | "center_horizontal" | "fill_horizontal" |
                     "center" | "fill" | "clip_vertical" | "clip_horizontal"] />

(2)自定义进度条:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:id="@android:id/background">
        <shape>
            <solid android:color="@color/colorAccent" />
            <corners android:radius="10dp" />
            <stroke
                android:width="2dp"
                android:color="@color/colorPrimary" />
        </shape>
    </item>

    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <solid android:color="@android:color/holo_red_dark" />
                <corners android:radius="10dp" />
                <stroke
                    android:width="2dp"
                    android:color="@color/colorAccent" />
            </shape>
        </clip>
    </item>
</layer-list>

持续更新中。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,783评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,396评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,834评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,036评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,035评论 5 362
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,242评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,727评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,376评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,415评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,463评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,140评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,734评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,809评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,028评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,521评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,119评论 2 341