前言:目录结构还有待优化,可直接ctrl+F搜索有无需要了解的内容
本笔记属于个人初学android过程时总结,如有错误或者图片缺失,还请留言指正,十分感谢!
仅供学习参考,如需转载请注明来自[Durango]: www.durango.cn

第一章 控件与布局

一、界面的美化(Shape和Selector例举)

1.背景颜色的渐变

res/ rawable/ background_login.xml, 整个布局的背景,渐变背景

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="90"
android:endColor="#FF72CAE1"
android:startColor="#FFACDAE5" />
</shape>

2.单色填充带圆角(按钮、局部的布局)

res/ rawable/background_login_div.xml, 登录框部分的背景,单色填充,带圆角

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#55FFFFFF" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />
</shape>

3.文本框不同状态的背景设置

res/drawable/edit_login.xml**, 两个编辑输入框的背景,edit_login 是一个 selector,针对正在输入和其它状态设 置不同的背景图片,login_input 和 input_over 是 res/drawable 目录下的两张 png 图片(Educoder 平台已经共享),名 字分别是 input_over.9.png 和 input_input.9.png

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item
android:state_enabled="false"
android:drawable="@drawable/login_input"/>
<item
android:state_focused="true"
android:drawable="@drawable/input_over"/>

</selector>

4.按钮不同状态的文字颜色

res/drawable/text_btn_selector.xml, 两个按钮的 textColor 属性,这是按钮的文本颜色,这是一个 selector,使得按钮在不同状态下的文字颜色显示不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 当前窗口失去焦点时 -->
<item
android:color="@android:color/black"
android:state_window_focused="false" />
<!-- 不可用时 -->
<item
android:color="@android:color/background_light" android:state_enabled="false" />
<!-- 按压时 -->
<item android:color="@android:color/holo_blue_light" android:state_pressed="true" />
<!-- 被选中时 -->
<item
android:color="@android:color/holo_green_dark"
android:state_selected="true" />
<!-- 被激活时 -->
<item
android:color="@android:color/holo_green_light"
android:state_activated="true" />
<!-- 默认时 -->
<item android:color="@android:color/white" />
</selector>

二、Shape

1.Shape可以画四种图形

矩形(rectangle)、椭圆(oval)、线(line)、圆环(ring)。

1
2
3
4
<shape xmIns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

</shape>

2.五种效果(利用 xml 文件描述,作为一种资源,放于drawable目 录。)

(1)solid:填充

                        android:color指定填充的颜色;

(2) gradient:渐变

  • android:startColor和android:endColor 分别为起始和结束颜色

  • android:angle 是渐变角度,必须为45的整数倍。

  • android:type=”linear”,线性渐变(默认)

  • android:type=”radial”,径向渐变

  • android:gradientRadius=”50”,径向渐变需要指定半径

(3) stroke:描边

  • android:width=”2dp” 描边的宽度

  • android:color 描边的颜色

  • 还可以把描边为虚线的形式,设置方式为:

    android:dashWidth=”5dp”
    android:dashGap=”3dp”

(4)corners:圆角

  • android:Radius=”20dp” 设置四个角的半径

  • android:topLeftRadius=”20dp” 设置左上角的半径

  • android:topRightRadius=”20dp” 设置右上角的半径

  • android:bottomLeftRadius=”20dp” 设置右下角的半径

  • android:bottomRightRadius=”20dp” 设置左下角的半径

(5)padding:间隔

可以设置上下左右四个方向的间隔。

image-20200922232849670

三、Selector

1.以Button为例,关键状态属性如下:

属性 含义
android:state_selected 设置是否选中状态,true表示已选中,false表示未选中
android:state_focused 设置是否获得焦点状态,true表示获得焦点,默认为false,表示未获得焦点
android:state_pressed 设置是否按压状态,一般在true时设置该属性,表示已按压状态,默认为false
android:state_enabled 设置是否响应事件,指所有事件;一般只在false时设置该属性,表示不可用状态
android:state_activated: 设置是否被激活状态,true表示被激活,false表示未激活,API Level 11及以上才支持,可通过代码调用控件的setActivated(boolean)方法设置是否激活该控件

