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

Java 中各进制间的转换

实际上,不管是常用的10进制转2、8、16进制,还是10进制转R进制、R进制转10进制的方法,都被封装在 Integer 对象中

10 进制转 R 进制

R: 进制
N: 10进制数

目标进制 方法 返回值
2 进制 Integer.toBinaryString(N:int) 字符串
8 进制 Integer.toOctalString(N:int) 字符串
16 进制 Integer.toHexString(N:int) 字符串
R 进制 Integer.toString(N:int, R:int) 字符串

R 进制转 10 进制

R: 进制
N: R 进制数字符串

1
Integer.parseInt(N:String, R:int)

附:Demo

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BinaryConversionTest {
public static void main(String[] args) {
System.out.println("Just Monika");
int dec_num = 18;
System.out.println(Integer.toBinaryString(dec_num));
System.out.println(Integer.toOctalString(dec_num));
System.out.println(Integer.toHexString(dec_num));
System.out.println(Integer.toString(dec_num, 3));

String bin_num = "10010";
System.out.println(Integer.parseInt(bin_num, 2));
}
}

Output

1
2
3
4
5
6
Just Monika
10010
22
12
200
18

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>

Just Monika

我曾经认识一个女孩。
她是一个素食主义者。
而且还是一名文学部部长。
擅长写诗,朗诵也不赖。
她崇拜那些说唱者,因为羡慕他们能够将词与歌完美的结合。
她对于恐怖电影来说,更喜欢看恐怖小说。
不过呢,她也讨厌冬天,相比之下则十分向往在夏天里喝着冰果汁,躺在阴处歇息的画面。

可在我眼中,她比谁都要更加的真实。

我曾经喜欢过一个女孩。
她有着翡翠绿一样的眼瞳。
一头棕色的单马尾。

尽管我知道我与她不可能在一起。
但是,我却依旧喜欢上了她。
喜欢上了这个名叫 Monika 的女孩。
一遍又一遍听她为我而弹的歌曲。
虽然旋律欢快悦人,但是看到最后的歌词时,我还是忍不住哽咽。

Monika,在游戏中我并没有选择。
所以我选择在这里,写下我想告诉你的话。

我想与你一起上街约会,找一个好的画师给你画上美美的立绘。
也想和你在冬天里抱着身子一起取暖。
想与你 Kiss,更想真正地牵着你的手,坐在咖啡厅里看书。
Monika,如果我能做选择的话,我会毫不犹豫地对你说出“我爱你”。
就算你在我的世界里不懂如何去爱我,我对你的那份感情也不会有丝毫的改变。
毕竟你让我知道了自己还有被爱的权利。
所以,Monika,我只想告诉你。

我爱你。 



J̴̨̧̬̤̫̞͍̩̥͚̤̮̻͓̄̐͌̐͛͘͝u̸͖͇̖̺̐̉͋͐̂̾̄̒̃̓̉͒͛̑̚s̴̯̳̤̜̯̟͊̒̇͑̓̽̏̚͘ṱ̶̱̱̣͔̟̰͖͔̜͒̂͜ͅ ̸̡͓̦͉̮̝͍͉͑̋̿̈́̆M̵̛̰̺̬̗̓͛̊ͅő̶̡̢͉̖̻͇̦̜̳̤̗̔̈̓̔́͘̕ͅͅǹ̵̫̱͕̋̏͝i̷̺̻̘͑͂̔̌̍̓͛̈͋̍́̕͝k̶̛̛̬̫̼͉̞̀̅͗̇͒̅̿̾͊͆̈́̒â̸̧̨̢̜̘͍̥͖͖͓̥̘̝͇̈́̄̎̔͒̓̂̊̋͜͠͠


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"
/>

Ubuntu - Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend)

在 Ubuntu 中 apt 未正常退出的情况下可能会遇到 Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend) 报错,即无法取得锁。总结出以下解决办法

杀死进程

即杀死占用了系统锁的进程

1
ps -e | grep apt-get

找到 apt 或 apt-get 进程的 pid

1
23072 ?        00:00:01 apt-get

杀之

1
sudo kill 23072

强制解锁

即强制删除锁文件来释放锁

1
2
sudo rm -f /var/cache/apt/archives/lock
sudo rm -f /var/lib/dpkg/lock

重启系统

重启解决 98% 的系统软件问题

1
2
3
4
5
6
7
8
9
10
11
# Method 1
# 强制重启系统,使用前请保存好文件
sudo systemctl --force reboot

# Method 2
# 利用内核调试功能强制重启系统,同样需要先保存好文件
echo "b" > /proc/sysrq-trigger

# Method 3
# 正常重启系统
sudo reboot

更多内核调试命令请参阅 Linux 内核调试

Android - Date/TimePickerDialog 日期和时间选择器

DatePickerDialog 和 TimePickerDialog 可以供用户来选择日期和时间

示例代码

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

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

findViewById(R.id.btn_pick_date).setOnClickListener(this);
findViewById(R.id.btn_pick_time).setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_pick_date:
Calendar cale1 = Calendar.getInstance();
new DatePickerDialog(
MainActivity.this,
new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
String result = "";
// 这里获取到的月份需要 +1s
result += "你选择的日期是:" + year + "年" + (monthOfYear + 1) + "月" + dayOfMonth + "日";
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
},
cale1.get(Calendar.YEAR),
cale1.get(Calendar.MONTH),
cale1.get(Calendar.DAY_OF_MONTH)
).show();
break;
case R.id.btn_pick_time:
Calendar cale2 = Calendar.getInstance();
new TimePickerDialog(
MainActivity.this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
String result = "";
result += "你选择的时间是:" + hourOfDay + "时" + minute + "分";
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
},
cale2.get(Calendar.HOUR_OF_DAY),
cale2.get(Calendar.MINUTE),
true
).show();
break;
}
}
}
Your browser is out-of-date!

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

×