乙巳🐍年

acc8226 的博客

1. 熟练掌握 Java 技术,熟悉面向对象思想,熟悉常用设计模式

  • 熟练掌握 Java 技术,熟悉面向对象思想,熟悉常用设计模式

  • 面向对象思想: 继承, 封装, 多态

  • 设计模式:

六大原则

1. 单一职责(Single Responsibility Principle)

对于单一职责原则,我的建议是接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。
2. 里氏替换原则(Liskov Substitution Principle)
所有引用基类的地方必须能透明地使用其子类的对象。
3. 迪米特法则(Law of Demeter,LoD)
一个对象应该对其他对象有最少的了解。通俗地讲,一个类应该对自己需要耦合或调用的类知道得最少
4. 接口隔离原则(Interface Segregation Principle)

阅读全文 »

安卓 tools 标签使用

查看假数据, 只会出现在设计模式(预览)中。 tools:text="fake data"

安卓逻辑分辨率 小知识

华为 8 寸平板 1920*1200 16:10 283PPI xdpi 逻辑像素密度 1.76875

逻辑分辨率 1086 * 678

虚拟按键占 96px 除去虚拟按键则分辨率 1824 1200
虚拟按键占 96px 除去虚拟按键则分辨率 1200 1824

华为 10.1 寸平板 1920*1200 16:10 224PPI hdpi 逻辑像素密度 1.4

阅读全文 »

ContentProvider

构建 content URI

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
53
54
public class TaskContract {

/* COMPLETED (1) Add content provider constants to the Contract
Clients need to know how to access the task data, and it's your job to provide
these content URI's for the path to that data:
1) Content authority,
2) Base content URI,
3) Path(s) to the tasks directory
4) Content URI for data in the TaskEntry class
*/

// The authority, which is how your code knows which Content Provider to access
public static final String AUTHORITY = "com.example.android.todolist";

// The base content URI = "content://" + <authority>
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + AUTHORITY);

// Define the possible paths for accessing data in this contract
// This is the path for the "tasks" directory
public static final String PATH_TASKS = "tasks";

/* TaskEntry is an inner class that defines the contents of the task table */
public static final class TaskEntry implements BaseColumns {

// TaskEntry content URI = base content URI + path
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_TASKS).build();

...
...
...

/*
The above table structure looks something like the sample table below.
With the name of the table and columns on top, and potential contents in rows
Note: Because this implements BaseColumns, the _id column is generated automatically
tasks
- - - - - - - - - - - - - - - - - - - - - -
| _id | description | priority |
- - - - - - - - - - - - - - - - - - - - - -
| 1 | Complete lesson | 1 |
- - - - - - - - - - - - - - - - - - - - - -
| 2 | Go shopping | 3 |
- - - - - - - - - - - - - - - - - - - - - -
.
.
.
- - - - - - - - - - - - - - - - - - - - - -
| 43 | Learn guitar | 2 |
- - - - - - - - - - - - - - - - - - - - - -
*/

}
}

构建 URiMatcher

  1. 为多行和单行数据定义final整型常量
  2. 为完整的UriMatcher声明静态全局变量
  3. 定义一个将URI与整型匹配项关联的buildUriMatcher方法
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Verify that TaskContentProvider extends from ContentProvider and implements required methods
public class TaskContentProvider extends ContentProvider {

// COMPLETED (1) Define final integer constants for the directory of tasks and a single item.
// It's convention to use 100, 200, 300, etc for directories,
// and related ints (101, 102, ..) for items in that directory.
public static final int TASKS = 100;
public static final int TASK_WITH_ID = 101;

// COMPLETED (3) Declare a static variable for the Uri matcher that you construct
private static final UriMatcher sUriMatcher = buildUriMatcher();

// COMPLETED (2) Define a static buildUriMatcher method that associates URI's with their int match
/**
Initialize a new matcher object without any matches,
then use .addURI(String authority, String path, int match) to add matches
*/
public static UriMatcher buildUriMatcher() {

// Initialize a UriMatcher with no matches by passing in NO_MATCH to the constructor
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

/*
All paths added to the UriMatcher have a corresponding int.
For each kind of uri you may want to access, add the corresponding match with addURI.
The two calls below add matches for the task directory and a single item by ID.
*/
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS, TASKS);
uriMatcher.addURI(TaskContract.AUTHORITY, TaskContract.PATH_TASKS + "/#", TASK_WITH_ID);

return uriMatcher;
}

