1page.title=Tạo một Trình cung cấp Nội dung 2@jd:body 3<div id="qv-wrapper"> 4<div id="qv"> 5 6 7<h2>Trong tài liệu này</h2> 8<ol> 9 <li> 10 <a href="#DataStorage">Thiết kế Kho lưu trữ Dữ liệu</a> 11 </li> 12 <li> 13 <a href="#ContentURI">Thiết kế URI Nội dung</a> 14 </li> 15 <li> 16 <a href="#ContentProvider">Triển khai Lớp Trình cung cấp Nội dung</a> 17 <ol> 18 <li> 19 <a href="#RequiredAccess">Phương pháp được Yêu cầu</a> 20 </li> 21 <li> 22 <a href="#Query">Triển khai phương pháp query()</a> 23 </li> 24 <li> 25 <a href="#Insert">Triển khai phương pháp insert()</a> 26 </li> 27 <li> 28 <a href="#Delete">Triển khai phương pháp delete()</a> 29 </li> 30 <li> 31 <a href="#Update">Triển khai phương pháp update()</a> 32 </li> 33 <li> 34 <a href="#OnCreate">Triển khai phương pháp onCreate()</a> 35 </li> 36 </ol> 37 </li> 38 <li> 39 <a href="#MIMETypes">Triển khai Kiểu MIME của Trình cung cấp Nội dung</a> 40 <ol> 41 <li> 42 <a href="#TableMIMETypes">Kiểu MIME cho bảng</a> 43 </li> 44 <li> 45 <a href="#FileMIMETypes">Kiểu MIME cho tệp</a> 46 </li> 47 </ol> 48 </li> 49 <li> 50 <a href="#ContractClass">Triển khai một Lớp Hợp đồng</a> 51 </li> 52 <li> 53 <a href="#Permissions">Triển khai Quyền của Trình cung cấp Nội dung</a> 54 </li> 55 <li> 56 <a href="#ProviderElement">Phần tử <provider></a> 57 </li> 58 <li> 59 <a href="#Intents">Ý định và Truy cập Dữ liệu</a> 60 </li> 61</ol> 62<h2>Lớp khóa</h2> 63 <ol> 64 <li> 65 {@link android.content.ContentProvider} 66 </li> 67 <li> 68 {@link android.database.Cursor} 69 </li> 70 <li> 71 {@link android.net.Uri} 72 </li> 73 </ol> 74<h2>Các Mẫu Liên quan</h2> 75 <ol> 76 <li> 77 <a href="{@docRoot}resources/samples/NotePad/index.html"> 78 Ứng dụng mẫu Note Pad 79 </a> 80 </li> 81 </ol> 82<h2>Xem thêm</h2> 83 <ol> 84 <li> 85 <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> 86 Nội dung Cơ bản về Trình cung cấp Nội dung</a> 87 </li> 88 <li> 89 <a href="{@docRoot}guide/topics/providers/calendar-provider.html"> 90 Trình cung cấp Lịch</a> 91 </li> 92 </ol> 93</div> 94</div> 95 96 97<p> 98 Trình cung cấp nội dung quản lý truy cập vào một kho dữ liệu tập trung. Bạn triển khai một 99 trình cung cấp thành một hoặc nhiều lớp trong một ứng dụng Android, bên cạnh các phần tử trong 100 tệp bản kê khai. Một trong các lớp của bạn triển khai một lớp con 101 {@link android.content.ContentProvider}, đây là giao diện giữa trình cung cấp của bạn và 102 các ứng dụng khác. Mặc dù mục đích của các trình cung cấp nội dung khác là cung cấp dữ liệu có sẵn cho các 103 ứng dụng khác, dĩ nhiên bạn có thể ra lệnh cho các hoạt động trong ứng dụng của mình 104 truy vấn và sửa đổi dữ liệu được quản lý bởi trình cung cấp của bạn. 105</p> 106<p> 107 Phần còn lại của chủ đề này là một danh sách cơ bản về các bước để xây dựng một trình cung cấp nội dung và một danh sách 108 các API để sử dụng. 109</p> 110 111 112<!-- Before You Start Building --> 113<h2 id="BeforeYouStart">Trước khi Bạn Bắt đầu Xây dựng</h2> 114<p> 115 Trước khi bạn bắt đầu xây dựng một trình cung cấp, hãy làm việc sau: 116</p> 117<ol> 118 <li> 119 <strong>Quyết định xem bạn có cần một trình cung cấp nội dung không</strong>. Bạn cần xây dựng một trình cung cấp 120 nội dung nếu muốn cung cấp một hoặc nhiều tính năng sau đây: 121 <ul> 122 <li>Bạn muốn cung cấp dữ liệu hoặc tệp phức tạp cho các ứng dụng khác.</li> 123 <li>Bạn muốn cho phép người dùng sao chép dữ liệu phức tạp từ ứng dụng của bạn vào các ứng dụng khác.</li> 124 <li>Bạn muốn cung cấp các gợi ý tìm kiếm tùy chỉnh bằng cách sử dụng khuôn khổ tìm kiếm.</li> 125 </ul> 126 <p> 127 Bạn <em>không</em> cần trình cung cấp phải sử dụng một cơ sở dữ liệu SQLite nếu việc sử dụng hoàn toàn 128 diễn ra trong ứng dụng của bạn. 129 </p> 130 </li> 131 <li> 132 Nếu bạn chưa làm như vậy, hãy đọc chủ đề 133 <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> 134 Nội dung Cơ bản về Trình cung cấp Nội dung</a> để tìm hiểu thêm về trình cung cấp. 135 </li> 136</ol> 137<p> 138 Tiếp theo, hãy làm theo những bước sau để xây dựng trình cung cấp của bạn: 139</p> 140<ol> 141 <li> 142 Thiết kế kho lưu trữ thô cho dữ liệu của bạn. Một trình cung cấp nội dung sẽ cung cấp dữ liệu theo hai cách: 143 <dl> 144 <dt> 145 Dữ liệu tệp 146 </dt> 147 <dd> 148 Dữ liệu mà thường đến các tệp chẳng hạn như 149 ảnh, âm thanh, hoặc video. Lưu trữ các tệp ở không gian 150 riêng tư trong ứng dụng của bạn. Để hồi đáp lại một yêu cầu tệp từ một ứng dụng khác, trình cung cấp 151 của bạn có thể cung cấp một núm điều tác cho tệp. 152 </dd> 153 <dt> 154 Dữ liệu "cấu trúc" 155 </dt> 156 <dd> 157 Dữ liệu mà thường đến một cơ sở dữ liệu, mảng, hoặc cấu trúc tương tự. 158 Lưu trữ dữ liệu dưới dạng tương thích với các bảng hàng cột. Hàng 159 biểu diễn một đối tượng, chẳng hạn như một người hoặc khoản mục trong kiểm kê. Cột biểu diễn 160 một số dữ liệu cho đối tượng, chẳng hạn như tên của một người hoặc giá của một khoản mục. Một cách thường dùng để 161 lưu trữ loại dữ liệu này đó là trong cơ sở dữ liệu SQLite, nhưng bạn có thể sử dụng bất kỳ loại 162 kho lưu trữ lâu dài nào. Để tìm hiểu thêm về các loại kho lưu trữ có sẵn trong 163 hệ thống Android, hãy xem phần <a href="#DataStorage"> 164 Thiết kế Kho lưu trữ Dữ liệu</a>. 165 </dd> 166 </dl> 167 </li> 168 <li> 169 Định nghĩa một triển khai cụ thể của lớp {@link android.content.ContentProvider} và 170 các phương pháp được yêu cầu của nó. Lớp này là giao diện giữa dữ liệu của bạn và phần còn lại của 171 hệ thống Android. Để biết thêm thông tin về lớp này, hãy xem phần 172 <a href="#ContentProvider">Triển khai Lớp ContentProvider</a>. 173 </li> 174 <li> 175 Định nghĩa xâu thẩm quyền của trình cung cấp, URI nội dung của nó, và các tên cột. Nếu bạn muốn 176 ứng dụng của trình cung cấp xử lý các ý định, hãy định nghĩa các hành động ý định, dữ liệu phụ thêm, 177 và cờ. Đồng thời, hãy định nghĩa các quyền mà bạn sẽ yêu cầu cho những ứng dụng muốn 178 truy cập dữ liệu của bạn. Bạn nên cân nhắc định nghĩa tất cả những giá trị này là hằng số trong một 179 lớp riêng; sau đó, bạn có thể cho hiện lớp này ra với các nhà phát triển khác. Để biết thêm 180 thông tin về URI nội dung, hãy xem 181 phần <a href="#ContentURI">Thiết kế URI Nội dung</a>. 182 Để biết thêm thông tin về ý định, hãy xem 183 phần <a href="#Intents">Ý định và Truy cập Dữ liệu</a>. 184 </li> 185 <li> 186 Thêm các nội dung tùy chọn khác, chẳng hạn như dữ liệu mẫu hoặc triển 187 khai {@link android.content.AbstractThreadedSyncAdapter} mà có thể đồng bộ hoá dữ liệu giữa 188 trình cung cấp và dữ liệu nền đám mây. 189 </li> 190</ol> 191 192 193<!-- Designing Data Storage --> 194<h2 id="DataStorage">Thiết kế Kho lưu trữ Dữ liệu</h2> 195<p> 196 Trình cung cấp nội dung là giao diện đối với dữ liệu được lưu theo một định dạng cấu trúc. Trước khi tạo 197 giao diện, bạn phải quyết định cách lưu trữ dữ liệu. Bạn có thể lưu trữ dữ liệu theo bất kỳ dạng nào 198 mà bạn muốn rồi thiết kế giao diện để đọc và ghi dữ liệu nếu cần thiết. 199</p> 200<p> 201 Có một số công nghệ lưu trữ dữ liệu có sẵn trong Android: 202</p> 203<ul> 204 <li> 205 Hệ thống Android bao gồm một API cơ sở dữ liệu SQLite mà các trình cung cấp của chính Androi sử dụng 206 để lưu trữ dữ liệu theo định hướng bảng. Lớp 207 {@link android.database.sqlite.SQLiteOpenHelper} giúp bạn tạo cơ sở dữ liệu, và lớp 208 {@link android.database.sqlite.SQLiteDatabase} là lớp cơ bản để đánh giá 209 các cơ sở dữ liệu. 210 <p> 211 Nhớ rằng bạn không phải sử dụng một cơ sở dữ liệu để triển khai kho lưu giữ của mình. Bề ngoài, một trình cung cấp 212 có dạng như là một tập hợp bảng, tương tự như một cơ sở dữ liệu quan hệ, nhưng đây 213 không phải là một yêu cầu đối với việc triển khai nội bộ của trình cung cấp. 214 </p> 215 </li> 216 <li> 217 Để lưu trữ dữ liệu tệp, Android có nhiều API định hướng tệp khác nhau. 218 Để tìm hiểu thêm về lưu trữ tệp, hãy đọc chủ đề 219 <a href="{@docRoot}guide/topics/data/data-storage.html">Kho lưu trữ Dữ liệu</a>. Nếu bạn 220 đang thiết kế một trình cung cấp dữ liệu liên quan tới phương tiện chẳng hạn như nhạc hay video, bạn có thể 221 có một trình cung cấp cho phép kết hợp dữ liệu bảng và các tệp. 222 </li> 223 <li> 224 Để làm việc với dữ liệu trên nền mạng, hãy sử dụng các lớp trong {@link java.net} và 225 {@link android.net}. Bạn cũng có thể đồng bộ hoá dữ liệu trên nền mạng với một kho lưu trữ dữ liệu cục bộ 226 chẳng hạn như một cơ sở dữ liệu, rồi cung cấp dữ liệu dưới dạng bảng hoặc tệp. 227 Ứng dụng mẫu <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> 228 Trình điều hợp Đồng bộ Mẫu</a> minh họa loại đồng bộ hoá này. 229 </li> 230</ul> 231<h3 id="DataDesign"> 232 Những nội dung cần xem xét khi thiết kế dữ liệu 233</h3> 234<p> 235 Sau đây là một số mẹo để thiết kế cấu trúc dữ liệu cho trình cung cấp của bạn: 236</p> 237<ul> 238 <li> 239 Dữ liệu bảng nên luôn có một cột "khóa chính" mà trình cung cấp duy trì 240 như một giá trị số duy nhất cho mỗi hàng. Bạn có thể sử dụng giá trị này để liên kết hàng với các hàng 241 có liên quan trong các bảng khác (sử dụng nó làm "khóa ngoại"). Mặc dù bạn có thể sử dụng bất kỳ tên gọi nào 242 cho cột này, sử dụng {@link android.provider.BaseColumns#_ID BaseColumns._ID} là lựa chọn tốt nhất 243 vì việc liên kết các kết quả của một truy vấn trình cung cấp với 244 {@link android.widget.ListView} đòi hỏi một trong các cột được truy xuất phải có tên 245 <code>_ID</code>. 246 </li> 247 <li> 248 Nếu bạn muốn cung cấp các hình ảnh bitmap hoặc nội dung dữ liệu định hướng tệp rất lớn khác, hãy lưu trữ 249 dữ liệu vào một tệp rồi cung cấp nó gián tiếp thay vì lưu trữ nó trực tiếp trong một 250 bảng. Nếu làm vậy, bạn cần báo cho người dùng trình cung cấp của bạn rằng họ cần sử dụng một phương pháp tệp 251 {@link android.content.ContentResolver} để truy cập dữ liệu. 252 </li> 253 <li> 254 Sử dụng kiểu dữ liệu Binary Large OBject (BLOB) để lưu trữ dữ liệu có kích cỡ khác nhau hoặc có một 255 cấu trúc thay đổi. Ví dụ, bạn có thể sử dụng cột BLOB để lưu trữ một 256 <a href="http://code.google.com/p/protobuf">bộ đệm giao thức</a> hay 257 <a href="http://www.json.org">cấu trúc JSON</a>. 258 <p> 259 Bạn cũng có thể sử dụng một BLOB để triển khai một bảng <em>độc lập với sơ đồ</em>. Trong 260 kiểu bảng này, bạn định nghĩa một cột khóa chính, một cột kiểu MIME, và một hoặc 261 nhiều cột chung là BLOB. Ý nghĩa của dữ liệu trong cột BLOB được thể hiện 262 bởi giá trị trong cột kiểu MIME. Điều này cho phép bạn lưu trữ các kiểu hàng khác nhau trong 263 cùng bảng. Bảng "dữ liệu" 264 {@link android.provider.ContactsContract.Data} của Trình cung cấp Danh bạ là một ví dụ về bảng 265 độc lập với sơ đồ. 266 </p> 267 </li> 268</ul> 269<!-- Designing Content URIs --> 270<h2 id="ContentURI">Thiết kế URI Nội dung</h2> 271<p> 272 <strong>URI nội dung</strong> là một URI xác định dữ liệu trong một trình cung cấp. URI nội dung bao gồm 273 tên mang tính biểu tượng của toàn bộ trình cung cấp (<strong>quyền</strong> của nó) và một 274 tên trỏ đến một bảng hoặc tệp (<strong>đường dẫn</strong>). Phần id tùy chọn chỉ đến một 275 hàng riêng lẻ trong một bảng. Mọi phương thức truy cập dữ liệu 276 {@link android.content.ContentProvider} đều có một URI nội dung là một tham đối; điều này cho phép bạn 277 xác định bảng, hàng, hoặc tệp để truy cập. 278</p> 279<p> 280 Nội dung cơ bản của URI nội dung được mô tả trong chủ đề 281 <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> 282 Nội dung Cơ bản về Trình cung cấp Nội dung</a>. 283</p> 284<h3>Thiết kế một thẩm quyền</h3> 285<p> 286 Một trình cung cấp thường có một thẩm quyền duy nhất, đóng vai trò là tên nội bộ Android của nó. Để 287 tránh xung đột với các trình cung cấp khác, bạn nên sử dụng quyền sở hữu miền Internet (đảo ngược) 288 làm cơ sở cho thẩm quyền của trình cung cấp của mình. Vì đề xuất này cũng đúng đối với tên gói 289 Android, bạn có thể định nghĩa thẩm quyền trình cung cấp của mình là phần mở rộng của tên 290 gói chứa trình cung cấp. Ví dụ, nếu tên gói Android là 291 <code>com.example.<appname></code>, bạn nên cấp cho trình cung cấp của mình 292 thẩm quyền <code>com.example.<appname>.provider</code>. 293</p> 294<h3>Thiết kế một cấu trúc đường dẫn</h3> 295<p> 296 Nhà phát triển thường tạo URI nội dung từ thẩm quyền bằng cách nối các đường dẫn trỏ đến 297 các bảng riêng lẻ. Ví dụ, nếu bạn có hai bảng <em>table1</em> và 298 <em>table2</em>, bạn kết hợp thẩm quyền từ ví dụ trước để tạo ra 299 các URI nội dung 300 <code>com.example.<appname>.provider/table1</code> và 301 <code>com.example.<appname>.provider/table2</code>. Các đường dẫn 302 không bị giới hạn ở một phân đoạn duy nhất, và không cần phải có một bảng cho từng cấp của đường dẫn. 303</p> 304<h3>Xử lý ID URI nội dung</h3> 305<p> 306 Theo quy ước, các trình cung cấp cho phép truy cập một hàng đơn trong một bảng bằng cách chấp nhận một URI nội dung 307 có một giá trị ID cho hàng đó ở cuối URI. Cũng theo quy ước, các trình cung cấp sẽ so khớp 308 giá trị ID với cột <code>_ID</code> của bảng, và thực hiện truy cập yêu cầu đối với 309 hàng trùng khớp. 310</p> 311<p> 312 Quy ước này tạo điều kiện cho một kiểu mẫu thiết kế chung cho các ứng dụng truy cập một trình cung cấp. Ứng dụng 313 tiến hành truy vấn đối với trình cung cấp và hiển thị kết quả {@link android.database.Cursor} 314 trong một {@link android.widget.ListView} bằng cách sử dụng {@link android.widget.CursorAdapter}. 315 Định nghĩa {@link android.widget.CursorAdapter} yêu cầu một trong các cột trong 316 {@link android.database.Cursor} phải là <code>_ID</code> 317</p> 318<p> 319 Sau đó, người dùng chọn một trong các hàng được hiển thị từ UI để xem hoặc sửa đổi 320 dữ liệu. Ứng dụng sẽ nhận được hàng tương ứng từ {@link android.database.Cursor} làm nền cho 321 {@link android.widget.ListView}, nhận giá trị <code>_ID</code> cho hàng này, nối nó với 322 URI nội dung, và gửi yêu cầu truy cập tới trình cung cấp. Sau đó, trình cung cấp có thể thực hiện 323 truy vấn hoặc sửa đổi đối với chính xác hàng mà người dùng đã chọn. 324</p> 325<h3>Kiểu mẫu URI nội dung</h3> 326<p> 327 Để giúp bạn chọn hành động nào sẽ thực hiện cho URI nội dung đến, API của trình cung cấp sẽ bao gồm 328 lớp thuận tiện {@link android.content.UriMatcher}, nó ánh xạ "kiểu mẫu" URI nội dung với 329 các giá trị số nguyên. Bạn có thể sử dụng các giá trị số nguyên trong một câu lệnh <code>switch</code> mà chọn 330 hành động mong muốn cho URI nội dung hoặc URI mà khớp với một kiểu mẫu cụ thể. 331</p> 332<p> 333 Kiểu mẫu URI nội dung sẽ so khớp các URI nội dung bằng cách sử dụng ký tự đại diện: 334</p> 335 <ul> 336 <li> 337 <strong><code>*</code>:</strong> Khớp một xâu ký tự hợp lệ bất kỳ với chiều dài bất kỳ. 338 </li> 339 <li> 340 <strong><code>#</code>:</strong> Khớp một xâu ký tự số có chiều dài bất kỳ. 341 </li> 342 </ul> 343<p> 344 Lấy một ví dụ về thiết kế và tạo mã xử lý URI nội dung, hãy xét một trình cung cấp có 345 thẩm quyền <code>com.example.app.provider</code> mà nhận ra các URI nội dung 346 trỏ đến các bảng sau: 347</p> 348<ul> 349 <li> 350 <code>content://com.example.app.provider/table1</code>: Một bảng gọi là <code>table1</code>. 351 </li> 352 <li> 353 <code>content://com.example.app.provider/table2/dataset1</code>: Một bảng gọi là 354 <code>dataset1</code>. 355 </li> 356 <li> 357 <code>content://com.example.app.provider/table2/dataset2</code>: Một bảng gọi là 358 <code>dataset2</code>. 359 </li> 360 <li> 361 <code>content://com.example.app.provider/table3</code>: Một bảng gọi là <code>table3</code>. 362 </li> 363</ul> 364<p> 365 Trình cung cấp cũng nhận ra những URI nội dung này nếu chúng có một ID hàng được nối kèm, như 366 ví dụ <code>content://com.example.app.provider/table3/1</code> đối với hàng được nhận biết bởi 367 <code>1</code> trong <code>table3</code>. 368</p> 369<p> 370 Sẽ có thể có các kiểu mẫu URI nội dung sau: 371</p> 372<dl> 373 <dt> 374 <code>content://com.example.app.provider/*</code> 375 </dt> 376 <dd> 377 Khớp với bất kỳ URI nội dung nào trong trình cung cấp. 378 </dd> 379 <dt> 380 <code>content://com.example.app.provider/table2/*</code>: 381 </dt> 382 <dd> 383 Khớp với một URI nội dung cho các bảng <code>dataset1</code> 384 và <code>dataset2</code>, nhưng không khớp với URI nội dung cho <code>table1</code> hoặc 385 <code>table3</code>. 386 </dd> 387 <dt> 388 <code>content://com.example.app.provider/table3/#</code>: Khớp với một URI nội dung 389 cho các hàng đơn trong <code>table3</code>, chẳng hạn như 390 <code>content://com.example.app.provider/table3/6</code> đối với hàng được xác định bởi 391 <code>6</code>. 392 </dt> 393</dl> 394<p> 395 Đoạn mã HTML sau cho biết cách hoạt động của các phương pháp trong {@link android.content.UriMatcher}. 396 Đoạn mã này xử lý các URI cho toàn bộ một bảng khác với URI cho một 397 hàng đơn, bằng cách sử dụng mẫu hình URI nội dung 398 <code>content://<authority>/<path></code> cho các bảng, và 399 <code>content://<authority>/<path>/<id></code> cho các hàng đơn. 400</p> 401<p> 402 Phương pháp {@link android.content.UriMatcher#addURI(String, String, int) addURI()} ánh xạ một 403 thẩm quyền và đường dẫn tới một giá trị số nguyên. Phương pháp {@link android.content.UriMatcher#match(Uri) 404 match()} trả về giá trị số nguyên cho một URI. Câu lệnh <code>switch</code> sẽ chọn 405 giữa truy vấn toàn bộ bảng và truy vấn cho một bản ghi đơn: 406</p> 407<pre class="prettyprint"> 408public class ExampleProvider extends ContentProvider { 409... 410 // Creates a UriMatcher object. 411 private static final UriMatcher sUriMatcher; 412... 413 /* 414 * The calls to addURI() go here, for all of the content URI patterns that the provider 415 * should recognize. For this snippet, only the calls for table 3 are shown. 416 */ 417... 418 /* 419 * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used 420 * in the path 421 */ 422 sUriMatcher.addURI("com.example.app.provider", "table3", 1); 423 424 /* 425 * Sets the code for a single row to 2. In this case, the "#" wildcard is 426 * used. "content://com.example.app.provider/table3/3" matches, but 427 * "content://com.example.app.provider/table3 doesn't. 428 */ 429 sUriMatcher.addURI("com.example.app.provider", "table3/#", 2); 430... 431 // Implements ContentProvider.query() 432 public Cursor query( 433 Uri uri, 434 String[] projection, 435 String selection, 436 String[] selectionArgs, 437 String sortOrder) { 438... 439 /* 440 * Choose the table to query and a sort order based on the code returned for the incoming 441 * URI. Here, too, only the statements for table 3 are shown. 442 */ 443 switch (sUriMatcher.match(uri)) { 444 445 446 // If the incoming URI was for all of table3 447 case 1: 448 449 if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC"; 450 break; 451 452 // If the incoming URI was for a single row 453 case 2: 454 455 /* 456 * Because this URI was for a single row, the _ID value part is 457 * present. Get the last path segment from the URI; this is the _ID value. 458 * Then, append the value to the WHERE clause for the query 459 */ 460 selection = selection + "_ID = " uri.getLastPathSegment(); 461 break; 462 463 default: 464 ... 465 // If the URI is not recognized, you should do some error handling here. 466 } 467 // call the code to actually do the query 468 } 469</pre> 470<p> 471 Một lớp khác, {@link android.content.ContentUris}, sẽ cung cấp các phương pháp thuận tiện để làm việc 472 với phần <code>id</code> của URI nội dung. Các lớp {@link android.net.Uri} và 473 {@link android.net.Uri.Builder} bao gồm các phương pháp thuận tiện cho việc phân tích các đối tượng 474 {@link android.net.Uri} hiện có và xây dựng các đối tượng mới. 475</p> 476 477<!-- Implementing the ContentProvider class --> 478<h2 id="ContentProvider">Triển khai Lớp Trình cung cấp Nội dung</h2> 479<p> 480 Thực thể {@link android.content.ContentProvider} quản lý truy cập vào 481 một tập dữ liệu cấu trúc bằng cách xử lý yêu cầu từ các ứng dụng khác. Tất cả các dạng 482 truy cập cuối cùng đều gọi {@link android.content.ContentResolver}, sau đó nó gọi ra một phương pháp 483 cụ thể của {@link android.content.ContentProvider} để lấy quyền truy cập. 484</p> 485<h3 id="RequiredAccess">Phương pháp được yêu cầu</h3> 486<p> 487 Lớp tóm tắt {@link android.content.ContentProvider} sẽ định nghĩa sáu phương pháp tóm tắt 488 mà bạn phải triển khai như một phần lớp con cụ thể của mình. Tất cả những phương pháp này ngoại trừ 489 {@link android.content.ContentProvider#onCreate() onCreate()} đều được gọi ra bởi một ứng dụng máy khách 490 đang cố truy cập trình cung cấp nội dung của bạn: 491</p> 492<dl> 493 <dt> 494 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 495 query()} 496 </dt> 497 <dd> 498 Truy xuất dữ liệu từ trình cung cấp của bạn. Sử dụng các tham đối để chọn bảng để 499 truy vấn, các hàng và cột để trả về, và thứ tự sắp xếp của kết quả. 500 Trả về dữ liệu như một đối tượng {@link android.database.Cursor}. 501 </dd> 502 <dt> 503 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} 504 </dt> 505 <dd> 506 Chèn một hàng mới vào trình cung cấp của bạn. Sử dụng các tham đối để lựa chọn 507 bảng đích và nhận các giá trị cột để sử dụng. Trả về một URI nội dung cho 508 hàng mới chèn. 509 </dd> 510 <dt> 511 {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) 512 update()} 513 </dt> 514 <dd> 515 Cập nhật các hàng hiện tại trong trình cung cấp của bạn. Sử dụng các tham đối để lựa chọn bảng và hàng 516 để cập nhật và nhận các giá trị cột được cập nhật. Trả về số hàng được cập nhật. 517 </dd> 518 <dt> 519 {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} 520 </dt> 521 <dd> 522 Xóa hàng khỏi trình cung cấp của bạn. Sử dụng các tham đối để lựa chọn bảng và các hàng 523 cần xóa. Trả về số hàng được xóa. 524 </dd> 525 <dt> 526 {@link android.content.ContentProvider#getType(Uri) getType()} 527 </dt> 528 <dd> 529 Trả về kiểu MIME tương ứng với một URI nội dung. Phương pháp này được mô tả chi tiết hơn 530 trong phần <a href="#MIMETypes">Triển khai Kiểu MIME của Trình cung cấp Nội dung</a>. 531 </dd> 532 <dt> 533 {@link android.content.ContentProvider#onCreate() onCreate()} 534 </dt> 535 <dd> 536 Khởi tạo trình cung cấp của bạn. Hệ thống Android sẽ gọi ra phương pháp này ngay lập tức sau khi nó 537 tạo trình cung cấp của bạn. Để ý rằng trình cung cấp của bạn không được tạo cho đến khi đối tượng 538 {@link android.content.ContentResolver} cố truy cập nó. 539 </dd> 540</dl> 541<p> 542 Để ý rằng những phương pháp này có cùng chữ ký như các phương pháp 543 {@link android.content.ContentResolver} được đặt tên như nhau. 544</p> 545<p> 546 Việc bạn triển khai những phương pháp này nên xét tới các nội dung sau: 547</p> 548<ul> 549 <li> 550 Tất cả phương pháp này ngoại trừ {@link android.content.ContentProvider#onCreate() onCreate()} 551 đều có thể được gọi đồng thời bằng nhiều luồng, vì thế chúng phải an toàn đối với luồng. Để tìm hiểu 552 thêm về nhiều luồng, hãy xem chủ đề 553 <a href="{@docRoot}guide/components/processes-and-threads.html"> 554 Tiến trình và Luồng</a>. 555 </li> 556 <li> 557 Tránh thực hiện những thao tác dài trong {@link android.content.ContentProvider#onCreate() 558 onCreate()}. Hoãn các tác vụ khởi tạo tới khi chúng thực sự cần thiết. 559 Phần <a href="#OnCreate">Triển khai phương pháp onCreate()</a> 560 sẽ bàn kỹ hơn về vấn đề này. 561 </li> 562 <li> 563 Mặc dù bạn phải triển khai những phương pháp này, mã của bạn không nhất thiết phải làm gì ngoại trừ việc 564 trả về kiểu dữ liệu kỳ vọng. Ví dụ, bạn có thể muốn ngăn những ứng dụng khác 565 chèn dữ liệu vào một số bảng. Để làm điều này, bạn có thể bỏ qua lệnh gọi tới 566 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} và trả về 567 0. 568 </li> 569</ul> 570<h3 id="Query">Triển khai phương pháp query()</h3> 571<p> 572 Phương pháp 573 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 574 ContentProvider.query()} phải trả về một đối tượng {@link android.database.Cursor}, nếu không nó sẽ thất bại 575, đưa ra một lỗi {@link java.lang.Exception}. Nếu bạn đang sử dụng một cơ sở dữ liệu SQLite làm kho lưu trữ dữ liệu của mình 576, bạn có thể chỉ cần trả về {@link android.database.Cursor} được trả về bởi một trong các phương pháp 577 <code>query()</code> của lớp {@link android.database.sqlite.SQLiteDatabase}. 578 Nếu truy vấn không khớp với bất kỳ hàng nào, bạn nên trả về một thực thể {@link android.database.Cursor} 579 có phương pháp {@link android.database.Cursor#getCount()} trả về 0. 580 Bạn chỉ nên trả về <code>null</code> nếu đã xảy ra một lỗi nội bộ trong tiến trình truy vấn. 581</p> 582<p> 583 Nếu bạn không đang sử dụng một cơ sở dữ liệu SQLite làm kho lưu trữ dữ liệu của mình, hãy sử dụng một trong các lớp con cụ thể 584 của {@link android.database.Cursor}. Ví dụ, lớp {@link android.database.MatrixCursor} sẽ triển khai 585 một con chạy trong đó mỗi hàng là một mảng của {@link java.lang.Object}. Với lớp này, 586 hãy sử dụng {@link android.database.MatrixCursor#addRow(Object[]) addRow()} để thêm một hàng mới. 587</p> 588<p> 589 Nhớ rằng hệ thống Android phải có thể giao tiếp với {@link java.lang.Exception} 590 qua các ranh giới tiến trình. Android có thể làm vậy cho những trường hợp ngoại lệ sau, điều này có thể hữu ích 591 trong xử lý lỗi truy vấn: 592</p> 593<ul> 594 <li> 595 {@link java.lang.IllegalArgumentException} (Bạn có thể chọn đưa ra lỗi này nếu trình cung cấp của bạn 596 nhận một URI nội dung không hợp lệ) 597 </li> 598 <li> 599 {@link java.lang.NullPointerException} 600 </li> 601</ul> 602<h3 id="Insert">Triển khai phương pháp insert()</h3> 603<p> 604 Phương pháp {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} sẽ thêm một 605 hàng mới vào bảng phù hợp bằng cách sử dụng các giá trị trong tham đối {@link android.content.ContentValues} 606. Nếu tên cột không nằm trong tham đối {@link android.content.ContentValues}, bạn có thể 607 muốn cung cấp một giá trị mặc định cho nó hoặc trong mã trình cung cấp của bạn hoặc trong sơ đồ 608 cơ sở dữ liệu của bạn. 609</p> 610<p> 611 Phương pháp này sẽ trả về URI nội dung cho hàng mới. Để xây dựng điều này, hãy nối 612 giá trị <code>_ID</code> của hàng mới (hay khóa chính khác) với URI nội dung của bảng bằng cách sử dụng 613 {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}. 614</p> 615<h3 id="Delete">Triển khai phương pháp delete()</h3> 616<p> 617 Phương pháp {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} 618 không cần phải xóa hàng thực chất khỏi kho lưu trữ dữ liệu của bạn. Nếu bạn đang sử dụng một trình điều hợp đồng bộ 619 với trình cung cấp của mình, bạn nên cân nhắc đánh dấu một hàng đã xóa 620 bằng cờ "xóa" thay vì gỡ bỏ hàng một cách hoàn toàn. Trình điều hợp đồng bộ có thể 621 kiểm tra các hàng đã xóa và gỡ bỏ chúng khỏi máy chủ trước khi xóa chúng khỏi trình cung cấp. 622</p> 623<h3 id="Update">Triển khai phương pháp update()</h3> 624<p> 625 Phương pháp {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[]) 626 update()} lấy cùng tham đối {@link android.content.ContentValues} được sử dụng bởi 627 {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, và 628 cùng tham đối <code>selection</code> và <code>selectionArgs</code> được sử dụng bởi 629 {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} và 630 {@link android.content.ContentProvider#query(Uri, String[], String, String[], String) 631 ContentProvider.query()}. Điều này có thể cho phép bạn sử dụng lại mã giữa những phương pháp này. 632</p> 633<h3 id="OnCreate">Triển khai phương pháp onCreate()</h3> 634<p> 635 Hệ thống Android sẽ gọi {@link android.content.ContentProvider#onCreate() 636 onCreate()} khi nó khởi động trình cung cấp. Bạn chỉ nên thực hiện các tác vụ khởi tạo chạy nhanh 637 trong phương pháp này, và hoãn việc tạo cơ sở dữ liệu và nạp dữ liệu tới khi trình cung cấp thực sự 638 nhận được yêu cầu cho dữ liệu. Nếu bạn thực hiện các tác vụ dài trong 639 {@link android.content.ContentProvider#onCreate() onCreate()}, bạn sẽ làm chậm lại 640 quá trình khởi động của trình cung cấp. Đến lượt mình, điều này sẽ làm chậm hồi đáp từ trình cung cấp đối với các 641 ứng dụng khác. 642</p> 643<p> 644 Ví dụ, nếu bạn đang sử dụng một cơ sở dữ liệu SQLite, bạn có thể tạo 645 một đối tượng {@link android.database.sqlite.SQLiteOpenHelper} mới trong 646 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}, 647 rồi tạo các bảng SQL lần đầu tiên khi bạn mở cơ sở dữ liệu. Để tạo điều kiện cho điều này, 648 lần đầu tiên bạn gọi {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase 649 getWritableDatabase()}, nó sẽ tự động gọi ra phương pháp 650 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 651 SQLiteOpenHelper.onCreate()}. 652</p> 653<p> 654 Hai đoạn mã HTML sau minh họa tương tác giữa 655 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} và 656 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 657 SQLiteOpenHelper.onCreate()}. Đoạn mã HTML đầu tiên là triển khai 658 {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}: 659</p> 660<pre class="prettyprint"> 661public class ExampleProvider extends ContentProvider 662 663 /* 664 * Defines a handle to the database helper object. The MainDatabaseHelper class is defined 665 * in a following snippet. 666 */ 667 private MainDatabaseHelper mOpenHelper; 668 669 // Defines the database name 670 private static final String DBNAME = "mydb"; 671 672 // Holds the database object 673 private SQLiteDatabase db; 674 675 public boolean onCreate() { 676 677 /* 678 * Creates a new helper object. This method always returns quickly. 679 * Notice that the database itself isn't created or opened 680 * until SQLiteOpenHelper.getWritableDatabase is called 681 */ 682 mOpenHelper = new MainDatabaseHelper( 683 getContext(), // the application context 684 DBNAME, // the name of the database) 685 null, // uses the default SQLite cursor 686 1 // the version number 687 ); 688 689 return true; 690 } 691 692 ... 693 694 // Implements the provider's insert method 695 public Cursor insert(Uri uri, ContentValues values) { 696 // Insert code here to determine which table to open, handle error-checking, and so forth 697 698 ... 699 700 /* 701 * Gets a writeable database. This will trigger its creation if it doesn't already exist. 702 * 703 */ 704 db = mOpenHelper.getWritableDatabase(); 705 } 706} 707</pre> 708<p> 709 Đoạn mã HTML tiếp theo là triển khai 710 {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) 711 SQLiteOpenHelper.onCreate()}, bao gồm một lớp trình trợ giúp: 712</p> 713<pre class="prettyprint"> 714... 715// A string that defines the SQL statement for creating a table 716private static final String SQL_CREATE_MAIN = "CREATE TABLE " + 717 "main " + // Table's name 718 "(" + // The columns in the table 719 " _ID INTEGER PRIMARY KEY, " + 720 " WORD TEXT" 721 " FREQUENCY INTEGER " + 722 " LOCALE TEXT )"; 723... 724/** 725 * Helper class that actually creates and manages the provider's underlying data repository. 726 */ 727protected static final class MainDatabaseHelper extends SQLiteOpenHelper { 728 729 /* 730 * Instantiates an open helper for the provider's SQLite data repository 731 * Do not do database creation and upgrade here. 732 */ 733 MainDatabaseHelper(Context context) { 734 super(context, DBNAME, null, 1); 735 } 736 737 /* 738 * Creates the data repository. This is called when the provider attempts to open the 739 * repository and SQLite reports that it doesn't exist. 740 */ 741 public void onCreate(SQLiteDatabase db) { 742 743 // Creates the main table 744 db.execSQL(SQL_CREATE_MAIN); 745 } 746} 747</pre> 748 749 750<!-- Implementing ContentProvider MIME Types --> 751<h2 id="MIMETypes">Triển khai Kiểu MIME của Trình cung cấp Nội dung</h2> 752<p> 753 Lớp {@link android.content.ContentProvider} có hai phương pháp để trả về các kiểu MIME: 754</p> 755<dl> 756 <dt> 757 {@link android.content.ContentProvider#getType(Uri) getType()} 758 </dt> 759 <dd> 760 Một trong các phương pháp được yêu cầu mà bạn phải triển khai cho bất kỳ trình cung cấp nào. 761 </dd> 762 <dt> 763 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} 764 </dt> 765 <dd> 766 Một phương pháp mà bạn được dự tính sẽ triển khai nếu trình cung cấp của bạn cung cấp tệp. 767 </dd> 768</dl> 769<h3 id="TableMIMETypes">Kiểu MIME cho bảng</h3> 770<p> 771 Phương pháp {@link android.content.ContentProvider#getType(Uri) getType()} trả về một 772 {@link java.lang.String} theo định dạng MIME mà mô tả kiểu dữ liệu được trả về bởi tham đối 773 URI nội dung. Tham đối {@link android.net.Uri} có thể là một mẫu hình thay vì một URI cụ thể; 774 trong trường hợp này, bạn nên trả về kiểu dữ liệu được liên kết với các URI nội dung mà khớp với 775 mẫu hình đó. 776</p> 777<p> 778 Đối với các kiểu dữ liệu phổ biến như văn bản, HTML, hay JPEG, 779 {@link android.content.ContentProvider#getType(Uri) getType()} sẽ trả về 780 kiểu MIME tiêu chuẩn cho dữ liệu đó. Một danh sách đầy đủ về những kiểu tiêu chuẩn này có sẵn trên trang web 781 <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a> 782. 783</p> 784<p> 785 Đối với các URI nội dung mà trỏ tới một hàng hoặc các hàng của bảng dữ liệu, 786 {@link android.content.ContentProvider#getType(Uri) getType()} sẽ trả về 787 một kiểu MIME theo định dạng MIME riêng cho nhà cung cấp của Android: 788</p> 789<ul> 790 <li> 791 Bộ phận kiểu: <code>vnd</code> 792 </li> 793 <li> 794 Bộ phận kiểu con: 795 <ul> 796 <li> 797 Nếu mẫu hình URI áp dụng cho một hàng đơn: <code>android.cursor.<strong>item</strong>/</code> 798 </li> 799 <li> 800 Nếu mẫu hình URI áp dụng cho nhiều hơn một hàng: <code>android.cursor.<strong>dir</strong>/</code> 801 </li> 802 </ul> 803 </li> 804 <li> 805 Bộ phận riêng theo trình cung cấp: <code>vnd.<name></code>.<code><type></code> 806 <p> 807 Bạn cung cấp <code><name></code> và <code><type></code>. 808 Giá trị <code><name></code> nên là giá trị duy nhất toàn cục, 809 và giá trị <code><type></code> nên là giá trị duy nhất đối với mẫu hình 810 URI tương ứng. Một lựa chọn hay cho <code><name></code> đó là tên công ty của bạn hoặc 811 một thành phần nào đó trong tên gói Android cho ứng dụng của bạn. Một lựa chọn hay cho 812 <code><type></code> đó là một xâu xác định bảng được liên kết với 813 URI. 814 </p> 815 816 </li> 817</ul> 818<p> 819 Ví dụ, nếu thẩm quyền của một trình cung cấp là 820 <code>com.example.app.provider</code>, và nó làm hiện ra một bảng có tên 821 <code>table1</code> thì kiểu MIME cho nhiều hàng trong <code>table1</code> là: 822</p> 823<pre> 824vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1 825</pre> 826<p> 827 Đối với một hàng đơn của <code>table1</code>, kiểu MIME là: 828</p> 829<pre> 830vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1 831</pre> 832<h3 id="FileMIMETypes">Kiểu MIME cho tệp</h3> 833<p> 834 Nếu trình cung cấp của bạn cung cấp tệp, hãy triển khai 835 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}. 836 Phương pháp này sẽ trả về một mảng {@link java.lang.String} của kiểu MIME đối với các tệp mà trình cung cấp của bạn 837 có thể trả về cho một URI nội dung cho trước. Bạn nên lọc các kiểu MIME mà mình cung cấp bằng tham đối bộ lọc 838 kiểu MIME, sao cho bạn chỉ trả về những kiểu MIME mà máy khách muốn xử lý. 839</p> 840<p> 841 Ví dụ, xét một trình cung cấp hình ảnh dưới dạng tệp có định dạng <code>.jpg</code>, 842 <code>.png</code> và <code>.gif</code>. 843 Nếu một ứng dụng gọi {@link android.content.ContentResolver#getStreamTypes(Uri, String) 844 ContentResolver.getStreamTypes()} bằng xâu bộ lọc <code>image/*</code> ( 845 mà là một "hình ảnh"), 846 khi đó phương pháp {@link android.content.ContentProvider#getStreamTypes(Uri, String) 847 ContentProvider.getStreamTypes()} sẽ trả về mảng: 848</p> 849<pre> 850{ "image/jpeg", "image/png", "image/gif"} 851</pre> 852<p> 853 Nếu ứng dụng chỉ quan tâm đến các tệp <code>.jpg</code>, vậy nó có thể gọi 854 {@link android.content.ContentResolver#getStreamTypes(Uri, String) 855 ContentResolver.getStreamTypes()} bằng xâu bộ lọc <code>*\/jpeg</code>, và 856 {@link android.content.ContentProvider#getStreamTypes(Uri, String) 857 ContentProvider.getStreamTypes()} sẽ trả về: 858<pre> 859{"image/jpeg"} 860</pre> 861<p> 862 Nếu trình cung cấp của bạn không cung cấp bất kỳ kiểu MIME nào được yêu cầu trong xâu bộ lọc, 863 {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()} 864 sẽ trả về <code>null</code>. 865</p> 866 867 868<!-- Implementing a Contract Class --> 869<h2 id="ContractClass">Triển khai một Lớp Hợp đồng</h2> 870<p> 871 Lớp hợp đồng là một lớp <code>public final</code> chứa các định nghĩa hằng số cho 872 URI, tên cột, kiểu MIME, và siêu dữ liệu khác liên quan tới trình cung cấp. Lớp này 873 sẽ thiết lập một hợp đồng giữa trình cung cấp và các ứng dụng khác bằng cách đảm bảo rằng trình cung cấp 874 có thể được truy cập đúng ngay cả khi có thay đổi về giá trị thực sự của URI, tên cột, 875 v.v. 876</p> 877<p> 878 Lớp hợp đồng cũng giúp các nhà phát triển vì chúng thường có tên dễ nhớ cho các hằng số của mình, 879 vì vậy các nhà phát triển ít có khả năng sử dụng các giá trị không đúng cho tên cột hay URI hơn. Do đó là một 880 lớp, nó có thể chứa tài liệu Javadoc. Các môi trường phát triển tích hợp như 881 Eclipse có thể tự động điền các tên hằng số từ lớp hợp đồng và hiển thị Javadoc cho các 882 hằng số đó. 883</p> 884<p> 885 Các nhà phát triển không thể truy cập tệp lớp của lớp hợp đồng từ ứng dụng của mình, nhưng họ có thể 886 lặng lẽ biên dịch nó vào ứng dụng của họ từ một tệp <code>.jar</code> mà bạn cung cấp. 887</p> 888<p> 889 Lớp {@link android.provider.ContactsContract} và các lớp lồng nhau của nó là các ví dụ về 890 lớp hợp đồng. 891</p> 892<h2 id="Permissions">Triển khai Quyền của Trình cung cấp Nội dung</h2> 893<p> 894 Quyền và truy cập đối với tất cả khía cạnh trong hệ thống Android được mô tả chi tiết trong 895 chủ đề <a href="{@docRoot}guide/topics/security/security.html">Bảo mật và Quyền</a>. 896 Chủ đề <a href="{@docRoot}guide/topics/data/data-storage.html">Kho lưu trữ Dữ liệu</a> cũng 897 mô tả bảo mật và các quyền có hiệu lực cho nhiều loại kho lưu trữ khác nhau. 898 Nói tóm lại, các điểm quan trọng là: 899</p> 900<ul> 901 <li> 902 Theo mặc định, các tệp dữ liệu được lưu trữ trên bộ nhớ trong của thiết bị là dữ liệu riêng tư 903 đối với ứng dụng và trình cung cấp của bạn. 904 </li> 905 <li> 906 Các cơ sở dữ liệu {@link android.database.sqlite.SQLiteDatabase} mà bạn tạo là dữ liệu riêng tư 907 đối với ứng dụng và trình cung cấp của bạn. 908 </li> 909 <li> 910 Theo mặc định, các tệp dữ liệu mà bạn lưu vào bộ nhớ ngoài là dữ liệu <em>công khai</em> và 911 <em>đọc được công khai</em>. Bạn không thể sử dụng một trình cung cấp nội dung để hạn chế truy cập vào các tệp trong 912 bộ nhớ ngoài vì các ứng dụng khác có thể sử dụng lệnh gọi API khác để đọc và ghi chúng. 913 </li> 914 <li> 915 Các lệnh gọi phương pháp để mở hoặc tạo tệp hoặc cơ sở dữ liệu SQLite trên bộ nhớ trong 916 của thiết bị của bạn có thể cấp quyền truy cập đọc và ghi cho tất cả ứng dụng khác. Nếu bạn 917 sử dụng một tệp hoặc cơ sở dữ liệu nội bộ làm kho lưu giữ của trình cung cấp của mình, và bạn cấp quyền truy cập 918 "đọc được công khai" hoặc "ghi được công khai", quyền mà bạn đặt cho trình cung cấp của mình trong 919 bản kê khai của nó sẽ không bảo vệ dữ liệu của bạn. Quyền truy cập mặc định cho các tệp và cơ sở dữ liệu trong 920 bộ nhớ trong là "riêng tư", và đối với kho lưu giữ của trình cung cấp của mình, bạn không nên thay đổi điều này. 921 </li> 922</ul> 923<p> 924 Nếu bạn muốn sử dụng các quyền của trình cung cấp nội dung để kiểm soát truy cập vào dữ liệu của mình, khi đó bạn nên 925 lưu trữ dữ liệu của mình trong các tệp nội bộ, cơ sở dữ liệu SQLite, hoặc "đám mây" (ví dụ, 926 trên một máy chủ từ xa), và bạn nên giữ các tệp và cơ sở dữ liệu riêng tư cho ứng dụng của mình. 927</p> 928<h3>Triển khai quyền</h3> 929<p> 930 Tất cả ứng dụng đều có thể đọc từ hoặc ghi vào trình cung cấp của bạn, ngay cả khi dữ liệu liên quan 931 là dữ liệu riêng tư, vì theo mặc định, trình cung cấp của bạn không được đặt quyền. Để thay đổi điều này, 932 hãy đặt quyền cho trình cung cấp của bạn trong tệp bản kê khai của bạn bằng cách sử dụng các thuộc tính hoặc phần tử 933 con của phần tử <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 934 <provider></a></code>. Bạn có thể đặt quyền áp dụng cho toàn bộ trình cung cấp, 935 hoặc cho một số bảng, hoặc thậm chí cho một số bản ghi, hoặc cả ba. 936</p> 937<p> 938 Bạn định nghĩa các quyền cho trình cung cấp của bạn bằng một hoặc nhiều phần tử 939 <code><a href="{@docRoot}guide/topics/manifest/permission-element.html"> 940 <permission></a></code> trong tệp bản kê khai của bạn. Để 941 quyền là duy nhất cho trình cung cấp của bạn, hãy sử dụng phạm vi kiểu Java cho thuộc tính 942 <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm"> 943 android:name</a></code>. Ví dụ, đặt tên quyền đọc 944 <code>com.example.app.provider.permission.READ_PROVIDER</code>. 945 946</p> 947<p> 948 Danh sách sau liệt kê phạm vi các quyền của trình cung cấp, bắt đầu với các quyền 949 áp dụng cho toàn bộ trình cung cấp rồi mới đến các quyền chi tiết hơn. 950 Các quyền chi tiết hơn được ưu tiên so với các quyền có phạm vi rộng hơn: 951</p> 952<dl> 953 <dt> 954 Quyền đọc-ghi đơn lẻ ở cấp trình cung cấp 955 </dt> 956 <dd> 957 Một quyền kiểm soát cả quyền truy cập đọc và ghi cho toàn bộ trình cung cấp, được quy định 958 bằng thuộc tính <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> 959 android:permission</a></code> của phần tử 960 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 961 <provider></a></code>. 962 </dd> 963 <dt> 964 Quyền đọc ghi tách riêng ở cấp độ trình cung cấp 965 </dt> 966 <dd> 967 Một quyền đọc và một quyền ghi cho toàn bộ trình cung cấp. Bạn chỉ định chúng 968 bằng các thuộc tính <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> 969 android:readPermission</a></code> và 970 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> 971 android:writePermission</a></code> của phần tử 972 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 973 <provider></a></code>. Chúng được ưu tiên so với quyền được yêu cầu bởi 974 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> 975 android:permission</a></code>. 976 </dd> 977 <dt> 978 Quyền ở cấp đường dẫn 979 </dt> 980 <dd> 981 Quyền đọc, ghi, hoặc đọc/ghi cho một URI nội dung trong trình cung cấp của bạn. Bạn chỉ định 982 từng URI mà bạn muốn kiểm soát bằng một phần tử con 983 <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"> 984 <path-permission></a></code> của phần tử 985 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 986 <provider></a></code>. Với mỗi một URI nội dung mà bạn chỉ định, bạn có thể chỉ định một 987 quyền đọc/ghi, quyền đọc, hoặc quyền ghi, hoặc cả ba. Quyền đọc và 988 quyền ghi được ưu tiên so với quyền đọc/ghi. Đồng thời, quyền ở cấp độ đường dẫn 989 sẽ được ưu tiên so với quyền ở cấp độ trình cung cấp. 990 </dd> 991 <dt> 992 Quyền tạm thời 993 </dt> 994 <dd> 995 Là cấp độ quyền cho phép truy cập tạm thời vào một ứng dụng, ngay cả khi ứng dụng 996 không có các quyền thường được yêu cầu. Tính năng truy cập 997 tạm thời làm giảm số quyền mà một ứng dụng phải yêu cầu trong 998 bản kê khai của mình. Khi bạn dùng đến các quyền tạm thời, những ứng dụng duy nhất mà cần 999 quyền "lâu dài" cho trình cung cấp của bạn là những ứng dụng liên tục truy cập tất cả 1000 dữ liệu của bạn. 1001 <p> 1002 Xét các quyền bạn cần để triển khai một trình cung cấp và ứng dụng e-mail khi bạn 1003 muốn cho phép một ứng dụng trình xem ảnh bên ngoài hiển thị các tài liệu đính kèm dạng ảnh từ trình cung cấp 1004 của bạn. Để cấp cho trình xem ảnh quyền truy cập cần thiết mà không cần yêu cầu quyền, 1005 hãy thiết lập các quyền tạm thời cho URI nội dung đối với ảnh. Thiết kế ứng dụng e-mail của bạn sao cho 1006 khi người dùng muốn hiển thị một ảnh, ứng dụng sẽ gửi một ý định chứa URI nội dung 1007 của ảnh và cờ cho phép tới trình xem ảnh. Trình xem ảnh khi đó có thể 1008 truy vấn trình cung cấp e-mail của bạn để truy xuất ảnh, ngay cả khi trình xem không 1009 có quyền đọc bình thường cho trình cung cấp của bạn. 1010 </p> 1011 <p> 1012 Để sử dụng các quyền tạm thời, hoặc đặt thuộc tính 1013 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> 1014 android:grantUriPermissions</a></code> của phần tử 1015 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1016 <provider></a></code> hoặc thêm một hoặc nhiều phần tử con 1017 <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> 1018 <grant-uri-permission></a></code> vào phần tử 1019 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1020 <provider></a></code> của bạn. Nếu bạn sử dụng các quyền tạm thời, bạn phải gọi 1021 {@link android.content.Context#revokeUriPermission(Uri, int) 1022 Context.revokeUriPermission()} bất cứ khi nào bạn gỡ bỏ hỗ trợ cho một URI nội dung khỏi 1023 trình cung cấp của mình, và URI nội dung đó sẽ được liên kết với một quyền tạm thời. 1024 </p> 1025 <p> 1026 Giá trị của thuộc tính sẽ xác định trình cung cấp của bạn được cho phép truy cập bao nhiêu. 1027 Nếu thuộc tính được đặt thành <code>true</code>, khi đó hệ thống sẽ cấp quyền tạm thời 1028 cho toàn bộ trình cung cấp của bạn, khống chế mọi quyền khác mà được yêu cầu bởi 1029 quyền ở cấp độ trình cung cấp hoặc cấp độ đường dẫn của bạn. 1030 </p> 1031 <p> 1032 Nếu cờ này được đặt thành <code>false</code>, khi đó bạn phải thêm các phần tử con 1033 <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html"> 1034 <grant-uri-permission></a></code> vào phần tử 1035 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1036 <provider></a></code> của mình. Mỗi phần tử con lại quy định URI nội dung hoặc 1037 các URI mà truy cập tạm thời được cấp cho. 1038 </p> 1039 <p> 1040 Để ủy quyền truy cập tạm thời cho một ứng dụng, ý định phải chứa 1041 cờ {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} hoặc cờ 1042 {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, hoặc cả hai. Những quyền 1043 này được đặt bằng phương pháp {@link android.content.Intent#setFlags(int) setFlags()}. 1044 </p> 1045 <p> 1046 Nếu thuộc tính <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> 1047 android:grantUriPermissions</a></code> không có mặt, giả sử rằng nó là 1048 <code>false</code>. 1049 </p> 1050 </dd> 1051</dl> 1052 1053 1054 1055<!-- The Provider Element --> 1056<h2 id="ProviderElement">Phần tử <provider></h2> 1057<p> 1058 Như các thành phần {@link android.app.Activity} và {@link android.app.Service}, 1059 một lớp con của {@link android.content.ContentProvider} 1060 phải được định nghĩa trong tệp bản kê khai cho ứng dụng của nó bằng cách sử dụng phần tử 1061 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1062 <provider></a></code>. Hệ thống Android nhận thông tin sau từ 1063 phần tử: 1064<dl> 1065 <dt> 1066 Thẩm quyền 1067 (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code 1068 android:authorities}</a>) 1069 </dt> 1070 <dd> 1071 Các tên biểu tượng nhận biết toàn bộ trình cung cấp trong hệ thống. Thuộc tính 1072 này được mô tả chi tiết hơn trong phần 1073 <a href="#ContentURI">Thiết kế URI Nội dung</a>. 1074 </dd> 1075 <dt> 1076 Tên lớp của trình cung cấp 1077 (<code> 1078<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a> 1079 </code>) 1080 </dt> 1081 <dd> 1082 Lớp triển khai {@link android.content.ContentProvider}. Lớp này 1083 được mô tả chi tiết hơn trong phần 1084 <a href="#ContentProvider">Triển khai Lớp Trình cung cấp Nội dung</a>. 1085 </dd> 1086 <dt> 1087 Quyền 1088 </dt> 1089 <dd> 1090 Những thuộc tính quy định quyền mà các ứng dụng khác phải có để truy cập 1091 dữ liệu của trình cung cấp: 1092 <ul> 1093 <li> 1094 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn"> 1095 android:grantUriPermssions</a></code>: Cờ quyền tạm thời. 1096 </li> 1097 <li> 1098 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn"> 1099 android:permission</a></code>: Quyền đọc/ghi đơn lẻ đối với toàn bộ trình cung cấp. 1100 </li> 1101 <li> 1102 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn"> 1103 android:readPermission</a></code>: Quyền đọc đối với toàn bộ trình cung cấp. 1104 </li> 1105 <li> 1106 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn"> 1107 android:writePermission</a></code>: Quyền ghi đối với toàn bộ trình cung cấp. 1108 </li> 1109 </ul> 1110 <p> 1111 Các quyền và thuộc tính tương ứng của chúng được mô tả chi tiết hơn trong 1112 phần 1113 <a href="#Permissions">Triển khai Quyền của Trình cung cấp Nội dung</a>. 1114 </p> 1115 </dd> 1116 <dt> 1117 Thuộc tính khởi động và kiểm soát 1118 </dt> 1119 <dd> 1120 Những thuộc tính này xác định cách và thời điểm hệ thống Android khởi động trình cung cấp, các 1121 đặc tính tiến trình của trình cung cấp, và các thiết đặt về thời gian chạy: 1122 <ul> 1123 <li> 1124 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled"> 1125 android:enabled</a></code>: Cờ cho phép hệ thống khởi động trình cung cấp. 1126 </li> 1127 <li> 1128 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported"> 1129 android:exported</a></code>: Cờ cho phép các ứng dụng sử dụng trình cung cấp này. 1130 </li> 1131 <li> 1132 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init"> 1133 android:initOrder</a></code>: Thứ tự mà trình cung cấp nên được khởi động, 1134 so với các trình cung cấp khác trong cùng tiến trình. 1135 </li> 1136 <li> 1137 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi"> 1138 android:multiProcess</a></code>: Cờ cho phép hệ thống khởi động trình cung cấp 1139 trong cùng tiến trình như máy khách gọi. 1140 </li> 1141 <li> 1142 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc"> 1143 android:process</a></code>: Tên của tiến trình mà trình cung cấp 1144 nên chạy trong đó. 1145 </li> 1146 <li> 1147 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync"> 1148 android:syncable</a></code>: Cờ cho biết rằng dữ liệu của trình cung cấp sẽ được 1149 đồng bộ với dữ liệu trên một máy chủ. 1150 </li> 1151 </ul> 1152 <p> 1153 Các thuộc tính được lập tài liệu theo dõi đầy đủ trong chủ đề hướng dẫn nhà phát triển đối với phần tử 1154 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1155 <provider></a></code> 1156. 1157 </p> 1158 </dd> 1159 <dt> 1160 Các thuộc tính thông tin 1161 </dt> 1162 <dd> 1163 Một biểu tượng tùy chọn và nhãn cho trình cung cấp: 1164 <ul> 1165 <li> 1166 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon"> 1167 android:icon</a></code>: Một tài nguyên có thể vẽ chứa một biểu tượng cho trình cung cấp. 1168 Biểu tượng xuất hiện bên cạnh nhãn của trình cung cấp trong danh sách ứng dụng trong 1169 <em>Settings</em> > <em>Apps</em> > <em>All</em>. 1170 </li> 1171 <li> 1172 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label"> 1173 android:label</a></code>: Một nhãn thông tin mô tả trình cung cấp hoặc dữ liệu 1174 của nó, hoặc cả hai. Nhãn xuất hiện trong danh sách ứng dụng trong 1175 <em>Settings</em> > <em>Apps</em> > <em>All</em>. 1176 </li> 1177 </ul> 1178 <p> 1179 Các thuộc tính được lập tài liệu theo dõi đầy đủ trong chủ đề hướng dẫn nhà phát triển đối với phần tử 1180 <code><a href="{@docRoot}guide/topics/manifest/provider-element.html"> 1181 <provider></a></code>. 1182 </p> 1183 </dd> 1184</dl> 1185 1186<!-- Intent Access --> 1187<h2 id="Intents">Ý định và Truy cập Dữ liệu</h2> 1188<p> 1189 Các ứng dụng có thể gián tiếp truy cập một trình cung cấp nội dung bằng một {@link android.content.Intent}. 1190 Ứng dụng không gọi bất kỳ phương pháp nào của {@link android.content.ContentResolver} hoặc 1191 {@link android.content.ContentProvider}. Thay vào đó, nó sẽ gửi một ý định để bắt đầu một hoạt động, 1192 đây thường là một bộ phận trong ứng dụng của chính trình cung cấp. Hoạt động đích phụ trách 1193 truy xuất và hiển thị dữ liệu trong UI của nó. Tùy vào hành động trong ý định, hoạt động 1194 đích cũng có thể nhắc người dùng thực hiện sửa đổi dữ liệu của trình cung cấp. 1195 Một ý định cũng có thể chứa dữ liệu "phụ thêm" mà hoạt động đích hiển thị 1196 trong UI; khi đó người dùng có tùy chọn thay đổi dữ liệu này trước khi sử dụng nó để sửa đổi 1197 dữ liệu trong trình cung cấp. 1198</p> 1199<p> 1200 1201</p> 1202<p> 1203 Bạn có thể muốn sử dụng truy cập ý định để giúp đảm bảo toàn vẹn dữ liệu. Trình cung cấp của bạn có thể phụ thuộc vào 1204 việc chèn, cập nhật và xóa dữ liệu theo lô-gic nghiệp vụ được quy định chặt chẽ. Trong 1205 trường hợp như vậy, việc cho phép các ứng dụng khác trực tiếp sửa đổi dữ liệu của bạn có thể dẫn đến dữ liệu 1206 không hợp lệ. Nếu bạn muốn các nhà phát triển sử dụng truy cập ý định, hãy đảm bảo lập tài liệu theo dõi nó thật kỹ. 1207 Giải thích với họ tại sao truy cập ý định sử dụng UI ứng dụng của chính bạn lại tốt hơn là cố gắng sửa đổi 1208 dữ liệu bằng mã của họ. 1209</p> 1210<p> 1211 Việc xử lý một ý định đến nhằm sửa đổi dữ liệu của trình cung cấp của bạn không khác với 1212 việc xử lý các ý định khác. Bạn có thể tìm hiểu về việc sử dụng ý định bằng cách đọc chủ đề 1213 <a href="{@docRoot}guide/components/intents-filters.html">Ý định và Bộ lọc Ý định</a>. 1214</p> 1215