2.示例:text_btn_selector.xml的代码,用于按钮的文本颜色t

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 不可用时 -->
<item android:color="@android:color/background_light"
android:state_enabled="false" />
<!-- 按压时 -->
<item android:color="@android:color/holo_blue_light"
android:state_pressed="true" />
<!-- 被选中时 -->
<item android:color="@android:color/holo_green_dark"
android:state_selected="true" />
<!-- 被激活时 -->
<item android:color="@android:color/holo_green_light"
android:state_activated="true" />
<!-- 默认时 -->
<item android:color="@android:color/white" />
</selector>

在控件中引用 android:background=”@drawable/bg_btn_selector”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<Button 
android:id="@+id/btn_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background=<Button
android:id="@+id/btn_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:background="@drawable/bg_btn_selector"
android:text="默认按钮"
android:textColor="@color/text_btn_selector" />
"
android:text="默认按钮"
android:textColor="@color/text_btn_selector" />

image-20200923134625276

四、登录布局和背景优化

image-20200923135110680

image-20200923135119943

image-20200923135127485

image-20200923135145022

image-20200923135612629

五、View概念

1.概念

  • 多个视图组件(View)可以存放在一个视图容器(ViewGroup)中,该容器可以与其他视图组件共同存放在另一个视图容器当中,但是一个界面文件必须有且仅有一个容器作为根节点。

  • Android应用的界面都是由View和ViewGroup对象构建的,

  • ViewGroup继承了View类,也可以当成普通的View来使用,但主要还是当成容器来使用。

image-20200923140230137

2.View类的常用属性与方法

image-20200923140315637

3.用户界面组件包widget

image-20200923140439546

第二章 Android 列表

一、AdapterView及其子类

1.image-20201002124214084

2.AdapterView子类

  • ListView:列表,通常含有一个TextView控件。

  • Spinner:下拉列表,给用户提供选择。

  • Gallery:缩略图,是一个可以把子项以中心锁定,水平滚动的列表。

  • GridView:网格图,以表格形式显示资源,可以左右滑动的。

二、ListView

1.XML属性

XML****属性 说明
android:divider 设置分割条样式(颜色或者Drawable对象)
android:dividerHeight 设置分割条高度
android:entries(数据源) 指定一个数组资源,用来填充ListView项
android:footerDividersEnabled 设置为false,则不在footer view之前绘制分割条
android:headerDividersEnabled 设置为false,则不在header view之后绘制分割条
android:scrollbars 设置是否显示滚动条
android:fadingEdge 设置是否去除ListView滑到顶部和底部时边缘的黑色阴影
android:listSelector 设置是否去除点击颜色
android:cacheColorHint 设置ListView去除滑动颜色

2.最简单的用法

布局文件中添加LsitView组件,然后在values/ strings.xml文件中填加string-array的数组元素。然后通过android:entries调用加载数组资源,填充ListView项。

3.M-V-C原理

(1)数据模型M(Model)存放数据(来自数组、列表、数据库),利用控制器C(Controller)将数据显示在视图V(View)上。

(2)特点:

  • 将前端显示和后端数据分离

  • 内容不能通过 ListView.add的形式添加列表项,需指定一个Adapter对象, 通过它获得显示数据

  • 数据源相当于 MVC 框架中的M(模型)

  • ListView 相当于 MVC 框架中的V(视图)

  • Adapter 相当于 MVC 框架中的C(控制器)

三、Adapter接口

1.image-20201002125728655

2.Adapter常用的实现类如下:

(1)ArrayAdapter:支持泛型操作,最为简单,一般用于将字符串数组或者任意对象(toString)数组绑定为列表项的数据源。

(2)SimpleAdapter:易于使用,可以将一组静态数据映射到使用XML定义的列表项视图组件上,可以自定义出各种效果。

(3)SimpleCursorAdapter:与SimpleAdapter类似,用于绑定游标(直接从数据库取出数据)作为列表项的数据源。

(4)BaseAdapter:是一个抽象类,继承它需要实现一些方法,具有较高的灵活性

四、ArrayAdapter

1.实现步骤:

(1)创建新项目:项目名称ArrayAdapterDemo。

(2)在string.xml创建一个string-array,存储栏目信息。(M)