// Member variable for a TaskDbHelper that's initialized in the onCreate() method
private TaskDbHelper mTaskDbHelper;

/* onCreate() is where you should initialize anything you’ll need to setup
your underlying data source.
In this case, you’re working with a SQLite database, so you’ll need to
initialize a DbHelper to gain access to it.
*/
@Override
public boolean onCreate() {
// Complete onCreate() and initialize a TaskDbhelper on startup
// [Hint] Declare the DbHelper as a global variable

Context context = getContext();
mTaskDbHelper = new TaskDbHelper(context);
return true;
}


@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {

throw new UnsupportedOperationException("Not yet implemented");
}


@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {

throw new UnsupportedOperationException("Not yet implemented");
}


@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {

throw new UnsupportedOperationException("Not yet implemented");
}


@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {

throw new UnsupportedOperationException("Not yet implemented");
}


@Override
public String getType(@NonNull Uri uri) {

throw new UnsupportedOperationException("Not yet implemented");
}

}

数据库解析流程

insert

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
// Implement insert to handle requests to insert a single new row of data
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
// Get access to the task database (to write new data to)
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();

// Write URI matching code to identify the match for the tasks directory
int match = sUriMatcher.match(uri);
Uri returnUri; // URI to be returned

switch (match) {
case TASKS:
// Insert new values into the database
// Inserting values into tasks table
long id = db.insert(TABLE_NAME, null, values);
if ( id > 0 ) {
returnUri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, id);
} else {
throw new android.database.SQLException("Failed to insert row into " + uri);
}
break;
// Set the value for the returnedUri and write the default case for unknown URI's
// Default case throws an UnsupportedOperationException
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}

// Notify the resolver if the uri has been changed, and return the newly inserted URI
getContext().getContentResolver().notifyChange(uri, null);

// Return constructed uri (this points to the newly inserted row of data)
return returnUri;
}

query
以下是查询一个任务的代码:

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
53
54
55
56
57
// Implement query to handle requests for data by URI
@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {

// Get access to underlying database (read-only for query)
final SQLiteDatabase db = mTaskDbHelper.getReadableDatabase();

// Write URI match code
// Write a query for the tasks directory and default case

int match = sUriMatcher.match(uri);
Cursor retCursor;

switch (match) {
// Query for the tasks directory
case TASKS:
retCursor = db.query(TABLE_NAME,
projection,
selection,
selectionArgs,
null,
null,
sortOrder);
break;

// Add a case to query for a single row of data by ID
// Use selections and selectionArgs to filter for that ID
case TASK_WITH_ID:
// Get the id from the URI
String id = uri.getPathSegments().get(1);

// Selection is the _ID column = ?, and the Selection args = the row ID from the URI
String mSelection = "_id=?";
String[] mSelectionArgs = new String[]{id};

// Construct a query as you would normally, passing in the selection/args
retCursor = db.query(TABLE_NAME,
projection,
mSelection,
mSelectionArgs,
null,
null,
sortOrder);
break;

// Default exception
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}

// Set a notification URI on the Cursor
retCursor.setNotificationUri(getContext().getContentResolver(), uri);

// Return the desired Cursor
return retCursor;
}

