Android - ContentProvider 内容提供器详解

概述

ContentProvider 的作用是为不同的应用之间数据共享,提供统一的接口。安卓系统中应用内部的数据是对外隔离的,要想让其它应用能使用自己的数据(例如通讯录),这个时候就用到了 ContentProvider。

原理

ContentProvider 通过 uri 来标识其它应用要访问的数据,通过 ContentResolver 的增、删、改、查方法实现对共享数据的操作。还可以通过注册 ContentObserver 来监听数据是否发生了变化来对应的刷新页面。

分析

ContentProvider

ContentProvider 是一个抽象类,如果我们需要开发自己的内容提供器我们就需要继承这个类并复写其方法,需要实现的主要方法如下:

方法 注释
public boolean onCreate() 在创建 ContentProvider 时使用
public Cursor query() 用于查询指定 uri 的数据返回一个 Cursor
public Uri insert() 用于向指定 uri 的 ContentProvider 中添加数据
public int delete() 用于删除指定 uri 的数据
public int update() 用户更新指定 uri 的数据
public String getType() 用于返回指定的 Uri 中的数据 MIME 类型

数据访问的方法 insert,delete 和 update 可以被多个线程同时调用,此时必须是线程安全的

Android 控件 - SearchView

SearchView 搜索视图 是一种非常常见的可自定义的搜索框

Android 控件 - SeekBar

SeekBar 拖动条 常见于音视频播放器的进度或者音量控制。

Android 控件 - RatingBar

RatingBar 评分条 是一个很常见的控件,常见于电商网站、应用商城等需要征求用户意见的地方。

基本使用

1. XML 属性

属性 注释
isIndicator 是否用作用户无法更改的指示器,默认为 false
numStars 显示多少个星星,整数
rating 默认评分值,浮点数
stepSize 评分每次增加的值,浮点数

Android 控件 - EditText

EditText 文本输入框可以接受用户输入。这里记录一下输入框控件的典型应用

1. 默认提示文本

属性

1
2
3
4
// 提示文本
android:hint="Hint text"
// 提示文本颜色
android:textColorHint="#95A1AA"

2. 获得焦点后全选

属性

1
android:selectAllOnFocus="true"

Android - 读取和查询手机联系人

本文会用到安卓的内容提供器 ContentProvider

1. 读取联系人列表

1.1. 权限

1
<uses-permission android:name="android.permission.READ_CONTACTS"/>

安卓 7.0 以上还需要申请动态权限

1
2
3
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE);
}

1.2. 示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void fetchAllContacts() {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_CODE);
}
ContentResolver resolver = getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor cursor = resolver.query(uri, null, null, null, null);
assert cursor != null;
while (cursor.moveToNext()) {
String cName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String cNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.i("Contact", "姓名:" + cName);
Log.i("Contact", "号码:" + cNum);
Log.i("Contact", "======================");
}
cursor.close();
}

2. 查询指定联系人

2.1 权限

同上

2.2 示例代码

1
2
3
4
5
6
7
8
9
10
11
private void queryContact(String number){
Uri uri = Uri.parse("content://com.android.contacts/data/phones/filter/" + number);
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(uri, new String[]{"display_name"}, null, null, null);
assert cursor != null;
if (cursor.moveToFirst()) {
String name = cursor.getString(0);
Log.i("Contact", number + "对应的联系人名称:" + name);
}
cursor.close();
}

Android - AlertDialog 对话框

1. 基本使用流程

Step 1. 创建 AlertDialog.Builder 对象
Step 2. 调用 setIcon() 设置图标,setTitle() 或 setCustomTitle() 设置标题
Step 3. 设置对话框的内容:setMessage() 还有其他方法来指定显示的内容
Step 4. 调用 setPositive/Negative/NeutralButton() 设置:确定,取消,中立按钮
Step 5. 调用 create() 方法创建这个对象,再调用 show() 方法将对话框显示出来

2. 示例代码

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">


<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dialog" />

<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dialog with list" />

<Button
android:id="@+id/btn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dialog with Radio Button" />

<Button
android:id="@+id/btn4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Dialog with Checkbox" />
</LinearLayout>

Android - 方位传感器

1. 三维坐标系