(3)在布局中添加ListView控件。(V)

(4)在MainActivity.Java设置布局中ListView的Adapter:(C)

2.代码

//视图 M

ListView listView = (ListView) findViewById(R.id.news_category);

//数据:strings.xml V

String [ ] mData = getResources().getStringArray(R.array.news_category);

//桥接:Adapter C

ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mData);

listView.setAdapter(adapter);

3.监听器

image-20201002130844609

五、SimpleAdapter

1.实现步骤:

(1)创建新项目:项目名称SimpleAdapterDemo。

(2)ListView的子项布局

用来显示列表的每一行内容的xml文件。自定义一个布局:listview_item.xml。

(3)数据准备

一般使用HashMap构成的List,List的每一个元素(map)用于填充ListView 的一个item。HashMap的每个键值数据映射到布局文件中对应id的组件上。

(4)数据适配:创建SimpleAdapter并设置

参数依次是:this,getData(),子项布局文件的ID,HashMap的键值数组,布局文件的组件id

第4个参数的键值序列与第5个参数的组件id序列一一对应。

2.代码

子项布局

image-20201002131857410

数据准备

image-20201002132023296

数据适配

image-20201002132215242

3.子项点击事件

image-20201002132331890 image-20201002132425472

六、BaseAdapter

1.实现步骤

(1)创建新项目:项目名称BaseAdapterDemo。

(2)ListView的子项布局: listview_item_bt.xml

​ 一个ImageView,两个TextView和一个ImageButton。

(3)设置自定义适配器MyAdapter

MyAdapter继承BaseAdapter,需要重写getCount(), getView()等方法。
​ ListView在绘制的时候,系统首先调用getCount()函数,根据返回值得到ListView的长度,然后根据 这个长度调用getView()逐一绘制每一行。
​ 在getView中使用了ViewHolder类和对象。
​ 使用ViewHolder可以进行性能优化,对控件实例进行缓存。ViewHolder是一个内部类,其中包含了单个项目布局中的各个控件。

2.image-20201002133333488

image-20201002133841796

mInflater = LayoutInflater.from( getContext() )

image-20201002134333722

image-20201002134657576

image-20201002134926677

image-20201002135612766

image-20201002134944464

image-20201002135159245

image-20201002135718003

image-20201002135725265

七、RecyclerView(补充)

1.定义子项布局:采用CardView布局进行美化。

(1)新建cardview_bt.xml(类似于前一例中的listview_item_bt.xml)

定义cardCornerRadius=”5dp”, elevation = “1dp”
CardView 继承于Framelayout,不能直接放置各类控件,否则各类控件将会重叠在一起,因此一般在CardView布局中嵌套其它布局,在其中放置放置其它控件

(2)image-20201009121547035

2.getAdapterPosition(); 获取当前点击项的position序号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
holder.fruitItemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position=holder.getAdapterPosition(); //获取当前点击项的position序号
Fruit fruit=mFruitList.get(position); //获取当前点击项的Fruit实例
new AlertDialog.Builder(parent.getContext()).setTitle("营养价值:")
.setMessage(fruit.nutrition)
.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
});

3.定位子项到第一项

1
2
3
4
int positions=fruitList.indexOf(fruit); //获取对象序号
recyclerView.scrollToPosition(positions);
LinearLayoutManager layoutManager1=(LinearLayoutManager)recyclerView.getLayoutManager();
layoutManager1.scrollToPositionWithOffset(positions,0); //对象定位到第一项

4.List按某个属性重新排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
case R.id.like_order_up:
Collections.sort(fruitList, new Comparator<Fruit>() { //按喜爱度升序排序
@Override
public int compare(Fruit o1, Fruit o2) {
return o1.likeNumber.compareTo(o2.likeNumber);
}
});
adapter.notifyDataSetChanged(); //刷新适配器
break;

case R.id.like_order_down:
Collections.sort(fruitList, new Comparator<Fruit>() { //按喜爱度降序排序
@Override
public int compare(Fruit o1, Fruit o2) {
return o2.likeNumber.compareTo(o1.likeNumber);
}
});
adapter.notifyDataSetChanged(); //刷新适配器
break;