update

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
// Update won't be used in the final ToDoList app but is implemented here for completeness
// This updates a single item (by it's ID) in the tasks directory
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {

//Keep track of if an update occurs
int tasksUpdated;

// match code
int match = sUriMatcher.match(uri);

switch (match) {
case TASK_WITH_ID:
//update a single task by getting the id
String id = uri.getPathSegments().get(1);
//using selections
tasksUpdated = mTaskDbHelper.getWritableDatabase().update(TABLE_NAME, values, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}

if (tasksUpdated != 0) {
//set notifications if a task was updated
getContext().getContentResolver().notifyChange(uri, null);
}

// return number of tasks updated
return tasksUpdated;
}

delete

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
// Implement delete to delete a single row of data
@Override
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {

// Get access to the database and write URI matching code to recognize a single item
final SQLiteDatabase db = mTaskDbHelper.getWritableDatabase();

int match = sUriMatcher.match(uri);
// Keep track of the number of deleted tasks
int tasksDeleted; // starts as 0

// Write the code to delete a single row of data
// [Hint] Use selections to delete an item by its row ID
switch (match) {
// Handle the single item case, recognized by the ID included in the URI path
case TASK_WITH_ID:
// Get the task ID from the URI path
String id = uri.getPathSegments().get(1);
// Use selections/selectionArgs to filter for this ID
tasksDeleted = db.delete(TABLE_NAME, "_id=?", new String[]{id});
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}

// Notify the resolver of a change and return the number of items deleted
if (tasksDeleted != 0) {
// A task was deleted, set notification
getContext().getContentResolver().notifyChange(uri, null);
}

// Return the number of tasks deleted
return tasksDeleted;
}

getType
以下是 ToDo list 应用的 getType 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* getType() handles requests for the MIME type of data
We are working with two types of data:
1) a directory and 2) a single row of data.
This method will not be used in our app, but gives a way to standardize the data formats
that your provider accesses, and this can be useful for data organization.
For now, this method will not be used but will be provided for completeness.
*/
@Override
public String getType(@NonNull Uri uri) {
int match = sUriMatcher.match(uri);

switch (match) {
case TASKS:
// directory
return "vnd.android.cursor.dir" + "/" + TaskContract.AUTHORITY + "/" + TaskContract.PATH_TASKS;
case TASK_WITH_ID:
// single item type
return "vnd.android.cursor.item" + "/" + TaskContract.AUTHORITY + "/" + TaskContract.PATH_TASKS;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}

  • 创建 Entry 的内部类, 该类实现 BaseColumns
  • tableName 定义常量字符串
  • 为 table 的每一项什么常量字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.android.waitlist.data;

import android.provider.BaseColumns;

public class WaitlistContract {

// COMPLETED (1) Create an inner class named WaitlistEntry class that implements the BaseColumns interface
public static final class WaitlistEntry implements BaseColumns {
// COMPLETED (2) Inside create a static final members for the table name and each of the db columns
public static final String TABLE_NAME = "waitlist";
public static final String COLUMN_GUEST_NAME = "guestName";
public static final String COLUMN_PARTY_SIZE = "partySize";
public static final String COLUMN_TIMESTAMP = "timestamp";
}

}
阅读全文 »

设置可接受的范围

要将可接受的值限制在 0(不包括)和 3(包括)之间,我们选择使用 PreferenceChangeListener - 它与 SharedPreferenceChangeListener 的不同之处为:

  • SharedPreferenceChangeListener 在任何值保存到 SharedPreferences 文件后被触发。
  • PreferenceChangeListener 在值保存到 SharedPreferences 文件前被触发。因此,可以防止对偏好设置做出无效的更新。PreferenceChangeListeners 也附加到了单个偏好设置上。

流程通常如下所示:

  1. 用户更新偏好设置。
  2. 该偏好设置触发了 PreferenceChangeListener。
  3. 新的值保存到了 SharedPreference 文件。
  4. onSharedPreferenceChanged 监听器被触发。

除此之外,它们的行为很相似。你将在你的 Activity中实现Preference.OnPreferenceChangeListener,覆盖onPreferenceChange(Preference preference, Object newValue)。 onPreferenceChange 方法将返回 true 或 false,取决于偏好设置实际上是否要被保存。

若要妥善管理 Activity 生命周期,我们建议您在 onResume() 和 onPause() 回调期间分别注册和注销SharedPreferences.OnSharedPreferenceChangeListener

阅读全文 »
0%