在现实中确定方向需要一个由 X、Y、Z 轴 组成的三维坐标。安卓给我们返回的方向值就是一个长度为 3 的 flaot 数组,包含三个方向的值。

坐标轴参考释义

参考
X 轴 沿着屏幕水平方向从左到右
Y 轴 从屏幕的左下角开始沿着屏幕的的垂直方向指向屏幕的顶端
Z 轴 当设备水平放置时,指向天空的方向

2. 方向传感器数据值

传感器的回调方法 onSensorChanged 中的参数 SensorEvent event 是一个最多包含三个元素的 Float[] 数组,对应含义见下表:

数据下标 数据名称 含义
values[0] 方位角 手机绕着 Z 轴旋转的角度。
0 表示正北(North),90 表示正东(East),180表示正南(South),270表示正西(West)。
假如 values[0] 的值刚好是这四个值的话,并且手机沿水平放置的话,那么当前手机的正前方就是这四个方向,可以利用这一点来实现指南针
values[1] 倾斜角 手机翘起来的程度,当手机绕着 X 轴倾斜时该值会发生变化。取值范围是 [-180, 180] 之间。假如把手机放在桌面上,而桌面是完全水平的话,这个值应该为0,当然很少桌子是绝对水平的。从手机顶部开始抬起,直到手机沿着 X 轴旋转180°(此时屏幕向下水平放在桌面上)。在这个旋转过程中,这个值会在 [0, -180] 之间变化,即手机抬起时,这个值会逐渐变小,直到等于 -180°;而假如从手机底部开始抬起,直到手机沿着 X 轴旋转180°,这个值会在 [0, 180] 之间变化。可以利用这些特性结合 values[2] 来实现一个水平尺
values[2] 滚转角 沿着Y轴的滚动角度,取值范围为 [-90, 90],假设将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,这个值应为 0。将手机从左侧逐渐抬起,这个值将逐渐减小,直到垂直于手机放置,此时这个值为 -90,相反,从右侧抬起则是 90;假如在垂直位置时继续向右或者向左滚动,这个值将会继续在 [-90, 90] 之间变化

好了,看了这么多文字想必都犯困了吧。那么接下来上代码

3. Demo:监听坐标轴变化

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="15dp"
tools:context=".MainActivity">


<TextView
android:id="@+id/val1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:text="方位角" />

<TextView
android:id="@+id/val2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:textSize="20sp"
android:textStyle="bold"
android:text="倾斜角" />

<TextView
android:id="@+id/val3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:textSize="20sp"
android:textStyle="bold"
android:text="滚转角" />
</LinearLayout>

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MainActivity extends AppCompatActivity implements SensorEventListener {

private TextView val1, val2, val3;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);

val1 = findViewById(R.id.val1);
val2 = findViewById(R.id.val2);
val3 = findViewById(R.id.val3);
}

@SuppressLint("SetTextI18n")
@Override
public void onSensorChanged(SensorEvent event) {
val1.setText("方位角:" + (float) Math.round(event.values[0] * 100) / 100);
val2.setText("倾斜角:" + (float) Math.round(event.values[1] * 100) / 100);
val3.setText("滚转角:" + (float) Math.round(event.values[2] * 100) / 100);
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
}

TODO: Compass demo

Android - PopupMenu 弹出式菜单

PopupMenu 可以很方便的在指定 View 下显示一个弹出菜单,而且 PopupMenu 的菜单选项可以来自于 Menu 资源。

示例代码

menu_pop.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/monika" android:title="Monika" />
<item android:id="@+id/sayori" android:title="Sayori" />
<item android:id="@+id/natsuki" android:title="Natsuki" />
<item android:id="@+id/yuri" android:title="Yuri" />
<item android:id="@+id/delete" android:title="DELETE THEM ALL" />
</menu>

Android - Date & Time 组件

1. TextClock 文本时钟

TextClock 可以以字符串格式显示当前的日期和时间

效果

用法非常简单,没有什么值得说的,android:format24Hour 属性的参数就是一个时间格式化字符串,之后可能会单独写一篇文章

示例代码

1
2
3
4
5
<TextClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:format24Hour="yyyy-MM-dd HH:mm:ss"
/>
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×