第三章 数据存储

一、数据持久化

1.数据存储方式

  • 文件存储
  • SharedPreferences
  • SQLite数据库

2.Android内部存储和外部存储

(1)内存(Memory):

​ RAM,类似于PC的内存条

(2)内部存储(Internal Storage):

​ 机身固有存储,类似于PC的硬盘

(3)外部存储(External Storage):

​ 早期的Android设备(4.4之前) 指SDCard(扩展卡),类似于PC上的U盘。

​ 之后随着技术的进步,机身存储得到了快速增大(8G以上),此时的外部存储是概念级别的“外部存储”,机 身固有的存储有一部分被划分为“内部存储”,另一部分被划分为“外部存储”,但其实都是机身固有存储。 后期的外部存储也包括了SDCard。
​ 所以不管Android手机是否有可移动的SDCard,他们总是有外部存储和内部存储。

image-20210601224438335

3.几个重要文件夹

打开DDMS(Dalvik Debug Monitor Service),有一个Device File Explorer:data文件夹、mnt文件夹、sdcard 文件夹、storage文件夹

4.内部存储data

(1)data文件夹就是我们常说的内部存储,打开data文件夹,有两个文件夹:

  • 文件夹app:存放着我们所有安装的app的apk文件
  • 文件夹data:一些包名,展开后,

    data/data/包名/shared_prefs(SharedPreference存储方式)

    data/data/包名/<font color='orange'>databases</font>(数据库存储方式)
    data/data/包名/<font color='orange'>files</font>(文件存储方式)
    data/data/包名/<font color='orange'>cache</font>
    

(2)路径的访问:Environment.getDataDirectory()获取内部存储根路径。/data

(3)几点:

  1. 系统默认只在内部存储中创建cache目录,并且此时cache目录是空的

  2. 此外,还可以根据需要自动创建:shared_prefs,databases,files目录

    但files可以手动创建,而shared_prefs,databases不能

  3. 别的App几乎无法访问内部存储中的数据(都是私有的),除了用非法手段或者我们主动暴露内部存储目录下的文件夹,文件会随着App的卸载而被系统自动删除。

(4)内部存储的API

image-20201028153632199

5.外部存储storage

(1)一般是/storage/emulated/0也有可能是其它文件夹,不同厂家不同版本有可能不一样。

/storage/sdcard0,/sdcard,/mnt/sdcard,/storage/emulated/0,/storage/emulated/legacy

  • 公有目录:10大类,比如DCIM,Download等这些系统创建的文件夹。storage/emulated/0/Download
  • 私有目录:Android文件夹,打开后有data文件夹。storage/emulated/0/Android/data/包名 文件夹:里面包含了许多包名组成的文件夹。

    (2)Google官方建议我们App的数据应该存储在外部存储的私有目录(data)中该App的包名下,这样当用户卸载掉App之后,相关的数据会一并删除

    如果直接在根目录/storage/emulated/0)下创建一个应用的文件夹,这样当该应用被卸载后,这些数据还保留在外部存储中,留下垃圾数据

(3)路径的访问:Environment.getExternalStorageDirectory():获取机身存储的外部存储根路径。

(4)默认情况下,Android系统不会为我们的App在外部存储中创建私有目录,需要手动创建私有目录

context.getExternalFilesDir(…):在storage/emulated/0/Android/data/包名/files 中创建文件

​ context.getExternalCacheDir() :在storage/emulated/0/Android/data/包名/cache 中创建文件

image-20201028154738508

6.内部存储与外部存储比较

​ 外部存储目录空间较大,而内部存储空间有限
​ 部分目录不会被自动创建,需要手动创建
​ 两者都不需要权限
​ 两者都会随着App的卸载而会自动被删除
​ 对于内部存储,只有本App才可以访问
​ 对于外部私有目录,本App可以直接访问,而其它App在自 Android 7.0 开始,系统对应用私有目录的访问权限进一步限制。其他 App 无法通过 file:// 这种形式的 Uri 直接读写该目录下的文件内容,而是通过 FileProvider 访问。
​ 需要注意的是:由于用户可以直接查看并操作外部私有存储目录,那么也就意味着我们在操作这个目录下的文件的时候一定要做好异常和判空处理。

7.数据存储与清除

(1)数据存储:

  • 默认情况下,存储在内部存储
    data/app:用户APP安装目录,存放apk;

    data/data/包名/:存放应用程序的数据

  • 数据可以存放到指定的外部存储

    /storage/sdcard(共有目录)

    /storage/sdcard0/Android/data/包名/(私有目录)

    (2)清除数据:

删除对应包中的cache,files,lib,shared_prefs,datbBases等等

​ (清除data/data/packagename中的cache,files,lib, databases,shared_prefs等等)

​ (清除storage/emulated/0/Android/data/packagenam中的文件)

(3) 清除缓存:

删除的是App运行过程中所产生的临时数据,比如读入程序,计算,输入输出等等,这些过程中肯定会产生很多的数据,它们在内存中。

二、文件存储

1.内部存储

(1)存:

  • 方法1:使用 context.getFilesDir() 获取内部存储data/data/包名/files目录,然后创建文件,最后利用文件(全路径)新建FileOutputStream对象进行文件写入。
    FileOutputStream fileOutputStream = new FileOutputStream(filePathName);
image-20201028160019136
  • 方法2:直接使用Context.openFileOutput()方法(只需要文件名)获取FileOutputStream对象,进行文件写入。
image-20201028160258040 image-20201028160348975

(2)取:

  • 方法1:使用context.getFilesDir() 获取内部存储data/data/包名/files目录,然后利用文件(全路径)创建FileInputStream对象,进行内容读取。
    FileInputStream fileInputStream = new FileInputStream(filePathName);

image-20210601224213396

  • 方法2:直接使用Context. openFileInput()方法(只需要文件名)获取FileInputStream对象,进行文件内容读取。
    FileInputStream fileInputStream = openFileInput(fileName);
image-20201028160853113

image-20210601224250308

2.外部存储

(1)外部根目录:

使用 Environment.getExternalStorageDirectory() 获取

一般是/storage/emulated/0

(2)外部公有目录:

使用Environment.getExternalStoragePublicDirectory获取

/storage/emulated/0/Music

针对外部共有目录、根目录等位置的存取需要添加权限,Android 6.0 之后还需要做运行时权限申请。针对外部私有目录的存取则不需要添加权限
默认情况下,Android系统不会为我们的App在外部存储中创建私有路径,需要手动创建
外部私有目录在App卸载时同步删除。

(3)获取外部私有目录

image-20201028162002693

(4)存:

image-20201028162420940

(5)取:

image-20201028162532386

二、SharedPreferences存储

1.获取SharedPreferences对象

(1) Context . getSharedPreferences()方法 

​ 此方法接受两个参数,第一个参数用于指定 SharedPreferences 文件的名称,如果指定的文件不存在则会创建一个。SharedPreferences 文件都是存放在 /data/data/<包名>/shared_prefs/ 目录下的。
​ 第二个参数用于指定操作模式,主要为 MODE_PRIVATE(默认操作模式) 和 MODE_MULTI_PROCESS(多进程读写) 。

(2)Activity 类中的 getPreferences() 方法

这个方法和 Context 中的 getSharedPreferences() 方法类似,不过它只接收一个操作模式参数,使用这个方法时会自动将当前活动的类名作为 SharedPreferences 的文件名

(3) PreferenceManager 类中的 getDefaultSharedPreferences() 方法

这是一个静态方法,它接收一个 Context 参数,并自动使用当前应用程序的包名作为前缀来命名 SharedPreferences 文件。

2.通过SharedPreferences对象获取到Editor对象存数据

(1)SharePreferences.Editor editor = shared.edit();

调用 SharedPreferences 对象的 edit() 方法来获取一个 SharePreferences.Editor 对象。

(2)editor.putString( )

向 SharedPreferences.Editor 对象中添加数据,如果添加一个字符串则使用 editor.putString() 方法,以此类推。

(3)editor.commit() editor.apply()

调用 editor.commit() 方法或者editor.apply()方法将添加的数据提交,从而完成数据存储操作。

image-20201028164007127

image-20201028164138241

3.SharePreferences读取与删除数据

image-20201028164251857

image-20201028164334426****