LƯU TRỮ DỮ LIỆU – SQLITE
KHÁI NIỆM CƠ SỞ DỮ LIỆU (DATABASE CONCEPTS)
Dữ liệu là những sự kiện có thể ghi lại được và có ý nghĩa.
Cơ sở dữ liệu (CSDL) là tập hợp các dữ liệu liên quan, được lưu trữ trên máy tính, cho phép nhiều người sử dụng và được tổ chức theo một mô hình cụ thể.
Cơ sở dữ liệu (CSDL) phản ánh một khía cạnh của thế giới thực, nơi thông tin được tổ chức và lưu trữ Những dữ liệu này tạo nên một không gian CSDL, hay còn gọi là "thế giới nhỏ" (miniworld), cho phép người dùng dễ dàng truy cập và quản lý thông tin.
Cơ sở dữ liệu (CSDL) là tập hợp dữ liệu được liên kết một cách logic và mang ý nghĩa nhất định, thường được thiết kế cho mục đích cụ thể Hệ quản trị cơ sở dữ liệu (DBMS) là tập hợp các chương trình hỗ trợ người dùng trong việc tạo, duy trì và khai thác CSDL Thuật ngữ chung để chỉ cả cơ sở dữ liệu và hệ quản trị cơ sở dữ liệu là hệ cơ sở dữ liệu.
Hệ quản trị cơ sở dữ liệu (DBMS) là phần mềm được thiết kế để quản lý và điều hành một cơ sở dữ liệu, giúp lưu trữ, sửa chữa, xóa và tìm kiếm thông tin hiệu quả Có nhiều loại hệ quản trị CSDL, từ phần mềm đơn giản trên máy tính cá nhân đến các hệ thống phức tạp chạy trên siêu máy tính.
Hầu hết các hệ quản trị cơ sở dữ liệu (CSDL) hiện nay đều sử dụng ngôn ngữ truy vấn có cấu trúc, được gọi là Structured Query Language (SQL) Một số hệ quản trị CSDL phổ biến bao gồm MySQL, Oracle, PostgreSQL, SQL Server và DB2 Những hệ thống này thường hoạt động hiệu quả trên nhiều hệ điều hành khác nhau như Linux, Unix và MacOS, ngoại trừ SQL Server của Microsoft, vốn chỉ tương thích với hệ điều hành Windows.
GIỚI THIỆU SQLITE
SQLite là một cơ sở dữ liệu mở, được tích hợp dưới dạng thư viện nhúng trong Android, hỗ trợ các tính năng quan hệ chuẩn như cú pháp, giao dịch và các câu lệnh SQLite được sử dụng phổ biến trong các ứng dụng di động trên Android và iOS, và cũng được Mozilla Firefox áp dụng để lưu trữ dữ liệu cấu hình.
Bộ thư viện tích hợp sẵn SQLite hỗ trợ lập trình viên trong việc lưu trữ và phục hồi dữ liệu một cách dễ dàng Mặc dù là phiên bản rút gọn, SQLite vẫn đáp ứng hầu hết các nhu cầu xử lý dữ liệu Tính linh hoạt của SQLite cho phép người dùng kiểm soát hiệu quả thông tin dữ liệu.
Sử dụng SQLite không yêu cầu về thiết lập bất cứ cơ sở dữ liệu hoặc đòi hỏi quyền admin.
SQLite hỗ trợ các kiểu dữ liệu : TEXT, INTEGER, REAL
Đường dẫn của cơ sở dữ liệu:
DATA/data//databases/FILENAME
Thể hiện dữ liệu ở dạng bảng quan hệ:
Cột: thể hiện trường dữ liệu (hoặcthuộc tính dữ liệu).
Dòng: một thể hiện dữ liệu. word app id frequency Locale _ID mapreduce userl 100 en_US 1 precompiler user14 200 fr_FR 2 applet user2 225 fr_CA 3 const userl 255 pt_BR 4
Mỗi ứng dụng trên hệ thống sẽ được cấp phát một thư mục riêng để lưu trữ cơ sở dữ liệu, và thư mục này chỉ có thể được truy cập bởi ứng dụng đó Để chia sẻ dữ liệu giữa các ứng dụng, chúng ta có thể sử dụng Content Provider.
XÂY DỰNG CƠ SỞ DỮ LIỆU VỚI SQLITE
3.1 Tạo Cơ sở dữ liệu
Tạo cơ sở dữ liệu thông qua lớp SQLiteOpenHelper.
SQLiteOpenHelper là một lớp ảo giúp tạo và quản lý cơ sở dữ liệu SQLite, do SQLite không hỗ trợ các phương thức khởi tạo cơ sở dữ liệu Để sử dụng SQLiteOpenHelper, bạn cần khai báo một lớp khác kế thừa từ lớp này.
SQLiteOpenHelper cung cấp các phương thức cần thiết để khởi tạo và nâng cấp cơ sở dữ liệu, đồng thời tạo đối tượng để thực hiện các thao tác truy cập cơ sở dữ liệu, bao gồm đọc và ghi dữ liệu.
SQLiteDatabase cung cấp phương thức insert(), update(), delete(), hoặc execSQL() cho phép thực hiện truy xuất dữ liệu.
Override phương thức onCreate() để tạo cơ sở dữ liệu
Override phương thức onUpgrade() để nâng cấp cơ sở dữ liệu.
Lớp SQLiteOpenHelper cung cấp 2 phương thức getReadableDatabase() và getWriteableDatabase() để trả về đối tượng SQLiteDatabase
Tạo một CSDL có tên: COUNTRY_DB
Tạo một Table có tên: COUNTRY
The COUNTRY table consists of three columns: _id, enName, and viName, where _id serves as the primary key with an auto-incrementing value The database is defined in the MySQLiteHelper class, with the database name set to "COUNTRY_DB" and the table named "COUNTRY." The columns are defined as COL_ID for "_id," COL_EN_NAME for "enName," and COL_VI_NAME for "viName." The SQL command to create the table is specified as "CREATE TABLE."
+ COL_ID + " integer primary key autoincrement, "
+ COL_EN_NAME + " text not null, "
+ COL_VI_NAME + " text not null);"; public MySQLiteHelper(Context context) { super(context, DB_NAME, null, 1);
Lưu ý: Hàm khởi tạo có các thông số sau:
DB_NAME: Tên của cơ sở dữ liệu.
CursorFactory cho phép mở rộng lớp cursor để kế thừa các phương thức và truy vấn Khi cần sử dụng lớp tùy chỉnh, ta có thể tạo một instance của CursorFactory để tham chiếu đến lớp đó thay vì sử dụng mặc định Nếu không cần sử dụng lớp tùy chỉnh, ta có thể để giá trị của CursorFactory là null.
Version: Version của cơ sở dữ liệu
Tiến hành tạo CSDL trong hàm onCreate():
@Override public void onCreate(SQLiteDatabase db) {
Log.d("SQLite", "On Create Database");
//Tạo Table với câu lệnh execSQL db.execSQL(CREATE_TABLE);
^Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
3.2 Mở Cơ sở dữ liệu
Dùng cú pháp getReadableDatabase() và getWriteableDatabase() để trả về đối tượng SQLiteDatabase cần sử dụng
SQLiteDatabase là đối tượng để truy cập cơ sở dữ liệu (Read và Write).
SQLiteDatabase cung cấp phương thức insert(), update(), delete(), hoặc execSQL() cho phép thực hiện truy xuất dữ liệu.
MySQLiteHelper myHelper = new MySQLiteHelper(context);
SQLiteDatabase database; try{ database = myHelper.getWritableDatabase();
}catch(SQLiteException ex){ database = myHelper.getReadableDatabase();
Nếu cơ sở dữ liệu đã tồn tại, lớp SQLiteOpenHelper sẽ không tạo mới mà chỉ mở kết nối đến cơ sở dữ liệu hiện có Để đóng cơ sở dữ liệu, bạn có thể sử dụng phương thức public void close() { myHelper.close(); }.
TRUY VẤN DỮ LIỆU
4.1.1 Truy vấn với câu lệnh SQL
Sử dụng phương thức rawQuery() của lớp SQLiteDatabase
Phương thức rawQuery() nhận vào một giá trị chuỗi là câu lệnh SQL dùng để truy vấn dữ liệu và trả ra một đối tượng Cursor.
String queryStr = “SELECT * FROM COUNTRY WHERE _id=? AND enName=?”; Cursor cursor = database.rawQuery(queryStr, new String[]{“1”,”Vietnam”});
Cú pháp truy xuất dữ liệu trong câu lệnh SQL:
1 Phát biểu truy vấn SQL có dạng:
SELECT {Tên trường cần truy vấn, * nếu lấy tất cảcác trường}
WHERE {Biểu thức điều kiện}
2 SELECT dùng để đọc thông tin từ cơ sở dữ liệu theo trường hợp quy định hay những biểu thức cho trường hợp đó.
3 FROM chỉ ra tên một bảng hay những bảng có liên quan cần truy vấn thông tin
4 WHERE để tạo nên điều kiện cần lọcmẩu tin theo tiêu chuẩn được định nghĩa Thông thường, WHERE dùng cột (trường) để so sánh với giá trị cột khác, hay biểu thức chứa cột (trường) bất kỳ có trong bảng (table)
- Các phép toán so sánh trong câu lệnh SQL:
> Lớn WHERE _id>10; < : nhỏ hơn WHERE _id= Lớn hơn hoặc bằng WHERE _id>;
CHẾ ĐỘ ĐIỀU HƯỚNG
- NavigationMode: thực hiện khai báo chế độ điều hướng thông qua phương thức setNavigationMode.
- NavigationMode cho phép hiển thị dữ liệu màn hình ở hai chế độ: o Tab:
■ Dữ liệu màn hình bao gồm nhiều trang, mỗi trang được điều hướng hiển thị theo tab của ActionBar.
■ Khai báo: actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Gọi phương thức newTab(): đối tượng trả về - Tab
Thiết lập bộ lắng nghe - setTabListener
Tiêu đề cho từng Tab - setText
Gắn Tab vào ActionBar thông qua phương thức addTab, tham số truyền vào là một đối tượng Tab.
Ví dụ khai báo sử dụng:
Tab tab = actionBar.newTab() setText(R.string.artist) setTabListener(new TabListener(this, "artist",
ArtistFragment.class)); actionBar.addTab(tab); tab = actionBar.newTab()
.setTabListener(new TabListener(this, "album",
AlbumFragment.class)); actionBar.addTab(tab); o List:
■ Dữ liệu màn hình có thể bao gồm nhiều trang hoặc chế độ hiển thị, mỗi chế độ được chọn lựa từ Spinner thiết lập trên ActionBar.
■ Khai báo: actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
Khai báo bộ lắng nghe sự kiện trên List - OnNavigationListener
Gọi phương thức setListNavigationCallbacks, tham số truyền vào là một adapter và bộ lắng nghe sự kiện
Ví dụ khai báo sử dụng :
SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource (this, R.array.action_list, android.R.layout.simple_spinner_dropdown_item);
// Thiết lập Adapter và lắng nghe sự kiện actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
TOOLBAR
Từ phiên bản API 21 (Android 5.0 Lollipop), Android đã giới thiệu Toolbar như một sự thay thế cho ActionBar Toolbar không chỉ là một phiên bản cải tiến của ActionBar mà còn được kế thừa từ ViewGroup, cho phép sử dụng nhiều thuộc tính và phương thức của ActionBar như thêm logo, nhãn và các mục điều hướng Ngoài ra, Toolbar còn cung cấp các phương thức mới để thay đổi màu sắc, tùy chỉnh kích thước và thiết lập vị trí hiển thị trên giao diện Để hiển thị Toolbar cho một Activity cụ thể, bạn có thể sử dụng phương thức tương ứng.
Toolbar cùng lúc có thể chứa các yếu tố sau:
- A Navigation Button Nó có thể là Up arrow, navigation menu toggle, close, collapse, done hay một số hình ảnh mà bạn tự thiết kế.
- A branded logo image Có thể thiết lập chiều cao cho logo, thiết lập khoảng cách tùy ý
- A title and subtitle Thiết lập tiêu đề cho Toolbar, nhưng có thể nó sẽ bị che lấp khi ta thiết lập logo quá lớn.
Chúng ta có thể thiết lập một hoặc nhiều View tùy chỉnh để điều chỉnh vị trí hiển thị Để thực hiện điều này, cần thông qua lớp tương ứng.
Để canh giữa các đối tượng trong Toolbar, chúng ta sử dụng biến cờ CENTER_HORIZONTAL thông qua Gravity, giúp các View được căn giữa trong không gian trống còn lại Nếu đã thiết lập logo cho Toolbar, các đối tượng View được thêm vào sẽ tự động nằm ở vị trí trống còn lại và được canh giữa theo chiều ngang.
- An action menu Cũng giống như thanh ActionBar, “menu” sẽ mằm ở vị trí cuối của Toolbar.
Chúng ta cần xóa ActionBar cũ ra khỏi theme Mở thư mục res -> value -> styes.xml và viết lại như bên dưới Chúng ta chọn theme
Theme.AppCompat.Light.NoActionBar để không hiển thị ActionBar.
To enhance the interface with a Toolbar, it's essential to add it only when necessary As a ViewGroup, the Toolbar can be integrated into various ViewGroups, allowing for the configuration of attributes such as ID, color, width, and height Additionally, margins can be adjusted using contentInsetEnd and contentInsetStart for the left and right sides.
Bắt lại sự kiện khi người dùng tương tác lên các item của menu. toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
^Override public boolean onMenuItemClick(MenuItem menuItem) { switch (menuItem.getItemId()){ case R.id.action_share:
Toast.makeText(MainActivity.this, "Share", Toast.LENGTH_SHORT).show(); return true;
To set an icon in a toolbar, use the method "setNavigationIcon()" To handle click events on the icon, implement the "setNavigationOnClickListener()" method For example, you can set the navigation icon with the code: `toolbar.setNavigationIcon(R.drawable.ic_launcher);` and define the click listener using `toolbar.setNavigationOnClickListener(new View.OnClickListener() { });`.
^Override public void onClick(View view) {
Toast.makeText(MainActivity.this,"Navigation",Toast.LENGTH_SHORT) show();
Bài tập của học viên
1 Trình bày các dạng Menu
4 Trình bày các bước tạo Menu, Action Bar và ToolBar
5 Thực Hành Xây Dựng ActionBar Cho TourNote
6 Bài tập thực hành Menu trong android
7 Thiết kế hiển thị Spinner trên toolbar gồm các yêu cầu như sau:
Tạo một layour toolbar chứa spinner
Tạo layout cho mỗi item của spinner
1 Trình bày các dạng Menu, tham khảo mục 1 của Bài 3 trong giáo trình
2 Trình bày ACTION BAR, tham khảo mục 2 của Bài 3 trong giáo trình
3 Trình bày TOOLBAR, tham khảo mục 4 của Bài 3 trong giáo trình
4 Trình bày các bước tạo Menu, Action Bar và ToolBar, tham khảo mục 3.4 của Bài
5 Thực Hành Xây Dựng ActionBar Cho TourNote
Chúng ta sẽ áp dụng lý thuyết hôm nay để xây dựng ActionBar cho ứng dụng TourNote Để hình dung rõ hơn về công việc, hãy xem lại màn hình chính của TourNote Như đã đề cập, mỗi màn hình có thể có ActionBar riêng, nhưng hôm nay chúng ta chỉ tập trung vào việc xây dựng ActionBar cho màn hình chính.
ActionBar của TourNote sẽ bao gồm một nút tìm kiếm luôn hiển thị bên ngoài màn hình chính, cùng với hai nút “Về Ứng Dụng” và “Giúp Đỡ” được thu gọn trong menu mở rộng Các tab như “Ăn Uống” và “Tham Quan” sẽ được thêm vào sau này và do người dùng quản lý Trước khi xây dựng ActionBar, cần chuẩn bị đầy đủ các tài nguyên cho ứng dụng, trong trường hợp này chỉ cần một biểu tượng kính lúp.
Nếu bạn quen thuộc với công cụ Android Asset Studio, hãy truy cập vào đó và tìm Clipart với hình kính lúp Sau đó, chọn Theme là Dark để có biểu tượng màu trắng, rồi tải về Vậy là xong.
To find the search icon for the ActionBar, you can either search for it manually or conveniently download the zip file linked here The images within this file are named ic_action_search.png and have been pre-downloaded from Android Asset.
Studio cho bạn rồi Bạn hãy tự giải nén rồi để các ảnh vừa down vào các alternative resource tương ứng nhé
Hình 3.11 Để icon search của ActionBar vào các thư mục res
Thêm một dòng vào resource string để tạo nhãn cho nút tìm kiếm của bạn Bạn có thể tự thêm vào hoặc tham khảo trên GitHub qua liên kết dưới đây bài học hôm nay.
Để thêm chức năng tìm kiếm văn bản cho biểu tượng ActionBar, trước tiên bạn cần tạo thư mục menu/ trong thư mục res/ Việc tạo thư mục resource đã được thực hiện khi bạn tạo thư mục res/values-vi/.
Sau khi tạo xong res/menu/ , bạn hãy tạo trong đó một Menu resource file có tên main_actions.xml
Khi file main_actions.xml được tạo, Android Studio sẽ hiển thị resource này dưới dạng menu để bạn chỉnh sửa Bạn có thể tự học cách sử dụng giao diện để tạo và chỉnh sửa các menu item Tuy nhiên, hiện tại, mình khuyên bạn nên chọn tab Text trong editor để chuyển sang màn hình code bằng XML.
Hình 3.13 Thêm item cho ActionBar
Bạn hãy khai báo các item cho menu của ActionBar như sau.
Thao Tác Với Các Button Của ActionBar
Trong bài học này, chúng ta sẽ sử dụng file main_actions.xml làm menu chính cho ActionBar của màn hình chính Để thực hiện điều này, bạn cần truy cập vào lớp MainActivity.java và thêm mã vào phương thức onCreateOptionMenu() như sau: public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_actions, menu); return super.onCreateOptionsMenu(menu);
Cuối cùng, đoạn mã thực hiện phản hồi khi nhấn vào các nút của ActionBar thông qua phương thức onOptionsItemSelected() Hiện tại, chúng ta chưa xử lý các sự kiện nhấn này mà chỉ hiển thị thông báo tạm thời bằng Toast.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main_actions, menu); return super.onCreateOptionsMenu(menu);
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.search:
Toast.makeText(this, "Search button selected", Toast.LENGTH_SHORT).show(); return true; case R.id.about:
Toast.makeText(this, "About button selected", Toast.LENGTH_SHORT).show(); return true; case R.id.help:
Toast.makeText(this, "Help button selected", Toast.LENGTH_SHORT).show(); return true;
} Và đây là thành quả khi khởi chạy TourNote
Hình 3.14 Kết quả ActionBar của TourNote
ACTION PRO VIDER, ĐIỀU KHIẺN TÌM KIẾM VÀ CÁC CHUYỂN HOẠT
ACTION PROVIDER
ActionProvider (API Level 14) là một loại menu tích hợp giúp người dùng thực hiện các thao tác nhanh chóng trên ActionBar Bài viết này sẽ tập trung vào ShareActionProvider, một menu chia sẻ tiện lợi cho phép người dùng dễ dàng chia sẻ nội dung.
- ShareActionProvider có từ API level 14.
Hình 4.1 Chia sẻ hình với ShareActionProvider.
- Để tạo ra một ShareActionProvider chúng ta chỉ việc khai báo thuộc tính android:actionProviderClass trong cặp thẻ của file tài nguyên menu.
- Xử lý sự kiện với ShareActionProvider: private ShareActionProvider mShareActionProvider;
@Override public boolean onCreateOptionsMenu(Menu menu) {
// Inflate menu resource file getMenuInflater().inflate(R.menu.share_menu, menu);
// Locate MenuItem with ShareActionProvider MenuItem item = menu.findItem(R.id.menu_item_share);
// Fetch and store ShareActionProvider mShareActionProvider (ShareActionProvider)item.getActionProvider();
// Return true to display menu return true;
// Call to update the share intent private void setShareIntent(Intent shareIntent) { if (mShareActionProvider != null) { mShareActionProvider.setShareIntent(shareIntent);
ĐIỀU KHIỂN TÌM KIẾM
- ActionView là dạng điều khiển hiển thị trên ActionBar cho phép thực hiện các chuỗi thao tác trên cùng một điều khiển để thay đổi dữ liệu.
- Khai báo sử dụng thông qua hai thuộc tính: actionLayout actionViewClass
Trong ứng dụng, khi làm việc với khối dữ liệu lớn, người dùng thường gặp khó khăn và mất thời gian trong việc tìm kiếm tập tin Để giải quyết vấn đề này, bài viết này sẽ hướng dẫn tích hợp điều khiển tìm kiếm SearchView vào ActionBar, giúp người dùng truy xuất thông tin nhanh chóng và hiệu quả hơn.
Ví dụ sau đây sẽ hướng dẫn chi tiết vềứng dụng của điều khiển tìm kiếm này.
- Thực hiện kéo ListView vào tập tin activity main.xml:
The RelativeLayout in Android, defined by the XML namespace, is a versatile layout that allows for dynamic positioning of child views relative to each other and the parent container With attributes set for width and height to match the parent, it ensures a responsive design that adapts to various screen sizes This layout is commonly used in the MainActivity of Android applications to create intuitive user interfaces.
- Sau đó trong thư mục res/menu tạo tập tin search_view.xml thực hiện khai báo như sau:
In Java code, you can reference and utilize the AnimationDrawable object from a View displaying a Drawable by using the getBackgroundResource() method To initiate the animation, simply call the start() method on the AnimationDrawable object.
Ví dụ tham chiếu AnimationDrawable:
ImageView planeView = (Imageview) findViewByld(R.id.plane); planeView.setBackgroundResource(R.drawable.exam_drawable_anim);
(AnimationDrawable)planeView.getBackground(); plane.start();
Bài tập của học viên
1 Trình bày được action provider trong Android
2 Xác định chính xác điều khiển tìm kiếm
5 Dùng Drawable Animation thiết kế giao diện sau
6 Thiết kế các Action Provider đề cập đến các vấn đề sau:
1 Trình bày được action provider trong Android
2 Xác định chính xác điều khiển tìm kiếm.
4 Trình bày View Animation, tham khảo ở mục 4 ở bài 4 trong giáo trình
5 Dùng Drawable Animation thiết kế giao diện
Bitmap drawable là một loại bitmap cho phép bạn thiết lập nhiều thuộc tính như giá trị alpha và kích thước trước khi vẽ Để sử dụng BitmapDrawable, bạn có thể làm theo các bước hướng dẫn cụ thể.
Thêm hình ảnh vào thư mục drawable
Sau đó sử dụng @drawable/drawable_name để gán drawable cho view
//set bitmapdrawable left for textview
BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
BitmapFactory.decodeResource(getResources(), R.drawable.facebook));
((TextView)findViewById(R.id.tv_title)).setCompoundDrawablesWithIntrinsicBound s(bitmapDrawable, nu
ShapeDrawable cho phép vẽ các hình học cơ bản trong android
Chuột phải vào thư mục drawable để tạo drawable resource
Nhập tên drawable để hoàn thành
Tôi tạo file có tên là circle_drawable với nội dung file như dưới đây.
Và sử dụng trong xml
Bây giờ tôi tạo một tiếp drawable có hình dạng như một row chat của messenger facebook như sau: facebook_chat_drawable.xml
Set Drawable là background cho TextView
The XML layout for a TextView in an Android application includes a margin of 20dp and an ID of "tv_message_chat." It displays the text "This is message" in white color, set against a background defined by the drawable resource "facebook_drawable_chat." The TextView's width and height are set to wrap the content, ensuring it adjusts to the text size.
Trong java bạn có thể làm như sau: findViewById(R.id.tv_message_chat).setBackgroundResource(R.drawable.facebook_ drawable_chat);
Thử sửa lại một số thông tin trong file facebook_chat_drawable.xml runvà chạy xem lại kết quả
Drawable trong Android mang lại sức mạnh lớn để làm cho giao diện người dùng trở nên hấp dẫn hơn Hãy cùng khám phá thêm về các loại drawable khác để hiểu rõ hơn về khả năng của chúng trong việc cải thiện trải nghiệm người dùng.
StateListDrawable is a drawable that represents various states of a view, such as normal, focused, pressed, and disabled It is commonly used to visually depict these states, particularly for buttons and items in ListView or RecyclerView.
Hình ảnh dưới đây thể hiện các trạng thái của Button Để tạo StateListDrawable, quy trình tương tự như ShapeDrawable Tôi đã tạo một drawable trong thư mục drawable với tên button_selector.xml, có nội dung như sau:
Sử dụng drawable cho button
Các bạn hãy làm thử và xem kết quả.
Bây tôi muốn làm một button như dưới đây:
Tôi sẽ có các file như sau: button_state_normal.xml định nghĩa trạng trái normal của button
button_state_pressed.xml định nghĩa trạng thái khi button được nhấn.
và file button_selector_save_change.xml định nghĩa selector của button gồm 2 state đó là normal và pressed
The button element in Android XML is designed to save changes, featuring a drawable selector for its background, white text color, and centered layout It is configured with a width of 200dp and a height that wraps its content, ensuring a user-friendly interface.
Sau khi chạy và kiểm tra chương trình, bạn sẽ thấy có sự khác biệt trong kết quả Trong Android, ngoài hai trạng thái normal và pressed, còn có nhiều trạng thái khác Hầu hết các view trong Android đều có thể sử dụng những trạng thái này Mặc dù StateListDrawable có nhiều loại, nhưng tôi chỉ giới thiệu một số trạng thái cơ bản.
VectorDrawable được giới thiệu ở Android 5.0 (API 21) VectorDrawable có nhiều lợi thế đó là kích thước của file nhỏ (so với việc chúng ta copy 1 hình ảnh vào project)
Tự động scale theo tỉ lệ màn hình trêntừng thiết bị.
Trước tiên cần enable supportVecDrawable trong file build.gradle như sau: apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.0" defaultConfig { applicationId "com.example.nguyennghia.vectordrawable" minSdkVersion 15 targetSdkVersion 24 versionCode 1 versionName "1.0"
// enable for using vector drawables vectorDrawables.useSupportLibrary = true
} buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard- rules.pro'
} dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:24.0.0' compile 'com.android.support:design:24.0.0'
} Tiếp theo để tạo VectorDrawable chúng ta right click vào thư mục drawable > New -> chọn Vector Asset
To export an icon as a vector drawable in Android Studio, open the Vector Asset Studio and click on "Choose" to select your desired icon Then, click "OK" to allow Android Studio to generate the drawable file for you.
File vector được generate có nội dung như sau:
Để gán vector drawale cho View trong xml chúng ta sử dụng thuộc tính srcCompat.
Các bạn làm lại và chạy thử để xem kết quả.
Trong bài viết này, tôi đã giới thiệu về các Drawable có sẵn trong Android SDK Tiếp theo, tôi sẽ hướng dẫn các bạn cách tạo Drawable tùy chỉnh, giúp bạn hiểu rõ hơn về tính năng Drawable trong Android.
I created a class called ArcDrawable that extends the Drawable class In the constructor, I initialize a Paint object with anti-aliasing enabled, set its color, style to STROKE, stroke cap to ROUND, and a stroke width of 10 Additionally, I define a RectF object to represent the bounds for drawing the arc.
In the overridden `draw` method, a `RectF` object is initialized to define the bounds for drawing an arc on the canvas The left and top edges of the rectangle are adjusted by adding half of the paint's stroke width, while the right and bottom edges are reduced by the stroke width and an additional 2 pixels Finally, the canvas draws an arc within these defined bounds, starting at an angle of 45 degrees and spanning 270 degrees, using the specified paint attributes.
@Override public void setAlpha(int alpha) { if (mPaint != null) mPaint.setAlpha(alpha);
@Override public void setColorFilter(ColorFilter cf) { mPaint.setColorFilter(cf);
@Override public int getOpacity() { return PixelFormat.TRANSLUCENT;
} Và sử dụng Drawable này như sau:
ImageView imvAvatar = (ImageView)findViewById(R.id.imv_avatar);
ArcDrawable arcDrawable = new ArcDrawable(Color.parseColor("#16a085")); imvAvatar.setImageDrawable(arcDrawable);
Kết quả ta thấy như sau:
Và dưới đây là hình ảnh của drawale đã sử dụng trong bài viết từ đầu tới cuối
Những trọng tâm cần chú ý:
- Trình bày được action provider trong Android
- Xác định chính xác điều khiển tìm kiếm.
- Dùng Drawable Animation thiết kế giao diện sau
- Thực hiện đúng các thao tác Thiết kế các Action Provider
Bài mở rộng và nâng cao
Tạo và kích hoạt nút "Chia sẻ" trong ứng dụng Androidnhư hình sau
Yêu cầu đánh giá kết quả học tập
Trình bày được action provider trong Android
Xác định chính xác điều khiển tìm kiếm
Thực hiện Drawable Animation thiết kế giao diện
Thực hiện đúng các thao tác khai thác Thiết kế các Action Provider
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
Về kiến thức: Đánh giá bằng hình thức kiểm tra viết, trắc nghiệm, vấn đáp.
Về kỹ năng: Đánh giá kỹ năng thực các thao tác hực hiện Drawable Animation thiết kế giao diện và Thiết kế các Action Provider
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
ASYNCTASK - THREAD - HANDLER
THREAD VÀ MULTITHREADING
Trong lập trình ứng dụng di động, việc giải quyết vấn đề tài nguyên hạn hẹp của thiết bị là rất quan trọng Mặc dù các thiết bị di động đã được nâng cấp về CPU, GPU và RAM, nhưng vẫn không thể chạy ứng dụng như trên PC hay laptop Do đó, cần tinh giản các thuật toán và thực hiện chúng một cách nhanh chóng để tiết kiệm chi phí tài nguyên.
Thread là đơn vị nhỏ nhất của tiến trình, được quản lý bởi hệ điều hành và nằm trong các tiến trình thực thi của máy tính Mỗi thread có một callstack riêng, chứa các phương thức, đối số và biến cục bộ của nó.
Android hoạt động trên nền tảng hệ điều hành Linux, với các ứng dụng được phát triển bằng ngôn ngữ Java và chạy trên máy ảo Dalvik (Dalvik Virtual Machine) thay vì Java Virtual Machine (JVM) Mỗi máy ảo Android khởi động với ít nhất một thread chính và có khả năng tạo thêm nhiều thread phụ để quản lý các tiến trình Các thread trong cùng một máy ảo tương tác và đồng bộ hóa thông qua các đối tượng chia sẻ và các monitor liên quan.
Mỗi Thread trong lập trình được gán một độ ưu tiên từ 1 đến 10, giúp xác định thời gian CPU mà nó có thể sử dụng Độ ưu tiên này được thiết lập thông qua phương thức setPriority(int).
- Các phương thức của Thread như sleep(), wait() , notify() và notifyAll().
- Đểtạo ra một thread khác ngoài thread chính trên, chúng ta có 2 cách:
■ Tạo 1 lớp mới kế thừa từ lớp java.lang.Thread và ghi đè lại phương thức run() của lớp này: public class MyThread extends Thread{
■ Tạo 1 lớp và cho lớp này implement Interface Runnable: public class MyRunnable implements Runnable{
Multithreading, hay còn gọi là đa luồng, cho phép các ứng dụng thực thi nhiều dòng lệnh đồng thời Điều này có nghĩa là bạn có thể thực hiện nhiều công việc cùng lúc trong một ứng dụng Hiểu đơn giản, trong khi hệ điều hành với cơ chế đa nhiệm cho phép nhiều ứng dụng chạy song song, thì ứng dụng với cơ chế đa luồng cho phép thực hiện nhiều tác vụ đồng thời.
- Ưu điểm của việc sử dụng Multithreading:
Các thread chia sẻ tài nguyên của tiến trình nhưng vẫn có khả năng thực thi độc lập Sử dụng multi-threading sẽ mang lại lợi ích lớn trong lập trình đa nhiệm.
Các ứng dụng Multi-thread chạy nhanh hơn trên các máy tính hỗ trợ xử lý đa luồng.
Khó khăn trong việc lập trình, việc sử dụng multithreading không hề dễ dàng, đòi hỏi lập trình viên có kinh nghiệm.
Khó khăn trong việc quản lí.
Có khả năng tiềm tàng xảy ra tình trang deadlock
1.3 Main Thread và UI Thread, Worker Thread
Trong Android, khi chương trình được khởi chạy, hệ thống sẽ start một Thread ban đầu cùng với một Process Thì Thread đó chính là Main Thread
Vậy vì sao Main Thread lại thường được gọi là UI Thread thì có 2 lý do chính đáng sau đây.
Thread này có nhiệm vụ gửi các sự kiện đến widget, tức là đến các view ở giao diện điện thoại, thậm chí cả các sự kiện vẽ
Ngoài ra Thread này cũng phải tương tác với bộ công cụ Android UI (Android UI toolkit) gồm hai gói thư viện là android.widget và android.view
Trong một số trường hợp, Main Thread không được gọi là UI Thread khi một ứng dụng có nhiều hơn một Thread đảm nhiệm việc xử lý giao diện.
Worker Thread, hay còn gọi là Background Thread, là loại Thread mà bạn tạo ra để thực hiện các công việc không liên quan đến giao diện trong chương trình.
1.4 Hiện tượng ANR trong Android.
Có khi nào bạn dùng điện thoại Android mà thấy xuất hiện Dialog tương tựnhư hình sau đây không?
Khi có nhiều tác vụ chạy trên UI Thread, những công việc tốn thời gian như kết nối mạng hoặc truy vấn cơ sở dữ liệu có thể làm UI bị block, khiến người dùng cảm thấy ứng dụng bị treo Nếu tình trạng này kéo dài hơn 5 giây, hệ thống Android sẽ hiển thị hộp thoại cho phép người dùng đóng ứng dụng hoặc chờ đợi Để cải thiện trải nghiệm người dùng và tránh tình trạng này, Android đã đưa ra hai quy tắc mà lập trình viên cần tuân thủ.
Không được block UI Thread
Không được kết nối tới bộ công cụ Android UI (Android UI toolkit) từ một Thread không phải là UI Thread
Trong đoạn mã này, có một số vấn đề cần lưu ý khi sử dụng luồng (Thread) trong phương thức onClick Đầu tiên, việc tạo một luồng mới bên trong onClick có thể dẫn đến việc không đồng bộ hóa dữ liệu, gây ra lỗi trong giao diện người dùng Thứ hai, cần đảm bảo rằng mọi thay đổi đối với giao diện người dùng đều được thực hiện trên luồng chính để tránh tình trạng treo ứng dụng Cuối cùng, nên sử dụng các phương thức như AsyncTask hoặc Handler để quản lý luồng hiệu quả hơn.
Bitmap b loadImageFromNetwork("http://example.com/img.png"); mImageView.setImageBitmap(b);
Ta thấy việc kết nối internet để load hình ảnh được thực hiện một Thread khác (Worker Thread hay Background Thread) nên sẽ không block
UI đáp ứng quy tắc đầu tiên, nhưng trong Thread này, nó đã tác động trực tiếp đến UI thông qua câu lệnh mImageView.setImageBitmap(b), vi phạm quy tắc thứ hai, dẫn đến việc code không thể chạy Từ Worker Thread, việc cập nhật UI là không thể Do đó, Android đã cung cấp cho Worker Thread một số phương thức để thực hiện điều này.
Here is a rewritten paragraph based on the provided content:To demonstrate the functionality, we implement an `onClick` method that initiates a new thread This thread runs a `Runnable` which loads an image from the network using the URL "http://example.com/img.png" Once the image is successfully retrieved, it is posted to the `ImageView` to update the displayed bitmap.
Bây giờ, code đã có thể chạy được, nhưng ba phương thức trên chỉ phù hợp với một số bài toán cụ thể Nếu không có tham số là một View hoặc Activity để truyền vào, việc cập nhật UI sẽ không khả thi Đối với các bài toán với dữ liệu lớn, phương pháp này cũng không hiệu quả Giải pháp cho vấn đề này là sử dụng Handler hoặc AsyncTask.
ASYNCTASK
AsyncTask là một đối tượng cho phép thực hiện các tác vụ xử lý trong nền (background) mà không cần phải quản lý các luồng (Thread) hoặc trình xử lý (Handler) Nó giúp trả kết quả về cho giao diện người dùng (UI thread) một cách dễ dàng và hiệu quả.
Khi ứng dụng của bạn thực hiện tác vụ dài như gửi request lên server khi nhấn nút Login, người dùng có thể cảm thấy ứng dụng bị treo và chậm, ảnh hưởng đến trải nghiệm Để khắc phục tình trạng này, việc sử dụng AsyncTask là một giải pháp hiệu quả.
- Trong AsyncTask có 3 đối số là các Generic Type:
Params: Là giá trị (biến) được truyền vào khi gọi thực thi tiến trình và nó sẽ được truyền vào doInBackground
Progress: Là giá trị (biến) dùng để update giao diện diện lúc tiến trình thực thi, biến này sẽ được truyền vào hàm onProgressUpdate
Result: Là biến dùng để lưu trữ kết quả trả về sau khi tiến trình thực hiện xong.
■ Những đối số nào không sử dụng trong quá trình thực thi tiến trình thì ta thay bằng kiểu Void
- Thông thường trong một AsyncTask sẽ chứa 4 hàm, đó là :
onPreExecute(): Tự động được gọi đầu tiên khi tiến trình được kích hoạt.
Hàm doInBackground() được thực thi trong quá trình tiến trình chạy nền, cho phép gọi hàm onProgressUpdate để cập nhật giao diện thông qua lệnh publishProgress Trong quá trình này, việc cập nhật giao diện trực tiếp là không thể.
onProgressUpdate(): Dùng để cập nhật giao diện lúc runtime.
Hàm onPostExecute() tự động được gọi khi tiến trình hoàn thành, cho phép chúng ta truy cập kết quả trả về sau khi tiến trình kết thúc.
Hình 5.2 Thứ tự hoạt động của các hàm trong AsyncTask
Ví dụ: public class MainActivity extends Activity { long startMillis; Textview txtHello;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtHello = (TextView) findViewById(R.id.txtHello);
MyAsyncTask myAsyncTask new MyAsyncTask(); myAsyncTask.execute();
- Tạo lớp MyAsyncTask kế thừa từ lớp AsyncTask: private class MyAsyncTask extends AsyncTask{
@Override protected void onPreExecute() { super.onPreExecute(); startMillis = System.currentTimeMillis();
@Override protected void onProgressUpdate(Integer values) { super.onProgressUpdate(values);
Log.d("Test", "Công việc đang làm " + values[0]); }
@Override protected void onPostExecute(Void result) { super.onPostExecute(result);
Log.d("Test", "Thời gian kết thúc: "
+ (System.currentTimeMillis()-startMillis)/1000 + " g iâ y"); Log.d("Test", "Công việc hoàn thành.");
@Override protected Void doInBackground(String arg0) { Log.d("Test",
Đối tượng của AsyncTask chỉ được dùng trong UI thread (Thread chính của ứng dụng).
Các phương thúc onPostExecute, onPreExecute, onProgressUpdate chỉ là tùy chọn.
Bản chất Asynctask gồm có 4 bước:
Bước 1: onPreExecute() Được thực hiện trước khi bắt đầu thực hiện tác vụ Hàm được gọi trước phương thức doInBackground() và được gọi trên UI thread.
Thông thường, hàm này được dùng để hiển thị thanh progressbar thông báo cho người dùng biết tác vụ bắt đầu thực hiện
Tất cả mã cần thời gian thực hiện sẽ được đặt trong hàm này, vì nó hoạt động trên một thread riêng biệt với UI thread, do đó không được phép cập nhật giao diện ở đây Để cập nhật giao diện trong khi tác vụ đang diễn ra, như hiển thị trạng thái % file đã tải xuống, chúng ta cần sử dụng hàm onProgressUpdate() bên dưới.
Hàm này được gọi khi trong hàm doInBackground()gọi đến hàm publishProgress()
Hàm này được gọi khi doInBackground hàm thành công việc Kết quả của doInBackground() sẽ được trả cho hàm này để hiển thị lên giao diện người dùng.
Trong quá trình thực hiện tác vụ của AsyncTask, bạn có thể dễ dàng tạm dừng bất kỳ lúc nào mà không cần chờ AsyncTask hoàn thành Chỉ cần gọi hàm cancel(boolean) để dừng tác vụ.
Một số lưu ý về các sử dụng AsynctTask
Lớp AsyncTask phải được thực hiện trên UI Thread
Hàm execute(Params…) phải được gọi trên UI Thread
Không nên gọi onPreExecute (), onPostExecute(), doInBackground
(Params…),onProgressUpdate (Progress…) theo cách thủ công.
Task chỉ được thực thi một lần tại một thời điểm (Exception sẽ được throw nếu thực hiện lần thứ hai)
Kiến thức cơ bản về cách sử dụng AsyncTask trong Android đã được trình bày Khi bạn hiểu rõ bản chất của AsyncTask, việc áp dụng và điều chỉnh trong các tình huống cụ thể sẽ trở nên dễ dàng hơn.
Handler
3.1 Giới thiệu Đầu tiên, Handlers không phải là một khái niệm mới, chúng đã có từ rất lâu Cụ thểlà bao lâu? Theo mình được biết thì là từ thời API level 1 rồi Mặc dù vậy, mình vẫn luôn cảm thấy các bạn vẫn chưa thực sự khai thác triệt để, kể cả mình cũng vậy ^^
A Handler can be understood as a class that, when declared in an application, functions similarly to a "listener" for other controls on the screen The key difference is that while other controls listen for events like "onKey" and "onClick," Handlers specifically handle messages through the handleMessage method.
Handler trong android có một hạn chế là “sự không rõ ràng” Nó không phải là một Runnable, mà cũng không phải là Thread
Handler là một cơ chế cao cấp dùng để xử lý hàng đợi, cho phép quản lý các Messages và Runnables Việc xác định xem chúng nên được xử lý trên main thread hay background thread không ảnh hưởng đến chức năng chính của Handler.
Handler vẫn sẽ được tạo ra để xử lý đống Messages này, từng cái một Và đây chính là điều cần phải nhớ.
Một ví dụ điển hình về việc sử dụng Handler là khi bạn có một Runnable để xử lý tác vụ trên background thread trong Android Khi cần, bạn có thể cập nhật dữ liệu lên giao diện người dùng một cách hiệu quả.
Để cập nhật giá trị cho Handler, bạn cần sử dụng cú pháp `new Handler(Looper.getMainLooper())` Sau đó, hãy gọi `handler.post()` để thực hiện công việc của UI bên trong phương thức post() Thật tuyệt vời phải không?
Thread backgroundThread = new Thread(new Runnable() {
// pretend to do something "background-y" try {
@Override public void run() { tv04.setText("Hi from a Handler inside of a background Thread!"); }
Chúng ta đều biết rằng, một AsyncTask chỉ có thể được thực hiện một lần Điều này không xảy ra với Handlers.
Thậm chí có một lớp đặc biệt có thể xử lý một vài các Handlers cùng lúc đó là HandlerThread
HandlerThread có thể thay phiên xử lý cho cả Looper, một cách tự động Vì vậy bạn không cần phải lo lắng về điều này.
Handler là một đối tượng cho phép gửi và xử lý các thông điệp cùng các đối tượng Runnable liên quan đến hàng đợi thông điệp Mỗi Handler có khả năng liên kết với một thread và hàng đợi thông điệp của thread đó.
Bạn có thể tạo một thread riêng và giao tiếp với main thread của ứng dụng thông qua Handler Điều này được thực hiện bằng cách gọi sendMessage từ thread mới của bạn.
- Tạo một đối tượng Handler và ghi đè lại phương thức handleMessage để bắt và xử lý các thông điệp liên lạc.
Handler handler = new Handler(new Handler.Callback() {
^Override public boolean handleMessage(Message msg) { //Kiểm tra message if(msg != null){
//Xử lý message nhận được từ Thread } return true;
- Thread sẽ gửi tin nhắn lên Handler và Handler đóng vai trò kiểm tra tin nhắn là gì và làm những việc tương ứng.
- Ta chú ý các phương thức sendMessage sau:
sendMessage(): gửi tin nhắn lên Handler ngay lập tức.
sendMessageAtFrontOfQueue(): gửi tin nhắn lên Handler và tin nhắn đó sẽ ưu tiên giải quyết trước.
sendMessageAtTime(): gửi tin nhắn vào thời điểm chỉ định trước.
sendMessageDelayed(): gửi tin nhắn vào Handler sau một khoảng thời gian nhất định
Thread t1 = new Thread(new Runnable() {
Message mss = new Message(); mss.arg1 = 1; handler.sendMessage(mss);
Bài tập thực hành của sinh viên
1 Trình bày Thread trong android
3 Xây dựng giao diện với Main Thread và UI Thread, Worker Thread
4 Trình bày các bước ASYNCTASK
5 Trình bày Handler trong android
6 Sử dụng AsyncTask với nhiều giá trị truyến vào và trả về kết quả nhiều giá trị:
Trình bày Thread trong android, tham khảo mục 1.1 ở bài 5 của giáo trình
Trình bày Multithreading, tham khảo mục 1.2 ở bài 5 của giáo trình
Xây dựng giao diện với Main Thread và UI Thread, Worker Thread, tham khảo mục 1.4 ở bài 5 của giáo trình
Trình bày các bước ASYNCTASK, tham khảo mục 2 ở bài 5 của giáo trình
Trình bày Handler trong android, tham khảo mục 3 ở bài 5 của giáo trình
Sử dụng AsyncTask với nhiều giá trị truyến vào và trả về kết quả nhiều giá trị:
6.1.Đầu tiên tạo một class để lưu trữ các giá trị truyền vào như sau: private class MyParam {
Bitmap bm; int requestCode; public MyParam(Bitmap bm, int requestCode) { this.bm = bm; this.requestCode = requestCode;
Asynctask nhận vào 2 giá trị làbm kiểu Bitmap và RequestCode kiểu Int.
6.2 Tạo một Class dùng để nhận kết quả trả về như sau: private class Result
AsyncTask này sẽ trả về 2 kết quả là 1 Uri và 1 requestCode
6.3 Tạo Class AsynTask gọi hàm SaveImage và giá trị trả về là Uri kèm theo một requestCode để xử lý. private class SaveImageAsyncTask extends AsyncTask {
@Override protected Result doInBackground(MyParam myParams) {
//Lấy các Param đã truyền vào.
Bitmap bm = myParams[0].bm; int requestCode = myParams[0].requestCode;
Result result = new Result(); result.uri = presenter.saveImageCrop(bm); result.requestCode = requestCode; return result;
@Override protected void onPostExecute(Result result) { super.onPostExecute(result);
//Kết quả trả về được xử lý tại đây listUriImage.put(result.requestCode,result.uri);
6.4 Thực thi AsyncTask như sau:
Tạo mới đối tượng MyParam và tiến hành execute AsyncTask.
MyParam myParam = new MyParam(bm,requestCode);
SaveImageAsyncTask saveImageAsyncTask = new SaveImageAsyncTask(); saveImageAsyncTask.execute(myParam);
Note: Hàm Save Image cho bạn nào cần:
//Lưu image tạm thời public Uri saveImageCrop(Bitmap bm){
File root = new File(Environment.getExternalStorageDirectory() + File.separator + "androidcoban" + File.separator); root.mkdirs();
String.valueOf(random.nextInt(100)) + System.currentTimeMillis() + ".jpg"; File sdImageMainDirectory = new File(root, imageNameForSDCard); outputFileUri = Uri.fromFile(sdImageMainDirectory); fOut = new FileOutputStream(sdImageMainDirectory);
// Toast.makeText(activity, "Error occured Please try again later.", // Toast.LENGTH_SHORT).show();
} try { bm.compress(Bitmap.CompressFormat.PNG, 80, fOut); fOut.flush(); fOut.close();
Những trọng tâm cần chú ý:
Trình bày Thread trong android
Xây dựng giao diện với Main Thread và UI Thread, Worker Thread
Trình bày các bước ASYNCTASK
Trình bày Handler trong android
Sử dụng AsyncTask với nhiều giá trị truyến vào và trả về kết quả nhiều giá trị:
Thực hiện đúng các thao tác lập trình thiết kế, quản lý các thuộc tính của fragment
Bài mở rộng và nâng cao
Thực hện ANR với thao tác mạng trên Main Thread
Yêu cầu đánh giá kết quả học tập
Trình bày Thread trong android
Xây dựng giao diện với Main Thread và UI Thread, Worker Thread
Trình bày các bước ASYNCTASK
Trình bày Handler trong android Trình bày các thiết kế giao diện cho fragment
Thao tác Thiết kế giao diện cho Multithreading
Thực hiện đúng các thao tác Sử dụng AsyncTask với nhiều giá trị truyến vào và trả về kết quả nhiều giá trị:
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
Về kiến thức: Đánh giá bằng hình thức kiểm tra viết, trắc nghiệm, vấn đáp.
Về kỹ năng: Đánh giá kỹ năng thực hành lập trìnhthiết kế, quản lý các thuộc tính của fragment
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
SERVICE - BROADCAST RECEIVER VÀ NOTIFICATION
SERVICE
Dịch vụ được coi là một thành phần hoạt động ngầm, không cần giao diện tương tác trực tiếp với người dùng Ví dụ điển hình cho các tác vụ này bao gồm việc truy xuất và cập nhật dữ liệu, cũng như nhận và xử lý thông báo từ người dùng, thường tiêu tốn nhiều thời gian.
- Service giống như Activity thực hiện theo chu kỳ thời gian để quản lý sự thay đổi của trạng thái
- Trong AndroidManifest.xml cần phải khai báo:
trong cặp thẻ
- Service chạy trên Main Thread nên có thể gây cản trở các tác vụ khác
Dịch vụ "Started" được khởi động khi ứng dụng gọi phương thức startService() Dịch vụ này sẽ hoạt động liên tục cho đến khi hoàn thành nhiệm vụ cụ thể, chẳng hạn như tải xuống hoặc thực hiện tính toán Khi công việc hoàn tất, dịch vụ sẽ tự động dừng lại.
Dịch vụ “Bound” là dịch vụ được khởi tạo khi một thành phần của ứng dụng gọi phương thức bindService() Loại dịch vụ này cung cấp giao diện Client - Server, cho phép các thành phần của ứng dụng tương tác, gửi yêu cầu và nhận kết quả Khi tất cả các thành phần ngừng liên kết, dịch vụ sẽ tự động kết thúc.
Hình 6.1 Mô tả vòng đời của Service
Ví dụ sau sẽ tạo một service có chức năng tính toán và trả về kết quả của phương thức cộng 2 số nguyên
- Tạo một lớp có tên là MyService mở rộng từ lớp Service như sau: public class MyService extends Service {
// Binder cho cac client private final IBinder mBinder = new LocalBinder();
@Override public IBinder onBind(Intent intent) { return mBinder;
} public class LocalBinder extends Binder {
// Trả vềđối tượng MyService để cho client có thể gọi public method
MyService getService() { return MyService.this;
//Viết phương thức cho các client có thể gọi public int cong2So(int a, int b){ return a + b ; }
- Trong MainActivity khai báo biến, khởi tạo các đối tượng giao diện:
Hình 6.2 Màn hình ứng dụng gọi Service cộng 2 số. public class MainActivity extends Activity implements OnClickListener{
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtResult = (Textview) findViewByld(R.id.txtResult); btnCallService
= (Button) findViewById(R.id.btnCallService); btnCallService.setOnClickListener(this);
To create a specialized ServiceConnection object for managing the opening and closing of connections to a Service, override the onServiceDisconnected() and onServiceConnected() methods to establish a binding with MyService The implementation includes setting the mBound variable to false within the onServiceDisconnected() method to indicate that the connection has been severed.
@Override public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service; mService binder.getService(); mBound = true;
- Trong hàm OnStart(): chúng ta dùng phương thức bindService(parameter) để gọi đến MyService thông qua đối tượng Intent:
@Override protected void onStart() { super.onStart();
Intent i = new Intent(this, MyService.class); bindService(i, mConnection, Context.BIND_AUTO_CREATE);
- Trong hàm onStop(): Ngắt kết nối đến MyService protected void onStop() { super.onStop(); if(mBound){ mService.unbindService(mConnection); mBound = false ; }
In the onClick method of the button, we invoke the function cong2so(int, int) and display the returned result in a TextView The implementation begins with a switch statement that checks the button's ID, specifically for R.id.btnCallService, ensuring that the service is called only when mBound is true.
//Cho service cộng 2 số 5 5 int result = mService.cong2So(5, 5); txtResult.setText(String.valueOf(result));} break; default: break;
IntentService là một loại Service hoạt động độc lập với Main Thread, cho phép thực hiện các tác vụ nền mà không làm ảnh hưởng đến hiệu suất của Main Thread.
- Ví dụ: public class HelloIntentService extends IntentService{ public HelloIntentService() { super("HelloIntentService");
@Override protected void onHandleIntent(Intent intent) { long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime- System.currentTimeMillis());
BROADCAST RECEIVER
Broadcast Receiver là một thành phần quan trọng trong Android, có chức năng tiếp nhận và xử lý các Intent theo chỉ định của người dùng Nó cho phép mở ứng dụng để xử lý các Intent được gửi từ hệ thống, giúp cải thiện khả năng tương tác và phản hồi của ứng dụng.
Trong ứng dụng Android, việc nhận tín hiệu khi có sự kiện xảy ra trên thiết bị là rất quan trọng để cải thiện hiệu suất của ứng dụng Các sự kiện như pin sắp cạn, máy vừa khởi động hoặc ứng dụng mới được cài đặt có thể được xử lý hiệu quả thông qua Broadcast Receiver, giúp chúng ta nắm bắt và phản ứng kịp thời với những thay đổi này.
- Để tạo một BroadcastReceiver, ta sẽ tạo một lớp kế thừa từ lớp
BroadcastReceiver Ví dụ: public class ConnectivityChangeReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) { Toast.makeText(context, "Connectivity changed", Toast.LENGTH_SHORT).show();
- Để đăng ký đối tượng của Broadcast receiver, sử dụng 2 cách: o Đăng ký động với phương thức: Context.registerReceiver()
■ Broadcast Receiver có thể được đăng ký trong Activity ở hàm onResume() như sau:
@Override protected void onResume() { super.onResume(); mReceiver = new ConnectivityChangeReceiver(); registerReceiver(mReceiver,new
- Chúng ta cũng nên hủy đăng ký khi Activity trong hàm onPause():
@Override protected void onPause() { super.onPause(); unregisterReceiver(mReceiver);
- Lưu ý: nếu tắt ứng dụng BroadcastReceive sẽ không còn lắng nghe. o Đăng ký trong Manifest.xml thông qua cặp thẻ
Lưu ý: tự động lắng nghe kể cả khi đã đóng ứng dụng.
NOTIFICATION
Thông báo (Notification) là một thành phần quan trọng giúp gửi thông tin đến người dùng mà không làm gián đoạn quá trình sử dụng thiết bị Chẳng hạn, khi nhận được tin nhắn hoặc email, thiết bị sẽ sử dụng Notification để thông báo cho người dùng thông qua âm thanh, đèn nền và biểu tượng trên thanh tác vụ.
Hình 6.3 Các dạng thông báo với Notification
Thông thường, các ứng dụng sẽ tự động gửi thông báo tới người dùng khi hoàn thành một công việc nào đó Khi nhận được thông báo này, người dùng có thể kích chọn trực tiếp vào đó để khởi chạy lại ứng dụng đang ở trạng thái ngủ, giúp tiết kiệm thời gian và tăng cường trải nghiệm người dùng.
Ví dụ sau đây sẽ tạo một thông báo với âm thanh và rung thiết bị. public class MainActivity extends Activity {
^Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedlnstanceState); setContentView(R.layout.activity_main); final int NOTIF_ID = 1234; int icon = R.drawable.email; long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Builder(this);
Intent notificationIntent = new Intent(this,
PendingIntent intent = PendingIntent.getActivity(this, 0,notificationIntent, 0); buildersetSmallIcon(icon).setContentText("You have one unread message.").setWhen(when)
// Play default notification sound notification.defaults Notification.DEFAULT_SOUND;
// Vibrate notification.defaults = Notification.DEFAULT_VIBRATE; notificationManager.notify(NOTIF_ID, notification);
} o Xin quyền nếu muốn rung thiết bị:
Hình 6.4 Kết quả hiển thị Notification vừa tạo.
- Một số dạng hiển thị thông báo khác: o Dialog:
Dialog là một thành phần giao diện phổ biến trên phần mềm desktop, trang web và ứng dụng di động, thường được sử dụng để yêu cầu sự xác nhận từ người dùng hoặc hiển thị cảnh báo và lỗi khi thao tác với ứng dụng.
■ Có tất cả 3 kiểu hiển thị dialog:
1 Sử dụng trực tiếp lớp Dialog hoặc kế thừa: ngoài lớp AlertDialog để dùng chung Android còn xây dựng một số lớp khác để phục vụ cho từng mục đích riêng biệt Dialog là lớp được xây dựng và điều khiển hoàn toàn trong Activily nên ta sẽ không cần khai báo trong Manifest khi cần sử dụng.
2 Activity sử dụng giao diện Dialog - chúng ta có thể áp đặt giao diện Dialog cho các Activity thông thường để nó có thể hiện thị như một Dialog chuẩn.
3 Để tạo Dialog chỉ cần tạo mới thực thể thuộc lớp Dialog và thiết lập tiêu đề cũng như giao diện cho Dialog bằng 2 phương thức tương ứng setTitle và setContentView Sau khi thiết lập ta chỉ cần gọi phương thức show ở nơi mà chúng ta muốn hiện Dialog.
Dialog dialog = new Dialog(MainActivity.this); dialog.setTitle(“Demo Dialog”);
//Thiết lập giao diện cho Dialog bằng layout xml dialog.setContentView(R.layout_dialog_layout); dialog.show(); o Toast:
Toast là một thông báo ngắn gọn, hiển thị trong một khoảng thời gian nhất định và tự động biến mất Nó có thể được sử dụng để thông báo các thiết lập cấu hình hoặc chỉ để cung cấp thông tin tạm thời, chẳng hạn như kiểm tra một vấn đề nào đó.
Toast có thể được tạo và hiển thị trong Activity hoặc trong Servive.
Không cho phép người sử dụng tương tác
Khi hiển thị sau khoảng thời gian nào đó sẽ tự đóng lại.
Có hai giá trị mặc định mà bạn nên sử dụng khi hiển thị thông báo Toast: hằng số Toast.LENGTH_SHORT hiển thị trong 2 giây và Toast.LENGTH_LONG hiển thị trong 3.5 giây.
Hình dưới đây cho bạn biết một Toast đang hiển thị:
- Cú pháp để tạo một thông báo Toast:
Toast toast = Toast.makeText(YourActivity.this, “Hiển thị gì thì ghi ở đây”, Toast.LENGTH_SHORT); toast.show();
Bài tập thực hành của sinh viên
1 Trình bày gửi Broadcasts theo cách thông thường
2 Trình bày gửi Broadcasts theo thứ tự
3 Gửi Broadcast trong nội bộ ứng dụng
6 Hướng dẫn đăng kí để nhận thông báo từ Broadcast Receiver
7 Cách gửi Broadcast Event/Intent
8 Vấn đề bảo mật khi sử dụng Broadcast Receiver
1 Trình bày gửi Broadcasts theo cách thông thường
2 Trình bày gửi Broadcasts theo thứ tự
3 Gửi Broadcast trong nội bộ ứng dụng
6 Hướng dẫn đăng kí để nhận thông báo từ Broadcast Receiver
7 Cách gửi Broadcast Event/Intent
8 Vấn đề bảo mật khi sử dụng Broadcast Receiver
9 Sử dụng Un bounded Service dịch vụ chơi nhạc (Chạy ngầm):
Tạo mới một "Empty Activity" project với tên PlaySongService
Package name: org.o7planning.playsongservice
Hình 6.7 playsongservice Project đã được tạo ra.
Hình 6.8 Project playsongservice Chuẩn bị file nhạc mp3:
Nhấn phải chuột vào thư mục res chọn:
New > Folder > Raw Resources Folder
Hình 6.9 Raw Resources Folder Copy và Paste một file nhạc mp3 vào thư mục'raw' bạn vừa tạo ra.
Hình 6.10 Đưa file nhạc mp3 vào thư mục 'raw'
Hình 6.11 kết quả đưa file nhạc Thiết kế giao diện của ứng dụng:
Hình 6.12 giao diện của ứng dụng activity_main.xml
The provided XML code defines a `ConstraintLayout` for an Android application, setting its width and height to match the parent container It includes necessary XML namespaces for Android attributes, application-specific attributes, and tools, indicating that it is designed for the `MainActivity` context.
The provided XML code snippet defines a button in an Android layout, identified by the ID "button_play." This button is designed to have a width and height that wrap around its content, with a top margin of 28dp It features the text "Play" and is constrained to align with the parent's start and end edges, as well as its top edge, ensuring proper positioning within the layout.
To create a stop button in Android, use the Button widget with the id "button_stop" and set its layout width and height to "wrap_content" Add a margin top of 37dp to position the button below another element, in this case, "button_play" Set the text of the button to "Stop" and use the ConstraintLayout to center the button horizontally by setting the end and start constraints to the parent.
Nhấn phải chuột vào một java package, chọn:
Hình 6.13 Service Nhập vào tên lớp:
Bạn có thể nhìn thấy PlaySongService đã được khai báo với AndroidManifest.xml:
The PlaySongService.java file, located in the org.o7planning.playsongservice package, defines a service in Android that utilizes the MediaPlayer class to play audio This service extends the Android Service class and includes methods for binding and managing the media playback The constructor initializes the MediaPlayer instance, setting the foundation for audio playback functionality within the application.
// Return the communication channel to the service
@Override public IBinder onBind(Intent intent){
// So this method is never called return null;
@Override public void onCreate(){ super.onCreate();
// Create MediaPlayer object, to play your song mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.mysong); }
@Override public int onStartCommand(Intent intent, int flags, int startId){
// Play song mediaPlayer.start(); return START_STICKY;
// Release the resources mediaPlayer.release(); super.onDestroy();
The MainActivity.java file is part of the org.o7planning.playsongservice package and extends AppCompatActivity It imports essential Android libraries, including Bundle, Intent, View, and Button Within the MainActivity class, two buttons are declared: buttonPlay and buttonStop, which are intended to control song playback in the application.
In the `onCreate` method of the activity, the layout is set using `setContentView`, and two buttons, `buttonPlay` and `buttonStop`, are initialized by finding their respective views A click listener is added to the `buttonPlay`, which triggers the `playSong` method when the button is pressed.
}); this.buttonStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopSong();
// This method is called when users click on the Play button public void playSong() {
// Create Intent object for PlaySongService
Intent myIntent = new Intent(MainActivity.this, PlaySongService.class);
// Call startService with Intent parameter this.startService(myIntent);
// This method is called when users click on the Stop button public void stopSong( ) {
Intent myIntent = new Intent(MainActivity.this, PlaySongService.class); this.stopService(myIntent);
} OK bây giờ bạn có thể chạy ứng dụng của mình và thưởng thức bài hát.
Dịch vụ bị giàng buộc (Bounded Service) được mô phỏng qua ứng dụng cung cấp thông tin thời tiết hiện tại, nơi người dùng nhập vị trí địa lý như Hà Nội, Chicago, và nhận được kết quả về tình trạng thời tiết như mưa hay nắng.
Tạo một project có tên WeatherService
Package name: org.o7planning.weatherservice
Hình 6.17 tên WeatherService Thiết kế giao diện cho ứng dụng:
Hình 6.18 giao diện WeatherService activity_main.xml
KHAI THÁC TÀI NGUYÊN INTERNET VÀ GIAO THỨC KẾT NỐI
TỔNG QUAN TÀI NGUYÊN INTERNET
1.1 Tài nguyên Internet trên thiết bị di động Ứng dụng trực tuyến trên thiết bị di động được xây dựng nhằm mục đích hiển thị dữ liệu đầu cuối được xử lý từ các máy chủ cũng như gửi các yêu cầu về truy xuất dữ liệu Ví dụ: ứng dụng Goole Play Store được Google cài đặt trên thiết bị người dùng, hiển thị các ứng dụng được phát triển bởi các lập trình viên, cho phép người dùng có thể tải và cài đặt các ứng dụng đó ngay trên thiết bị của họ
Khi xây dựng các ứng dụng trực tuyến cần xác định rõ nguồn tài nguyên được cung cấp:
- Định dạng tài nguyên (văn bản, hình ảnh.).
- Giao thức kết nối đến máy chủ (http, https, tcp, rtsp.).
- Sử dụng công nghệ kết nối không dây (Wifi, Internet Mobile.).
Các tài nguyên sau khi truy xuất sẽ dựa trên loại tài nguyên và sử dụng các API tương ứng để chuyển đổi thành dữ liệu rõ ràng cho người dùng Android cung cấp đầy đủ các phương thức thư viện, giúp lập trình viên làm việc với hầu hết các loại dữ liệu phổ biến Ví dụ, WebView và các phương thức liên quan có thể được sử dụng để hiển thị thông tin từ một trang web ngay trên màn hình ứng dụng.
1.2 Các vấn đề khi kết nối Internet
Một trong những câu hỏi quan trọng là liệu có nên phát triển ứng dụng di động hoàn chỉnh (Native App) hay chỉ cần xây dựng trang web với giao diện dành cho thiết bị di động (Web App) Người dùng có thể truy cập trang web qua trình duyệt trên thiết bị của họ (ví dụ: http://m.t3h.vn) Việc phát triển Web App giúp lập trình viên tiết kiệm thời gian xây dựng ứng dụng cho từng hệ điều hành, nhưng vẫn không thể tránh khỏi những hạn chế mà chỉ có ứng dụng mới có thể khắc phục.
Vấn đề băng thông khi sử dụng trình duyệt để truy cập ứng dụng web là một thách thức lớn, vì hầu hết các tài nguyên như hình ảnh, giao diện và âm thanh đều phải tải lại từ đầu, dẫn đến việc tiêu tốn một lượng băng thông lớn Để khắc phục tình trạng này, việc xây dựng ứng dụng cho phép lưu trữ và truy xuất dữ liệu tĩnh một cách hiệu quả sẽ giúp giảm thiểu việc sử dụng băng thông.
Lưu cache là quá trình mà các trình duyệt chỉ có thể giữ lại một lượng thông tin hạn chế về trang web, trong khi ứng dụng có khả năng lưu trữ bất kỳ dữ liệu nào mà lập trình viên mong muốn, từ dữ liệu truy xuất đến thao tác của người dùng Khi xảy ra sự cố về kết nối, ứng dụng sẽ ghi lại thông tin tại thời điểm mất kết nối và tự động xử lý khi thiết bị khôi phục kết nối.
Năng lượng tiêu thụ từ các kết nối Internet là rất lớn, nhưng việc phát triển ứng dụng giúp chúng ta quản lý và duy trì các kết nối một cách hiệu quả khi cần thiết.
Các ứng dụng nền web thường gặp khó khăn trong việc truy xuất phần cứng và các đặc tính quan trọng của thiết bị di động như định vị, máy ảnh và cảm biến Tuy nhiên, khi phát triển ứng dụng, chúng ta có thể dễ dàng truy cập các đặc tính này thông qua các API được cung cấp bởi bộ SDK.
1.3 Các hình thức kết nối Internet
Các thiết bị di động ở thời điểm hiện tại hỗ trợ khá nhiều hình thức kết nối đến Internet, tuy nhiên ta có thể quy chung về dạng sau:
Internet di động là một loại kết nối được cung cấp qua dịch vụ băng thông của nhà mạng, với một số chuẩn phổ biến như GPRS, EDGE, 3G, 4G và LTE.
Wifi là công nghệ kết nối không dây cho phép truyền dữ liệu ra Internet thông qua các thiết bị mạng như router và switch Ngoài ra, các thiết bị di động Android cũng có khả năng phát tín hiệu mạng cho các thiết bị khác, tạo điều kiện thuận lợi cho việc kết nối và chia sẻ dữ liệu.
Việc xây dựng ứng dụng kết nối Internet phụ thuộc vào hình thức kết nối của thiết bị người dùng Để tối ưu hóa kết nối và nâng cao trải nghiệm người dùng, cần sử dụng hình thức kết nối một cách hợp lý Mạng di động thường có băng thông thấp và chi phí cao, trong khi đó Wifi lại phụ thuộc vào băng thông của nguồn kết nối.
1.4 Lớp khai báo kết nối
Việc khai báo kết nối tùy thuộc vào chuẩn giao thức kết nối và địa chỉ URL của máy chủ cần kết nối:
- URL: lớp giải quyết phân giải tên miền thành địa chỉ IP
Định dạng: http://username:password@host:8080/directoryfile?query#ref:
- URLConnection: lớp thực hiện kết nối đến URL được chỉ định cho việc đọc hoặc ghi dữ liệu, hỗ trợ các giao thức:
Các phương thức quan trọng:
Các lớp giao thức HTTP & HTTPS:
■ • Các phương thức quan trọng:
1.4.1 Thực hiện kết nối Internet (HTTP)
- Bao gồm các bước sau:
Thực hiện mở kết nối đến địa chỉ URL được chỉ định HttpURLConnection
Thực hiện khai báo các header, content-type, cookies,
Phương thức setDoOutput(true) được gọi để xây dựng dữ liệu cần gửi lên máy chủ, và dữ liệu này có thể được truy cập thông qua phương thức getOutputStream().
Thực hiện truy xuất dữ liệu thông qua phương thức getInputStream(), để lấy các thông tin về nội dung được trả, độ dài, thời gian.
Gọi phương thức disconnect() để đóng các kết nối khi kết thúc phiên làm việc và giải phóng tài nguyên.
- Một số lưu ý khi thực hiện:
Cần thực hiện xin cấp quyền truy cập Internet cho ứng dụng trong tập tin AndroidManifest
Trong một vài trường hợp cần xin cấp quyền kiểm soát trạng thái Internet
To ensure optimal performance, avoid making direct Internet connections on the main thread of your application Instead, utilize AsyncTask or Thread for handling network operations efficiently.
URL url = new URL(“http://t3h.vn”);
HttpURLConnection httpURLConnection =(HttpURLConnection) urlConnection; int responseCode = httpURLConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) {
// XửLý đọc dữ Liệu từ Inputstream
1.4.2 Thực hiện kết nối Internet (HTTPS)
- Bao gồm các bước sau:
Khai báo KeyStore dùng để chứng thực.
Chứng thực KeyStore thông qua X509TrustManager hoặc SSLSocketFactory
Thực hiện mở kết nối đến địa chỉ URL được chỉ định HttpsURLConnection
Thực hiện gắn SSLContext cho việc chứng thực
Gọi phương thức setDoOutput(true) thực hiện xây dựng phần dữ liệu cần gửi lên máy chủ, dữ liệu được thiết lập được trả thông qua phương thức getOutputStream()
Thực hiện truy xuất dữ liệu thông qua phương thức getInputStream(), để lấy các thông tin về nội dung được trả, độ dài, thời gian
Gọi phương thức disconnect() để đóng các kết nối khi kết thúc phiên làm việc và giải phóng tài nguyên
KeyStore keyStore String algorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null);
URL url = new URL("https://www.example.com/");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection(); urlConnection.setSSLSocketFactory(context.getSocketFactory()); InputStream in
2 SỬ DỤNG DỊCH VỤ DOWNLOAD MANAGER
2.1.Giới thiêu đích vụ Download Manager
Download Manager là một công cụ quản lý tải trên thiết bị Android, được Google tích hợp từ phiên bản Android 2.3 (API 9) Nó hoạt động như một dịch vụ ngầm, giúp giám sát và quản lý các kết nối HTTP, cũng như hỗ trợ khởi động lại thiết bị, đảm bảo quá trình tải xuống diễn ra hoàn chỉnh và hiệu quả.
Download Manager là công cụ hữu ích cho việc tải nội dung kéo dài trong chế độ ngầm, giúp người dùng tiếp tục tương tác trong khi quá trình tải diễn ra Với Download Manager, việc hoàn thành tải nội dung được ưu tiên hàng đầu, mang đến trải nghiệm mượt mà và hiệu quả cho người sử dụng.
- Tất cả các tập tin được tải thông qua Download Manager được quản lý bởi ứng dụng Download trên thiết bị
Hình 7.1 Ví dụ minh họa dịch vụ Download Manager
2.2 Khai báo và sử dụng Download Manager
Để truy xuất Download Manager, sử dụng phương thức getSystemService() với cú pháp: DownloadManager manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE) Để khởi tạo yêu cầu tải nội dung, cần tạo một đối tượng Request với tham số là một Uri, địa chỉ kết nối đến máy chủ chứa nội dung Đối tượng này sẽ được xếp vào hàng đợi để bắt đầu quá trình tải bằng cách gọi phương thức enqueue().
DownloadManager manager = (DownloadManager) getSystemService(DOWNLOAD _SERVICE);
("http://developer.android.com/downloads/design/roboto-1.2.zip"); Request request = new Request(uri); long id_reference = manager.enqueue(request);
DỊCH VỤ WEBSERVICE
Dịch vụ Web (Web Service) là công nghệ cách mạng hóa hoạt động của các dịch vụ B2B và B2C, cung cấp phương thức truy cập chuẩn cho hệ thống đóng gói và kế thừa Các phần mềm viết bằng ngôn ngữ lập trình khác nhau có thể sử dụng dịch vụ Web để chuyển đổi dữ liệu qua Internet, tương tự như giao tiếp nội bộ trong máy tính Công nghệ xây dựng dịch vụ Web không nhất thiết phải mới, mà có thể kết hợp với các công nghệ hiện có như XML, SOAP, WSDL, UDDI Với sự phát triển của Internet, dịch vụ Web là giải pháp hiệu quả để giảm chi phí và độ phức tạp trong tích hợp và phát triển hệ thống.
Theo W3C, dịch vụ Web là hệ thống phần mềm hỗ trợ tương tác giữa các ứng dụng trên máy tính khác nhau qua Internet, với giao diện và sự gắn kết được mô tả bằng XML Dịch vụ Web có thể được xác định bằng địa chỉ URL, thực hiện chức năng và cung cấp thông tin theo yêu cầu của người dùng Nó bao gồm việc đóng gói các chức năng để các ứng dụng khác có thể dễ dàng truy cập, đồng thời cho phép yêu cầu thông tin từ các dịch vụ Web khác Dịch vụ này bao gồm các mô đun độc lập cho hoạt động của khách hàng và doanh nghiệp, và được thực thi trên server.
Dịch vụ Web đóng vai trò quan trọng trong việc tích hợp các hệ thống, là một hoạt động thiết yếu trong phát triển hệ thống Các ứng dụng cần kết nối với cơ sở dữ liệu (CSDL) và các ứng dụng khác, cho phép người sử dụng giao tiếp để phân tích và truy xuất dữ liệu Sự phát triển mạnh mẽ của thương mại điện tử và B2B hiện nay cũng yêu cầu các hệ thống có khả năng tích hợp hiệu quả với CSDL của các đối tác kinh doanh.
Các Web Services giúp các tổ chức truyền thông dữ liệu mà không cần hiểu biết về hệ thống IT phía sau tường lửa Nhiều Web Services hiện có sẵn miễn phí và ngày càng được thiết kế phù hợp hơn với nhu cầu của doanh nghiệp.
Dịch vụ Web Service của PayPal cho phép người dùng có tài khoản thực hiện thanh toán, hoàn tiền hoặc tìm kiếm giao dịch, đồng thời truy xuất thông tin chi tiết về từng giao dịch cụ thể.
3.2 Các chuẩn dịch vụ WEB
Tìm hiểu các chuẩn dịch vụ WEB là cần thiết để lựa chọn phù hợp với hệ thống triển khai, dữ liệu và thiết bị truy xuất dữ liệu Một số chuẩn chính cần được chú ý bao gồm:
- UDDI (Universal Description, Discovery and Integrated)
- WSDL (Web Services Description Language)
- WSIL (Web Services Inspection Language)
- SOAP (Simple Object Access Protocol)
HTTP (Giao thức Truyền Tải Siêu Văn bản) là một giao thức mạng thiết yếu, cho phép các hệ thống thông tin phân phối và tương tác với nhau Nó đóng vai trò là nền tảng giao tiếp dữ liệu cho World Wide Web (WWW).
- HTTP hoạt động trên cơ chế giao thức request - response trong mô hình điện toán client - server
Hình 7.4 Minh họa cơ chế hoạt động của giao thức HTTP
A URI (Uniform Resource Identifier) is a string used to identify a resource on the internet A URL (Uniform Resource Locator) is a specific type of URI that indicates the existence of a resource and the method to access it Conversely, a URN (Uniform Resource Name) is a URI that identifies a resource by name, independent of its storage location.
- HTTP Status code : o 2xx Success ( Trạng thái thành công)
504 - Created o 3xx Redirection ( Báo chuyển hướng)
506 4xx Client Error ( Báo lỗi client)
508 - Not Found o 5xx Server Error ( Báo lỗi server)
- Ví dụ về HTTP - Request
GET http://www.fit.hcmus.edu.vn/vn/ HTTP/1.1
The accepted file types include application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, and application/msword, with the preferred language set to Vietnamese (vi-VN).
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; GTB6.5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ;
SLCC2; NET CLR 2.0.50727; NET CLR 3.5.30729; NET CLR 3.0.30729; Media Center PC 6.0; NET4.0C; NET4.0E; OfficeLiveConnector.1.5;
Accept-Encoding: gzip, deflate Connection: Keep-Alive
Host: www.fit.hcmus.edu.vn
.AS PXANONYMOU S=MG6LCiuSywE kAAAANTA2ZWN iYTAtYTh i
Ny00MDA1LTkyN jUtYTllYzAxNTA3MTU10
- Ví dụ về HTTP - Response
Content-Type: text/html; charset=utf-8
Set-Cookie: DotNetNukeAnonymous}b3c001-c407-4adb-a60f-053b5dc76dc2; expires=Thu, 30-Sep-2010 03:12:33 GMT; path=/; HttpOnly
Set-Cookie: language=vi-VN; path=/; HttpOnly X-Powered-By: ASP.NET
Date: Thu, 30 Sep 2010 02:52:33 GMT Content-Length: 24404
X-Cache: MISS from vweb.hcmuns.edu.vn
Via: 1.0 vweb.hcmuns.edu.vn:80 (squid/2.6.STABLE16) Connection: keep-alive
// Nội dung trang web
- Các phương thức phương thức chính của HTTP
Hình 7.5 Các phương thức chính của HTTP
■ Dùng để tải một biểu diễn của tài nguyên
■ Được sử dụng nhiều nhất.
■ Biểu diễn của tài nguyên có thể bao gồm HTML, JPG, XML, Phương thức HEAD:
■ Tương tự như GET thay vì tải toàn bộ thể hiện thì chỉ tải HTTP Header.
■ Dùng để kiểm tra thay đổi khi muốn tải lại tài nguyên có kích thước lớn Phương thức DELETE:
■ Dùng để xóa tài nguyên. o Phương thức PUT :
■ Dùng để lưu một biểu diễn vào một tài nguyên
■ Đăng tải một tập tin vào một vị trí xác định trên website.
■ Neu PUT thực hiện hai lần thì lần sau sẽ đè lên lần trước. o Phương thức POST :
■ Tạo một tài nguyên tương tự như PUT, nhưng server sẽ quyết định cách lưu trữ thay vì client như PUT
SOAP (Simple Object Access Protocol) là một giao thức giao tiếp được thiết kế với cấu trúc XML, cho phép các ứng dụng trao đổi thông tin một cách hiệu quả thông qua định dạng chung.
SOAP là một đặc tả sử dụng tài liệu XML để tạo ra các thông điệp, không định nghĩa ngữ nghĩa ứng dụng hay cách cài đặt chi tiết Nó cung cấp cơ chế đơn giản và gọn nhẹ cho việc trao đổi thông tin có cấu trúc trong môi trường phân tán SOAP được thiết kế để giảm chi phí tích hợp các hệ thống phân tán trên nhiều nền tảng khác nhau Đặc tả SOAP định nghĩa mô hình trao đổi dữ liệu dựa trên ba khái niệm cơ bản: các thông điệp là tài liệu XML, được truyền từ bên gửi đến bên nhận, và bên nhận có thể chuyển tiếp dữ liệu đến nơi khác.
Mô hình SOAP sử dụng tài liệu XML làm thông điệp trao đổi, mang lại nhiều ưu điểm so với các giao thức truyền dữ liệu khác Các thông điệp XML dễ dàng tổng hợp và đọc bằng các trình soạn thảo văn bản đơn giản, cho phép làm việc trên hầu hết các nền tảng.
SOAP có những đặc trưng nổi bật như thiết kế đơn giản và dễ mở rộng, tất cả các thông điệp đều được mã hóa bằng XML và sử dụng giao thức truyền dữ liệu riêng biệt Hệ thống này không hỗ trợ garbage collection phân tán và không có cơ chế tham chiếu, do đó, SOAP client không giữ bất kỳ tham chiếu nào về các đối tượng ở xa Đặc biệt, SOAP không bị ràng buộc bởi ngôn ngữ lập trình hay công nghệ cụ thể nào.
Với đặc điểm này, hệ thống không bị ràng buộc bởi công nghệ cụ thể nào, miễn là người dùng gửi các tin nhắn theo định dạng XML Tương tự, dịch vụ có thể được triển khai bằng bất kỳ ngôn ngữ lập trình nào, miễn là nó có khả năng xử lý các tin nhắn định dạng XML.
Trong quá trình trao đổi thông điệp SOAP, có hai thành phần chính là bên gửi và bên nhận, với thông điệp được chuyển từ bên này sang bên kia Mặc dù mô hình này đơn giản, nhưng trong nhiều trường hợp, nó không đáp ứng đủ nhu cầu chức năng Tuy nhiên, đây là nền tảng cơ bản cho việc phát triển các mô hình trao đổi phức tạp hơn trong tương lai.
Hình 7.6 Hệ thống Soap đơn giản.
- Một cấu trúc SOAP được định nghĩa gồm các phần: , và
Hình 7.7 Cấu trúc thông điệp SOAP.
XÂY DỰNG ỨNG DỤNG KẾT NỐI DỊCH VỤ WEB RESTFUL
Ứng dụng trực tuyến trên thiết bị di động được thiết kế để hiển thị dữ liệu từ các máy chủ và gửi yêu cầu truy xuất dữ liệu Chẳng hạn, Google Play Store là ứng dụng do Google cài đặt trên thiết bị người dùng, giúp hiển thị các ứng dụng do lập trình viên phát triển, cho phép người dùng tải và cài đặt chúng trực tiếp trên thiết bị của mình.
Trong hướng dẫn này, chúng ta sẽ khám phá dịch vụ OnlineShop, chuyên cung cấp thông tin chi tiết về các sản phẩm, bao gồm giá cả, chất liệu và tính năng.
5.2 Khai báo và kiểm soát các yêu cầu kết nối
Để bắt đầu, cần xin quyền truy cập Internet cho ứng dụng, đồng thời có thể bổ sung các quyền liên quan để kiểm soát kết nối Internet hiệu quả.
Trong việc truy xuất tài nguyên Internet trên thiết bị di động, việc kiểm soát kết nối là rất quan trọng Cần cho phép người dùng tương tác với ứng dụng ở chế độ ngoại tuyến và thực hiện cập nhật dữ liệu khi có kết nối Một ví dụ điển hình là việc sử dụng Broadcast Receiver để quản lý các vấn đề liên quan đến kết nối này.
@Override public void onReceive(Context context, Intent intent) {
.getSystemService(Context.CONNECTIVITY_SERVICE)); if (cm.getActiveNetworkInfo() != null) {
// Thực hiện xử Lý khi không có kết nối
} else {// Và khi không có kết nối.}
- Việc kết nối được thông qua 2 cách: sử dụng kết nối URL thông thường hoặc sử dụng kết nối thông qua thư viên của gói org.apcahe.http.
- Sử dụng kết nối URL thông thường:
Url url = new URL(“http://221.132.37.130:6969/OnlineShopWebService”); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10000); connection.setReadTimeout(10000); connection.setRequestMethod("GET");
Trong phương thức setRequestMethod, chúng ta có thể tự do chỉ định tên của các phương thức gọi từ dịch vụ RESTful như GET, POST, PUT, v.v Tùy thuộc vào loại phương thức mà dịch vụ cung cấp, cách thực hiện sẽ khác nhau Trong ví dụ trên, việc gọi theo phương thức GET mà không có tham số truyền vào không khác biệt nhiều so với cách thực hiện ở phần đầu chương.
Để đăng nhập vào dịch vụ này, bạn cần khảo sát quy trình gửi dữ liệu người dùng dưới định dạng JSON và sử dụng phương thức POST nhằm đảm bảo an toàn cho dữ liệu.
To establish a connection to the online shop web service, create a URL object with the specified endpoint Use HttpURLConnection to open the connection, setting a connection and read timeout of 10 seconds Configure the request method to POST and specify the content type as application/json, enabling output and allowing the connection to follow redirects.
BufferedOutputStream(connection.getOutputStream()); outputSt ream.write(incomingParams.getBytes()); outputStream.flush(); outputStream.close();
Dữ liệu incomingParams được chia nhỏ thành từng byte bằng phương thức getBytes() trước khi được gửi vào Outputstream của kết nối Dữ liệu này được định dạng dưới dạng JSON khi dịch vụ nhận qua phương thức setRequestProperty().
Sử dụng các lớp trong gói org.apache.http giúp làm rõ hơn việc gọi đến Service Cụ thể, việc áp dụng hai lớp HttpGet và HttpPost cho phép thực hiện các yêu cầu HTTP một cách hiệu quả và dễ dàng.
HttpGet: sau khi thực hiện có thể thực hiện truy xuất dữ liệu dạng InputStream thông qua phương thức getEntity đối tượng HttpResponse. public static Inputstream getInputStreamFromUrl(String url) {
HttpGet httpGet = new HttpGet(url));
HttpResponse response = httpclient.execute(httpGet); content = response.getEntity().getContent();
Log.d("[GET REQUEST]", "Network exception" + e);
Đối với phương thức HttpPost, cần xác định định dạng dữ liệu khi gửi lên dịch vụ Ví dụ dưới đây mô tả cách gửi dữ liệu dưới dạng JSON, được đóng gói trong một đối tượng.
NameValuePair Dữ liệu được trả về vẫn được truy xuất thông qua đối tượng HttpResponse
HttpPost httpPost = new HttpPost(URL_CONNECT);
JSONObject jsonObject = ModuleCore.moduleCoreToJson(ModuleCore.LOGIN, params);
List nvps = new ArrayList(); nvps.add(new BasicNameValuePair("jsonParam", j sonObject.toString())); httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
HttpResponse httpResponse = httpClient.execute(httpPost);
5.3 Truy xuất dữ liệu trả về
Việc truy xuất dữ liệu không phụ thuộc nhiều vào phương thức gọi dịch vụ, vì dữ liệu luôn ở dạng InputStream Chúng ta chỉ cần đọc dòng dữ liệu này và chuyển đổi thành định dạng dữ liệu tương ứng để tương tác Dưới đây là ví dụ về cách đọc dữ liệu từ InputStream thành String:
BufferedReader reader = new BufferedReader(new
InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null) { builder.append(line);
Bài tập thực hành của sinh viên
1 Trình bày và khai thác tài nguyên internet
2 Trình bày giao thức kết nối WEBSERVICE
3 Thêm mới tài khoản –Thực thi câu lệnh Insert Into
4 Thay đổi mật khẩu – Thực thi câu lệnh Update
5 Hiển thị danh sách tài khoản –Thực thi câu lệnh Select
6 Xóa một tài khoản –Thực thi câu lệnh Delete
7 Hướng dẫn sử dụng webservice trong android –Chuẩn bị
1 Trình bày SERVICE trong android, tham khảo mục 1 ở bài 6 của giáo trình
2 Trình bày BROADCAST RECEIVER tham khảo mục 2 ở bài 6 của giáo trình
3 Trình bày các bước NOTIFICATION tham khảo mục 3 ở bài 6 của giáo trình
4 Sử dụng Un bounded Service dịch vụ chơi nhạc (Chạy ngầm):
Sau đây là nội dung của Main Activity file đã được sửa đổi: src/com.example.My
In the MainActivity.java file of the com.example.MyApplication package, we have implemented the startService() and stopService() methods to manage the lifecycle of a service This is done within the MainActivity class, which extends the Activity class, allowing for the creation and management of user interface components and interactions in an Android application.
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true;
// Method to start the service public void startService(View view) { startService(new Intent(getBaseContext(), MyService.class));
// Method to stop the service public void stopService(View view) { stopService(new Intent(getBaseContext(), MyService.class));
The following content pertains to the file src/com.example.MyApplication/MyService.java, which may contain the implementation of one or more methods linked to a Service based on specific requirements In this instance, we are implementing only two methods: onStartCommand() and onDestroy() The package is defined as com.example.MyApplication, and it imports necessary classes such as android.app.Service, android.content.Intent, android.os.IBinder, and android.widget.Toast The main class, MyService, extends the Service class.
@Override public IBinder onBind(Intent arg0) { return null;
@Override public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show(); return START_STICKY;
@Override public void onDestroy() { super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show(); }
} Còn đây là nội dung đã được sửa đổi của AndroidManifest.xml Ở đây, chúng ta đã thêm thẻ để bao Service của chúng ta:
Đây sẽ là nội dung của res/layout/activity_main.xml file để bao hai nút:
The RelativeLayout in Android is defined with the XML namespace for Android and tools, ensuring it matches the parent layout's width and height It includes padding on all sides, utilizing dimensions specified in the app's resources This layout is typically used in the MainActivity of an Android application.
This example showcases a TextView in Android, defined with an ID of "textView1." It is designed to wrap its content and is positioned at the top center of its parent layout The text displayed is "Example of services," formatted with a text size of 30dp.
THAO TÁC VỚI DỮ LIỆU XML VÀ JSON
Đọc ghi dữ liệu XML
- XML (viết tắt từ tiếng Anh eXtensible Markup Language, "Ngôn ngữ Đánh dấu
XML (eXtensible Markup Language) là ngôn ngữ đánh dấu do W3C đề xuất, nhằm tạo ra các ngôn ngữ đánh dấu khác Đây là một tập con đơn giản của SGML, có khả năng mô tả nhiều loại dữ liệu khác nhau Mục tiêu chính của XML là đơn giản hóa việc chia sẻ dữ liệu giữa các hệ thống khác nhau, đặc biệt là những hệ thống kết nối Internet Các ngôn ngữ dựa trên XML như RDF, RSS, MathML, XHTML, SVG, GML và cXML được định nghĩa một cách thông thường, cho phép các chương trình dễ dàng sửa đổi và kiểm tra tính hợp lệ mà không cần hiểu biết sâu về hình thức của chúng.
- Cú pháp sơ lược: Nội dung thẻ
1.2 Đọc ghi dữ liêu XML
- Để thực hiên đọc dữ liêu từ XML trong Android, ta có thể sử dụng DOM (Document Object Model) Parser hoặc XML Pull Parser.
- DOM Parser: giao diên lập trình ứng dụng (API) có dạng một cây cấu trúc dữ liêu, các đối tượng cần khởi tạo khi sử dụng:
Element: đại diên cho một thẻ trong XML
Document: tập tin tài liêu được khởi tạo từ dữ liêu XML thông qua DocumentBuilder
DocumentBuilder: đối tượng hỗ trợ chuyển đổi dữ liêu XML thành cấu trúc tập tin XML cho viêc đọc ghi dữ liêu.
DocumentBuilderFactory: khởi tạo đối tượng DocumentBuilder.
Transformer: đối tượng cho phép thực hiên chuyển đổi dữ liêu sang nhiều dạng XML khác nhau
TransformerFactory : khởi tạo đối tượng Transformer.
- Ví dụ: thực hiên tổ chức ghi dữ liêu XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder();
Element rootElement = document.createElement("data"); document.appendChild(rootElement);
Element weather = document.createElement("weather");
// Thi ế t L ậ p Là th ẻ con trong th ẻ rootElement.appendChild(weather);
Element date = document.createElement("date");
// Kh ở i t ạ o giá tr ị th ẻ date.appendChild(document.createTextNode("20-06-2014"));
// Thi ế t L ậ p Là th ẻ con trong th ẻ weather.appendChild(date);
Element tempMaxC = document.createElement("tempMaxC"); tempMaxC.appendChild(document.createTextNode("13")); weather.appendChild(tempMaxC);
Element tempMaxF = document.createElement("tempMaxF"); tempMaxF.appendChild(document.createTextNode("56")); weather.appendChild(tempMaxF);
// Đị nh d ạ ng các thu ộ c tính d ữ Li ệ u XML
TransformerFactory transformerFactory TransformerFactory.newInstance(); Transformer transformer transformerFactory.newTransformer();
To configure the XML output format in Java, create a new Properties object and set various output properties Ensure that indentation is enabled for better readability by setting the "indent" property to "yes." Specify the output method as "xml" and include the XML declaration by setting "omit-xml-declaration" to "no." Additionally, define the XML version as "1.0" and use "UTF-8" encoding for character representation Finally, apply these output properties to the transformer using the setOutputProperties method.
// Chuy ển đổ i ngu ồ n d ữ Li ệ u theo chu ẩ n DOM
DOMSource domSource =new DOMSource(document.getDocumentElement()); OutputStream output = newByteArrayOutputStream();
StreamResult result = newStreamResult(output); transformer.transform(domSource, result);
String xmlString = output.toString(); textXML.setText(xmlString);
- Kết quả của dữ liệu XML:
XML Pull Parser cho phép trình bày các thành phần trong tệp tin dưới dạng chuỗi các thẻ (tag) Việc ghi dữ liệu XML được thực hiện thông qua hai đối tượng.
// Kh ở i t ạ o đố i tượ ng XmLSeriaLizer
// Kh ở i t ạ o đố i tượ ng StringWritter
The code snippet demonstrates how to use a `StringWriter` and `XmlSerializer` to create an XML document representing weather data It initializes the `StringWriter`, sets the output for the `XmlSerializer`, and starts the XML document with UTF-8 encoding The XML structure includes a root element `` with a source attribute, followed by a `` tag containing the date, maximum temperature in Celsius, and Fahrenheit Finally, the XML document is closed, and the generated XML string is set to a text view.
- Kết quả của dữ liệu XML:
- DOM Parser: giao diện lập trình ứng dụng (API) có dạng một cây cấu trúc dữ liệu, các đối tượng cần khởi tạo khi sử dụng:
Element: đại diện cho một thẻ trong XML
NodeList: đại diện cho một thẻ có chứa nhiều thẻ con.
Document: tập tin tài liệu được khởi tạo từ dữ liệu XML thông qua DocumentBuilder
DocumentBuilder: đối tượng hỗ trợ chuyển đổi dữ liệu XML thành cấu trúc tập tin XML cho việc đọc ghi dữ liệu.
DocumentBuilderFactory: khởi tạo đối tượng DocumentBuilder sample_xmlxml:
- Ví dụ xử lý XML với DOM: truy xuất dữ liệu thẻ trong đoạn XML trên. DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try {
InputStream inputStream = getAssets().open("sample_xml.xml");
Document document = db.parse(inputStream);
NodeList nodeList = element.getElementsByTagName("weather"); if (nodeList == null) return; for (int i=0; i
GoogLe Maps Android API v2 nhưng đượ c khuy ế n khích nên khai báo >
- Sử dụng OpenGL 2.0 cho việc đồ họa bản đồ:
2.3 GoogleMap & Xây dựng Đối tượng
- Tạo các đối tượng để thực hiện tương tác giữa ứng dụng với người dùng bao gồm:
■ Kết nối đến Google Map Service
■ Tải dữ liệu bản đồ theo từng mảng nhỏ (tiles)
■ Thể hiện dữ liệu bản đồ trên màn hình thiết bị.
■ Thể hiện các điều khiển giao tiếp như thu phóng, la bàn
■ Xử lý các tương tác thu phóng, xoay, góc nhìn.
MapFragment: xây dựng giao diện bản đồ bằng cách xây dựng Fragment
MapView: xây dựng giao diện bản đồ như một điều khiển và tương tác với
- Truy xuất và sử dụng đối tượng GoogleMap từ thẻ fragment trong XML:
GoogleMap mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
- Hoặc tạo trực tiếp bằng câu lệnh Java:
GoogleMap mMap = mapFragment.getMap(); mMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE); getFragmentManager().beginTransaction().add(R.id.container, mapFragment).commit();
- Cần thực hiện kiểm tra đối tượng GoogleMap trước khi tương tác Mã lệnh kiểm tra như sau: private void setUpMapIfNeeded(){
//Khởi tạo đối tượng GoogleMap nếu chưa có giá trị if( mMap == null){ mMap = mapFragment.getMap();
// Kiểm tra đối tượng GoogleMap đã được khởi tạo thành công if( mMap != null) {
// Thực hiện các tùy chỉnh trên đối tượng GoogleMap mMap.setMapType (GoogleMap.MAP_TYPE_TERRAIN);
- Các giao diện bản đồ:
- Để thực hiện thay đổi giao diện gọi phương thức setMapType(int) và truyền vào tham số tương ứng.
Hình 9.4 Minh họa một số loại giao diện bản đồ
- Thiết lập các giá trị ban đầu và điều khiển cho GoogleMap bao gồm:
La bàn và điều khiển thu phóng.
Các điều khiển cử chỉ trên bản đồ.
- Thiết lập các giá trị ban đầu và điều khiển cho GoogleMap trong XML:
The provided XML code snippet defines a MapFragment in an Android application, specifying its layout dimensions to match the parent view This fragment utilizes the Google Maps API to integrate mapping functionalities into the app, enhancing user experience with geographic features.
- Thực hiện tùy chỉnh GoogleMap thông qua đối tượng GoogleMapOptions: GoogleMapOptions mapOptions = new GoogleMapOptions(); mapOptions.mapType(GoogleMap.MAP_TYPE_HYBRID)
.scrollGesturesEnabled(true) rorateGesturesEnabled(true) zoomControlsEnabled(true);
- Thiết lập đối tượng GoogleMapOptions:
2.4 Đồ họa trên Google Map
Lớp Marker là một công cụ quan trọng được thiết kế để định vị tọa độ trên bản đồ, giúp hiển thị thông tin địa điểm và tương tác với người dùng Ví dụ, để sử dụng lớp Marker, bạn có thể khai báo bằng cách sử dụng MarkerOptions markerOptions = new MarkerOptions();.
LatLng position = new LatLng(lat, lng); markerOptions.position(position); markerOptions.draggable(true);
Marker marker = map.addMarker(markerOptions); marker.setTitle("Nhà của tui");
Hình 9.5 Minh họa sử dụng lớp Marker
- Tùy chỉnh Marker bằng các thông số:
- Ví dụ tùy chỉnh Marker bằng các thông số position, title, snippet, draggable, anchor, visible và icon: mMap.addMarker(new MarkerOptions()
.position(new LatLng(10.385474,104.488199)) title(“Nhà của tôi”)
- InfoWindow được thể hiện phía trên đối tượng Marker thể hiện các thông tin cần thiết về vị trí đang định vị.
- Chỉ một đối tượng InfoWindow hiển thị ở một thời điểm và có thể điều khiển thông qua hai phương thức:
- Để tùy chỉnh InfoWindow trong lớp GoogleMap hỗ trợ giao diện
InfoWindowAdapter bao gồm 2 phương thức:
- Gọi phương thức setInfoWindowAdapter để thiết lập InfoWindow cho đối tượng GoogleMap.
Hình 9.6 Minh họa sử dụng Marker và InfoWindow
- Google Maps API cung cấp các giao diện cho phép bắt lại các sự kiện tương với Marker và InfoWindow
- Shape bao gồm các đối tượng hình học được vẽ trên bản đồ bao gồm các dạng sau: o Polyline o Polygons o Circle
- Polyline: được tạo bằng các nối các điểm dựa trên toạ độ điểm Ví dụ minh họa:
.add(new LatLng(10.919618, 106.523438)) add(new LatLng(13.410994, 123.046875)) add(new LatLng(35.746512, 139.833984));
Polyline polyline = mMap.addPolyline(options);
- Polyline có các phương thức tùy chỉnh sau: boolean equals(Object other) int getColor()
The article outlines various methods for managing geographical features in a mapping application, including retrieving points with `getPoints()`, adjusting visual properties such as width and color with `setWidth(float width)` and `setColor(int color)`, and controlling visibility using `setVisible(boolean visible)` It also discusses the importance of geodesic lines with `isGeodesic()` and `setGeodesic(boolean geodesic)`, alongside the capability to remove features with `remove()`, and the ability to define their stacking order through `setZIndex(float zIndex)` Additionally, it highlights the unique identifier for each feature with `hashCode()` and the functionality to check if a feature is currently visible with `isVisible()`.
Polygon là một hình dạng tương tự như Polyline, được tạo ra bằng cách nối các điểm dựa trên tọa độ Tuy nhiên, Polygon có khả năng khép kín các tọa độ, cho phép người dùng thao tác với vùng đã được khép kín một cách hiệu quả.
- Ví dụ minh họa sử dụng Polygon: double height = 5, width = 5;
Polygonoptions options = new PolygonOptions(); options.add(new LatLng(center.latitude -height, center.longgitude - width))
.add(new LatLng(center.latitude - height, center.longgitude +width))
Hình 9.7 Minh họa sử dụng Polyline Hình 9.8 Minh họa sử dụng Polyline
.add(new LatLng(center.latitude + height, center.longgitude +width)) add(new LatLng(center.latitude - height, center.longgitude + width)) Polygon polygon = mMap.addPolygon(options);
Hình 9.9 Minh họa sử dụng Polygon
- Polygon có các phương thức tùy chỉnh sau:
PolygonOptions addAll(Iterable points) PolygonOptions addHole(Iterable points) int describeContents()
PolygonOptions geodesic(boolean geodesic) int getFillColor()
List getPoints() int getStrokeColor() float getStrokeWidth() float getZIndex() boolean isGeodesic() boolean isVisible()
PolygonOptions visible(boolean visible) void writeToParcel(Parcel out, int flags)
- Circle: đối tượng hình học (hình tròn) được xác định trên bản đồ thông qua bán kính và tâm
CircleOptions circleoptions = new CircleOptions(); circleoptions.center(HCM).radius(5);
Circle circle = mMap.addCircle(circleOptions); circle.setFillColor(Color.CYAN); circle.setStrokeColor(Color.WHITE);
- Circle có các phương thức tùy chỉnh sau:
The provided methods for managing a graphical object include retrieving the ID, radius, stroke color, stroke width, and visibility status, as well as setting the object's center, fill color, radius, stroke color, stroke width, visibility, and Z-index Additionally, there is a method to remove the object from the display.
Giới thiệu Google Cloud Messaging
- Google Cloud Messaging (GCM) là một dịch vụ cho phép gửi dữ liệu từ máy chủ của bạn đến các thiết bị Android của người dùng, và ngược lại.
GCM (Google Cloud Messaging) là công nghệ được sử dụng cho các hoạt động giao dịch giữa các ứng dụng và máy chủ hỗ trợ đầu cuối Với việc tích hợp vào Google Play Services, Cloud Messaging đã được cải tiến mạnh mẽ, cho phép kết nối liên tục và truyền tải thông điệp ngược dòng (upstream) hiệu quả Điều này cho phép thiết bị có thể gửi phản hồi trở lại máy chủ một cách linh hoạt, thay vì chỉ nhận thông tin một chiều từ máy chủ như trước đây.
Nhờ tính năng truyền tải ngược, các thông báo mà bạn nhận được và bỏ lỡ trên thiết bị này có thể được đồng bộ với thiết bị khác, giúp bạn không phải kiểm tra lại hàng loạt thông báo tương tự khi chuyển sang sử dụng máy tính bảng.
Hình 9.10 Logo Google Cloud Messaging
GCM hoàn toàn miễn phí và không giới hạn băng thông, cung cấp dịch vụ trên các gói dữ liệu nhỏ hơn 4kb Tin nhắn được gửi tới thiết bị Android một cách tức thời thông qua tính năng Push-notification.
- GCM là phù hợp cho việc xây dựng các ứng dụng nhắn tin tức thời hoặc tương tác giữa người dùng và nhà phát triển ứng dụng.
Nhận thông báo ngay lập tức trên thiết bị Android khi có email mới GCM sẽ thông báo cho người quản lý khi có đơn đặt hàng mới trên trang web của họ.
Gửi tin nhắn đến một cộng đồng như nhân viên trong cùng một công ty, học sinh hoặc phụ huynh của một trường học là cách hiệu quả và tiết kiệm chi phí nhất.
Hãy cùng xem hình dưới để hiểu rõ hơn.
Hình 9.11 Nguyên tắc hoạt động khi Web Server với Google Cloud Messaging.
CẤU HÌNH CHO GOOGLE CLOUD MESSAGING
4.1 Đăng ký dịch vụ GCM
- Đầu tiên, bạn cần đăng ký Google Cloud Messaging bằng tài khoản Google của bạn
Truy cập Google Console tại: https://cloud.google.com/console/project
Nếu bạn chưa tạo một dự án API nào, nhấp vào “Create Project” Điền tên và nhấn Create Start using the Google APIs console
Hình 9.12 Tạo một Project trên Google Developers Console
Một khi dự án đã được tạo ra, một trang xuất hiện hiển thị ID dự án của bạn Ví dụ: id dự án của bạn là engaged-root-93803
Hình 9.13 Minh hoạ màn hình tổng quan của dự án trên Google Developers Console
Sao chép số ID Project này lưu lại Bạn sẽ sử dụng nó như GCM sender ID - Sau đó, bạn cần kích hoạt API cho GCM
Trong thanh bên trên bên trái, chọn mục API & auth Chọn tiếp APIs
Tìm đến mục Google Cloud Messaging for Android và “Enable API”.
Hình 9.14 Kích hoạt Google Cloud Messaging trong dự án của bạn 1
Hình 9.15 Kích hoạt Google Cloud Messaging trong dự án của bạn 2
- Bây giờ bạn đã có thể lấy API Key với các bước sau:
Trong thanh bên trên bên trái, chọn API & auth Sau đó chọn Credentials
Trong phần Public API access, nhấp vào Create new key.
Trong hộp thoại Create a new key, nhấp vào Server key.
Trong hộp thoại IP address bêndưới nhập vào địa chỉ IP Web Server của bạn Dùng địa chỉ 0.0.0.0/0 cho mục đích thử nghiệm.
Nhấp vào Create. o Trong trang mới, sao chép API Key:
Hình 9.16 Sao chép lại API key.
Mở tập tin appengine-web.xml và tìm đến dòng lệnh bên dưới và thay thế
“YOUR KEY HERE” là API key vừa lấy được: cproperty name="gcm.api.key" value="YOUR_KEY_HERE" />
4.2 Cấu hình môi trường hoạt đông cho GCM
- Download thư viện hỗ trợ GCM
- Mở SDK Manager lên và tiến hành tải thư viện hỗ trợ GCM.
- Vào mục Extras Chọn mục Google Cloud Messaging for Android Library:
Hình 9.16 Tải GCM helper library
4.3 Chuẩn bị máy ảo với Google API:
Mở ADV Manager và tạo một máy ảo Google API emulator
Sau khi máy ảo chạy lên Vào mục Setting, chọn Select Account & Sync Và chọn Add Account sau đó điền tài khoản Google của bạn vào.
Lưu ý: Nếu bạn không đăng nhập tài khoản google vào và chạy ứng dụng sử dụng dịch vụ GGM sẽ bị lỗi GCM: error (ACCOUNT_MISSING)
4.4 Tạo Project để đăng ký GCM
- Tạo một Android Application Project.
- Trong tập tin AndroidManifest.xml cần đăng ký các quyền sau:
INTERNET - để kết nối mạng
ACCESS_NETWORK_STATE —để kiểm tra trạng thái mạng.
Hình 9.17 Tạo máy ảo Google API emulator
GET_ACCOUNTS — cần bởi vì GCM truy cập Google account của bạn
WAKE_LOCK — Cần để gọi thiết bị của bạn khi ở trạng thái sleep.
VIBRATE —Xin quyền rung thiết bị.
4.5 Sử dụng “backend” trong Android Studio
- Backend được hiểu như một server Backend minh họa dưới đây sử dụng Google Cloud Endpoints để định nghĩa một RESTfull API
- Sau đây là minh họa cụ thể từng bước thực hiện tạo một “backend” trong Android Studio:
To create a backend for an existing Android project, open Android Studio and navigate to File → New → Module, or right-click on the project and select New → Module.
Xuất hiện hộp thoại “Create New Module” Chọn “Google Cloud Module” Next
Xuất hiện hộp thoại “New Google Cloud Module” và điền các thông tin như sau:
- Module type (1): chúng ta chọn “App Engine Backend with Google Cloud Messaging”
- Module name (2): là tên của backend mà chúng ta muốn tạo, ở đây tôi để mặc định là backend
- Package name (3): tên gói để chứa backend
- Client module (4): backend được tạo cho ứng dụng này.
Cuối cùng, chúng ta chọn Finish để kết thúc quá trình tạo backend Và backend sau khi tạo có cấu trúc như sau:
Hình 9.22 Cấu trúc backend sau khi tạo
Hình 9.23 Cấu trúc backend sau khi tạo
- Chạy Debbugging backend (Debugging the backend locally)
Hình 9.25 Kết quả sau khi chạy Debbug
- Kết nối ứng dụng Android của bạn tới backend
Before messages can be sent from the Google Cloud Messaging (GCM) backend to devices, those devices must be registered with the GCM backend The following example demonstrates how to create an AsyncTask to register devices with a GCM backend: class GcmRegistrationAsyncTask extends AsyncTask { private static Registration regService = null; private GoogleCloudMessaging gcm; private Context context;
To register for the GCM service, assign the project number to the SENDER_ID, which is defined as "325746572265" The GcmRegistrationAsyncTask class is initialized with a context parameter to facilitate the registration process.
@Override protected String doInBackground(Void params) { if (regService == null) { Registration.Builder builder = new
Registration.Builder(AndroidHttp.newCompatibleTransport( ), new AndroidJsonFactory(), null)
// setRootUrl và setGoogleClientRequestInitializer để kiểm // tra cục bộ (local)
.setRootUrl("http://10.0.2.2:8080/_ah/api/") setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() { @Override public void initialize(AbstractGoogleClientRequest abstractGoogleClientRequest) throws IOException { abstractGoogleClientRequest.setDisableGZipContent(true ); }
} String msg = ""; try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(context);
} String regId = gcm.register(SENDER_ID); msg = "Device registered, registration ID=" + regId;
Gửi ID đăng ký đến server của bạn qua HTTP để sử dụng GCM/HTTP hoặc CSS nhằm gửi tin nhắn đến các ứng dụng của bạn bằng cách thực hiện regService.register(regId).execute();
} catch (IOException ex) { ex.printStackTrace(); msg = "Error: " + ex.getMessage();
@Override protected void onPostExecute(String msg) {
Toast.makeText(context, msg, Toast.LENGTH_LONG).show(); Logger.getLogger("REGISTRATION").log(Level.INFO, msg);
Trong lớp MainActivity.java phải có phương thức new GcmRegistrationAsyncTask(this).execute(); thì lớp
GcmRegistrationAsyncTask.java mới được thực thi
■ Chạy kiểm tra đăng ký thiết bị với máy ảo Google API emulator
■ Hiển thị các thông báo (notifications) được đẩy (push) từ GCM backend:
Để sắp xếp thứ tự hiển thị các thông báo (notifications) được gửi đi từ backend, chúng ta cần viết thêm 2 lớp GcmIntentService.java và
GcmBroadcastReceiver.java vào ứng dụng Android (phía Client):
Mã nguồn cho lớp GcmIntentService.java public class GcmIntentService extends IntentService { public GcmIntentService() { super("GcmIntentService");
@Override protected void onHandleIntent(Intent intent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent); if (extras != null && !extras.isEmpty()) { if
(GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) { Logger.getLogger("GCM_RECEIVED").log(Level.INFO, extras.toString()); showToast(extras.getString("message"));
GcmBroadcastReceiver.completeWakefulIntent(intent); } protected void showToast(final String message) { new Handler(Looper.getMainLooper()).post(new Runnable() {
Mã nguồn cho lớp GcmBroadcastReceiver.java public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
GcmIntentService.class.getName()); startWakefulService(context, (intent.setComponent(comp))); setResultCode(Activity.RESULT_OK);
Sau khi bổ sung hai lớp GcmIntentService.java và GcmBroadcastReceiver.java vào ứng dụng Android, chúng ta cần đăng ký chúng bằng cách thêm mã vào tệp AndroidManifest.xml trong thẻ .
- Triển khai backend trực tiếp đến Google App Engine
Nếu backend đang chạy thì dừng backend bằng cách chọn Run Stop
To deploy your module to App Engine, select Build → Deploy Module to App Engine A dialog box will appear; choose your Google Developers Console project (ensure you are logged into your Google account) and click Deploy If you do not have an existing Google Developers Console project, click on "create a new Google Developers Console project" to set up a new project.
Hình 4.18 Triển khai backend đến App Engine
Mở tập tin appengine-web.xml theo đường dẫn src/main/webapp/WEBINF/appengine-web.xml và tìm đến thẻ
“myApplicationId” bằng ID của dự án bạn vừa tạo (dự án Google Developers Console)
Bài tập thực hành của sinh viên
1 Trình bày được Google Play Service SDK
2 Trình bày được Google Maps Android API
3 Thực hiện được cấu hình cho Google Cloud Messaging
4 Trình bày và thực hiện được Đồ họa trên Google Map
5 Thực hiện được GoogleMap & Xây dựng Đối tượng
6 Tạo một project với Google Map
1 Trình bày được Google Play Service SDK
2 Trình bày được Google Maps Android API
3 Thực hiện được cấu hình cho Google Cloud Messaging
4 Trình bày và thực hiện được Đồ họa trên Google Map
5 Thực hiện được GoogleMap & Xây dựng Đối tượngtham khảo mục 2.2 ở bài 8 của giáo trình
6 Tạo một project với Google Map
Để hiểu rõ hơn về các vấn đề liên quan đến Google Map, bạn nên bắt đầu bằng cách tạo một project mới từ đầu Hãy mở Android Studio và tạo một project với tên MyGoogleMap, sau đó kéo thả đối tượng Google Map vào màn hình.
Package name: org.o7planning.mygooglemap
Hình 9.19 Tạo Project tên MyGoogleMap Một project rỗng đã được tạo ra:
Hình 9.20 Kết quả Tạo Project tên MyGoogleMap
Google Maps trên Android sử dụng dịch vụ để lấy và hiển thị dữ liệu bản đồ từ Google Sau khi đăng ký một Google Map API Key, bạn cần khai báo Key này trong tệp AndroidManifest.xml.
Đăng ký Google Map API Key
Tiếp theo, bạn cần thêm thư viện Google Map vào project của bạn Trên Android Studio chọn:
Hình 9.21 Tạo Project Structure Tìm kiếm thư viện với từ khóa "com.google.android.gms"
com.google.android.gms:play-services-maps
Hình 9.22 Cửa sổ com.google.android.gms:play-services-maps
Hình 9.23 Cửa sổ add com.google Lúc này, thư viện đã được thêm vào build.gradle(Module app)
Hình 9.24 Cửa sổ Module app implementation 'com.google.android.gms:play-services-maps:17.0.0'
Sau khi khai báo thư viện phụ thuộc, bạn cần phải biên dịch lại toàn bộ project.
Hình 9.25 Cửa sổ biên dịch lại toàn bộ projectMap Fragment
MapFragment và SupportMapFragment là hai fragment được cung cấp bởi thư viện, chứa GoogleMap Bạn có thể sử dụng một trong hai fragment này hoặc tạo một lớp kế thừa từ một trong hai lớp đó.
The `MyMapFragment.java` file is part of the `org.o7planning.mygooglemap` package and imports essential Google Maps components, including `CameraUpdateFactory`, `GoogleMap`, `OnMapReadyCallback`, and `MarkerOptions` This class extends `SupportMapFragment` to provide map functionality in an Android application It enables developers to integrate and manage Google Maps effectively within their apps.
OnMapReadyCallback { private GoogleMap googleMap; public MyMapFragment() { getMapAsync(this);
@Override public void onMapReady(final GoogleMap gmap) { this.googleMap = gmap;
// Add a marker in Sydney and move the camera
LatLng vietnam = new LatLng(14.0583, 108.2772); // 14.0583° N, 108.2772° E this.googleMap.addMarker(new MarkerOptions().position(vietnam).title("Marker in Vietnam")); this.googleMap.moveCamera(CameraUpdateFactory.newLatLng(vietnam)); this.googleMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
@Override public void onMapClick(LatLng latLng) {
MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); markerOptions.title(latLng.latitude + " : "+ latLng.longitude);
// Clear previously click position googleMap.clear();
// Zoom the Marker googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 10)); // Add Marker on Map googleMap.addMarker(markerOptions);
Thiết kế giao diện của ứng dụng:
Hình 9.26 Cửa sổ activity_main.xml
Set đặt ID cho các thành phần trên giao diện.
Hình 9.27 Cửa sổ Set đặt ID activity_main.xml
The provided XML code snippet defines a `ConstraintLayout` in an Android application, utilizing namespaces for Android attributes, app-specific resources, and tools It specifies that the layout should match the parent's width and height, indicating a responsive design suitable for various screen sizes This layout serves as the main context for the application, facilitating the arrangement of UI components efficiently within the `MainActivity`.
To integrate a map fragment in your Android application, use the following XML code snippet: `` This code defines the map fragment's ID, layout parameters, and constraints, ensuring it is properly positioned within the parent layout.
MainActivity.java package org.o7planning.mygooglemap; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import androidx.fragment.app.FragmentManager; public class MainActivity extends AppCompatActivity { private MyMapFragment myMapFragment;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
FragmentManager fragmentManager = this.getSupportFragmentManager(); this.myMapFragment = (MyMapFragment) fragmentManager.findFragmentById(R.id.fragment_map);
} Bây giờ bạn có thể chạy ứng dụng:
Hình 9.28 Cửa sổ chạy ứng dụng
Những trọng tâm cần chú ý:
Trình bày được Google Play Service SDK
Trình bày được Google Maps Android API
Thực hiện được cấu hình cho Google Cloud Messaging
Trình bày và thực hiện được Đồ họa trên Google Map
Thực hiện được GoogleMap & Xây dựng Đối tượng
Tạo một project với Google Map
Thực hiện đúng các thao tác lập trình thiết kế, quản lý với Google Map
Bài mở rộng và nâng cao
Tạo ứng dung với Google Map có mộtsố chức năng của như sau:
+ Làm sao biết biết được vị trí hiện tại của ta đểdi chuyển Map đúng vị trí + Cách xoay , quay Map như thế nào
+ Đường đi giữa các địa điểm ra sao…
Yêu cầu đánh giá kết quả học tập
Trình bày được Google Play Service SDK
Trình bày được Google Maps Android API
Thực hiện được cấu hình cho Google Cloud Messaging
Trình bày và thực hiện được Đồ họa trên Google Map
Thực hiện được GoogleMap & Xây dựng Đối tượng
Tạo một project với Google Map
Thực hiện đúng các thao tác lập trình thiết kế, quản lý với Google Map
Thực hiện được cách Đọc ghi dữ liệu JSON
Thực hiện đúng các thao tác thực hiện được cách Đọc ghi dữ liệu XML
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
Về kiến thức: Đánh giá bằng hình thức kiểm tra viết, trắc nghiệm, vấn đáp.
Đánh giá kỹ năng thực hành Thực hiện đúng các thao tác thực hiện được cách Đọc ghi dữ liệu XML
Thực hiện đúng các thao tác Thực hiện đúng các thao tác thực hiện được cách Đọc ghi dữ liệu JSON
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
CÁC ĐIỀU KHIỂN ĐA TRUYỀN THÔNG
MEDIA PLAYER
- Android cung cấp lớp MediaPlayer để quản lý các tác vụ đa truyền thông bao gồm các tập tin âm thanh, hình ảnh, video
- Có thể truy xuất các tập tin media thông qua việc lưu trữ như tài nguyên ứng dụng, bộ nhớ thiết bị, content provider hoặc thông qua URL
- MediaPlayer quản lý các tập tin media và luồng xử lý thông qua một tập các trạng thái sau:
Khởi tạo đối tượng MediaPlayer.
Chuẩn bị bộ thu phát MediaPlayer.
Bắt đầu thực hiện thu phát.
Thực hiện các thao tác Pause và Stop trên tập tin media trong khi đang thu phát
Hoàn thành quá trình thu phát
Android cho phép truy xuất các tập tin âm thanh thông qua nhiều nguồn lưu trữ khác nhau, bao gồm tài nguyên ứng dụng, bộ nhớ thiết bị, content provider và xử lý các luồng URL.
- Có thể đóng gói tập tin Audio vào thư mục res/raw như một dạng tài nguyên của ứng dụng.
- Để thu phát một tập tin Audio cần tạo một đối tượng MediaPlayer và thiết lập nguồn dữ liệu cho đối tượng này
- Thực hiện thu phát bằng phương thức Create() truyền vào 2 tham số: context của ứng dụng và một trong những dạng tài nguyên sau:
Định danh của tài nguyên.
URI trỏ đến nơi lưu trữ của tập tin trên thiết bị.
URI trỏ đến tập tin trực tuyến thông qua URL.
URI trỏ đến dòng dữ liệu trong bảng của content provider.
- Ví dụ tạo đối tượng MediaPlayer
Mediaplayer filePlayer = MediaPlayer.create(appContext,
Uri.parse(file:///sdcard/localfile.mp3));
MediaPlayer urlPlayer = MediaPlayer.create(appContext,
Uri.parse(“http://site.com/audio/audio.mp3”));
MediaPalyer contentPlayer = MediaPlayer.create(appContext,
Settings.System.DEFAULT_RINGTONE_URI);
- Để thực thi việc thu phát tập tin Video cần tạo một màn hình cho việc trình chiếu
Có hai cách để thực hiện công việc này:
Sử dụng thành phần Video View giúp đóng gói các thao tác liên quan đến đối tượng MediaPlayer, bao gồm việc tạo trình chiếu, chuẩn bị và cấp phát tập tin, vào trong thành phần View này.
Xây dựng màn hình hiển thị riêng và gắn kết dữ liệu thông qua đối tượng MediaPlayer
- Để thực thi việc thu phát tập tin Video cần tạo một màn hình cho việc trình chiếu
Có hai cách để thực hiện công việc này:
Sử dụng thành phần Video View giúp đóng gói các thao tác liên quan đến đối tượng MediaPlayer, bao gồm việc tạo trình chiếu, chuẩn bị và cấp phát tập tin, vào trong thành phần View này.
Xây dựng màn hình hiển thị riêng và gắn kết dữ liệu thông qua đối tượng MediaPlayer
- Ví dụ tạo bộ thu phát bằng Video View:
VideoView videoView = (VideoView) findViewById(R.id.surface); videoView.setKeepScreenOn(true); videoView.setVideoPath(“/sdcard/test2.2gp”); if(videoView.canSeekForward()) videoView.seekTo(videoView.getDuration()/2); videoView.start();
- Ví dụ tạo màn hình hiển thị trong Video View:
- Tạo đối tượng Surface Holder để hỗ trợ việc cập nhật các nguồn xử lý bên dưới: public class MyActivity extends Activity implements SurfaceHolder.Callback { private MediaPlayer mediaPlayer;
@Override public void onCreate(Bundle saveInstanceState)
{ super.onCreate(savedInstanceState); setContentView(R.layout.main); mediaPlayer = new MediaPlayer();
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
SurfaceHolder holder = surface.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
- Khởi tạo nội dung của tập tin cần trình chiếu: public void SurfaceCreated(SurfaceHolder holder)
{ try{ mediaPlayer.setDisplay(holder); mediaPlayer.setDataSource(“/sdcard/test2.3gp”); mediaPlayer.prepare(); mediaPlayer.start();
Log.d(“MEDIA_PALYER”, e.getMessage()); catch(IllegalStateException e){ Log.d(“MEDlA_PALYER”, e.getMessage());
1.4 Các điều khiển trên MediaPlayer
- Khởi chạy đối tượng bằng phương thức start()
Mediaplayer mediaplayer = new MediaPlayer(); mediaPlayer.start();
The MediaPlayer offers various control methods, including getDuration, getCurrentPosition, and seekTo To start playback, use mediaPlayer.start() You can retrieve the current position with int pos = mediaPlayer.getCurrentPosition() and the total duration with int duration = mediaPlayer.getDuration() To seek forward, implement mediaPlayer.seekTo(pos + (duration - pos) / 10) After waiting for a specific duration, you can stop playback with mediaPlayer.stop().
Một số phương thức hỗ trợ âm thanh như chống khóa màn hình trong quá trình thu phát và thiết lập chế độ phát lại rất quan trọng Để thiết lập chế độ phát lại cho tập tin media, bạn có thể sử dụng phương thức isLooping() và setLooping() Ví dụ, để bật chế độ lặp cho mediaPlayer, bạn có thể sử dụng đoạn mã: if (!mediaPlayer.isLooping()) mediaPlayer.setLooping(true);
Thiết lập Wake Clock giữ cho màn hình luôn mở khi đang phát bằng phương thức setScreenOnWhilePlaying()
Ví dụ: mediaPlayer.setSreenOnWhilePlaying(true);
Điều khiển âm thanh bằng phương thứ setVolume()
THU ÂM THANH VÀ HÌNH ẢNH (RECODING)
- Android cung cấp 2 lựa chọn trong việc thu âm thanh và hình ảnh:
Sử dụng Intent để khởi chạy ứng dụng Video Camera cho phép người dùng chỉ định nơi lưu trữ, định dạng và chất lượng của hình ảnh thu được.
Sử dụng lớp Media Recoder để xây dựng các thành phần UI, các thiết lập record cho ứng dụng.
Sử dụng Intent để thu hình ảnh:bằng cách truyền action
ACTION_VIDEO_CAPTURE vào một Intent và gửi Intent này đến một Activity khác xử lý và trả về kết quả thu được.
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); startActivityForResult(intent, RECORD_VIDEO);
- MediaStore hổ trợ hai URI cho phép lựa chọn trong quá trình thu hình ảnh:
EXTRA_OUPUT: cho phép tùy chọn nơi lưu trữ.
EXTRA_VIDEO_QUALITY: cho phép tùy chọn chất lượng hình ảnh thu được.
To utilize Intent for capturing images in Android, you can define constants such as `private static int RECORD_VIDEO = 1;`, `private static int HIGH_VIDEO_QUALITY = 1;`, and `private static int MMS_VIDEO_QUALITY = 0;` Implement the method `private void recordVideo(Uri outputPath)` to initiate video recording, ensuring that the output path is correctly specified for saving the recorded video.
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); if(outputpath != null)
Intent.putExtra(MediaStore.EXTRA_OUTPUT, output);
Intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, HIGH_CIDEO_QUALITY); startActivityForResult(intent, RECORD_VIDEO);
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == RECORD_VIDEO){
- Sử dụng Media Recorder để thu âm thanh và hình ảnh: cần tạo đối tượng thuộc lớp MediaRecoder để sử dụng
Cần đăng ký quyền sử dụng cho ứng dụng trong file AndroidManifest.xml
- MediaRecoder quản lý các tập tin media và luồng xử lý thông qua một tập các trạng thái sau:
Khởi tạo đối tượng MediaPlayer.
Chỉ định nguồn vào của thiết bị thu
Thiết lập định dạng của tập tin đầu ra.
Thiết lập các chỉ sốnhư: bộ mã hóa, chất lượng hình ảnh, dung lượng xuất ra
Chọn tập tin để xuất
Chuẩn bị thu âm & hình ảnh.
Tiến hành thu âm & hình ảnh.
Hoàn thành quá trình thu
// C ấ u hình các thông tin đâu vào mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mediaRecorder.setVideoSource(mediaRecorder.VideoSource.CAMERA);
// Thi ế t L ập đị nh d ạng các thông tin đâu ra mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
//Ch ỉ đị nh mâ hóa audio và video mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
// Ch ỉ đị nh t ập tin đâu ra mediaRecorder.setOutputFile(“ /sdcard/taptinxuatra.mp4”);
Tiến hành thu, dừng thu và giải phóng tài nguyên mediaRecorder.start();
Tạo màn hình Preview trong lúc record public class MyActivity extends Activity implements SurfaceHolder.Callback { private MediaRecorder mediaRecorder;
@Override public void onCcreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState); setContentView(R.layout.main);
Surfaceview surface = (Surfaceview) findViewByld(R.id.surface);
SurfaceHolder holder = surface.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); holder.setFixedSize(400, 300);
} public void surfaceCreated(SurfaceHolder holder)
To set up a media recorder for video and audio capture, initialize the audio source with MediaRecorder.AudioSource.MIC and the video source with MediaRecorder.VideoSource.CAMERA Configure the output format using MediaRecorder.OutputFormat.DEFAULT, and select the audio and video encoders with MediaRecorder.AudioEncoder.DEFAULT and MediaRecorder.VideoEncoder.DEFAULT, respectively Specify the output file path as "/sdcard/taptinxuatra.mp4" and set the preview display to the holder's surface Finally, prepare the media recorder for use.
} catch(IllegalArgumentException e){ Log.d(“MEDlA_PALYER”, e.getMessage());
} catch(IOException e) { Log.d(“MEDIA_PALYER”, e.getMessage());
CAMERA
3.1 Điều khiển chụp hình với Camera
- Sử dụng Intent để gửi hành động ACTION_IMAGE_CAPTURE đến activity xử lý và nhận kết quả trả về.
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, TAKE_PICTURE);
Hành động CAPTURE cung cấp hai kiểu hình ảnh: Thumbnail, là định dạng ảnh bitmap cho người dùng xử lý trong ứng dụng, và FullImage, cho phép sử dụng URI để lấy ảnh hoàn chỉnh và lưu trữ trong MediaStore.
- Ví dụ sử dụng Intent để lấy về dữ liệu của ACTION IMAGE CAPTURE private static int TAKE_PICTURE = 1; private Uri outputFileUri; private void getThumbailPicture()
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File file=new File(Enviroment.getExternalStorageDicrectory(), “hinh.jpg”); outputFileUri = Uri.fromFile(file); intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri); startActivityForResult(intent, TAKE_PICTURE);
- Nhận kết quả trả về và xử lý
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data)
//Ki ể m tra n ế u k ế t quà bao g ồ m 1 thumba ỉ L Bitmap if(data != null){ if(data.hasExtra(“data”)){
Bitmap thumbail = data.getParcelableExtra(“data”);
- Cần đăng ký trong file AndroidManifest để sử dụng Camera:
- Khởi tạo đối tượng Camera để tùy chỉnh và sử dụng: Camera camera Camera.open();
[ Làm việc với camera ] camera.release();
- Tùy chỉnh Camera thông qua đối tượng của Parameter trong lớp Camera:
Camera.Parameters parameters = camera.getParameters();
- Một số thiết lập đối tượng Parameter o [get/set]ScreenMode o [get/set]FlashMode o [get/set]WhiteBalance o [get/set]ColorEffect o [get/set]FocusMode
- Tạo màn hình Preview public class MyActivity extends Activity implements SurfaceHolder.Callback { private MediaRecoder mediaRecoder;
@Override public void onCreate(Bundle savedInstanceState)
Super.onCreate(savedInstanceState); setContentView(R.layout.main);
SurfaceView surface = (SurfaceView) findViewById(R.id.surface);
SurfaceHolder holder = surface.getHolder(); holder.addCallback(this); holder.setFixedSize(400, 300);
} public void surfaceCreate(SurfaceHolder holder)
{ try { camera = camera.open(); camera.setPreviewDisplay(holder); camera.starPreview();
[ draw on surface ] } catch (lOException e) { Log.d(“CAMERA”, e.getMessage());
} public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); camere.release();
- Ví dụ tiến hành chụp ảnh và lưu trên SDCard private void takePicture() { camera.takePicture(shutterCallback, rawCallback, jpegCallback); } shutterCallback shutterCallback = new ShutterCallback()
- Ví dụ tiến hành chụp ảnh và lưu trên SDCard pictureCallback jpegCallback = new PictureCallback()
{ public void onPictureTaken(byte[] data, Camera camera)
//Lưu dữ Li ệ u hình vào SD Card
FileOutputStream outStream = null; try { outStream = new FileOutputStream(“ /sdcard/ hinh.jpg”); outStream.write(data); outStream.close();
} catch(FileNotFoundException e) { Log.d(“CAMERA”, e.getMessage());
} catch(llOException e) { Log.d(“CAMERA”, e.getMessage());
3.2 Lưu tập tin Media vào MediaStore
- Có thể lưu tập tin media vào MediaStore bằng 2 cách:
Sử dụng MediaScanner để thông dịch tập tin vào thêm vào một cách tự động
Thêm mới vào một record trong một Content Provider thích hợp.
- Ví dụ tạo MediaScanner để thêm tập tin media
{ msc = new MediaScannerConnection(getApplicationContext(), this); msc.connect ();
} public void onMediaScannerConnected(){ msc.scanFile(“
} public void onScanCompleted(String path, Uri uri){ msc.disconnect();
- Ví dụ thêm media bằng Content Provider
Content.put(Audio.AudioColumns.TITLE, “TrheSoundandtheFury”);
Content.put(Audio.AudioColumnd.DATE_ADDED,
Content.put(Audio.Media.MIME_TYPE, “audio/ amr”);
Uri uri resolver.insert(mediaStore.Video.Media.EXTERNAL_CONTENT_URI, content);
Bài tập thực hành của sinh viên
1 Trình bày được Xây dựng MediaPlayer Audio
2 Trình bày được Xây dựng MediaPlayer Video
3 Trình bày và thực hiện Các điều khiển trên MediaPlayer
4 Thực hiện được thu âm thanh và hình ảnh (recoding)
5 Tạo một project vớiLưu tập tin Media vào MediaStore
6 Xây dựng ứng dụng xử lý media player trong android cho phép bạn phát một bài hát (Play), dừngmột bài hát (Pause), …
Hình 10.1 Giao diện Music Palyer
1 Trình bày được Xây dựng MediaPlayer Audio, tham khảo ở mục 1.2 trong bài 10 của giáo trình
2 Trình bày được Xây dựng MediaPlayer Video, tham khảo ở mục 1.3 trong bài 10 của giáo trình
3 Trình bày và thực hiện Các điều khiển trên MediaPlayer, tham khảo ở mục 1.4 trong bài 10 của giáo trình
4 Tạo một project vớiLưu tập tin Media vào MediaStore, tham khảo ở mục 3.2 trong bài 10 của giáo trình
5 Xây dựngứng dụng xử lý media player trong android cho phép bạn phát một bài hát (Play), dừngmột bài hát (Pause), … tạo mới project trong Android Studio và thực hiện các bước sau
Bước 1: Tạo thư mục tên raw và copy file nhạc vào thư mục này
Chuột phải package -> chọn New -> chọn Android resource directory
Hình 10.2 Android resource directory Nhập tên thư mục là raw tại Directory name và chỉ định raw tại Resource type
Hình 10.3 Tạo và chỉ định raw Copy file nhạc vào thư mục raw
Bước 2: Tạo activity và đặt tên MediaPlayerActivity
Tải hình và đặt vào thư mục drawable
Hình 10.4 Tải hình và đặt vào thư mục drawable
The MediaPlayerActivity class in Android extends AppCompatActivity and includes essential components for media playback, such as ImageButtons for play, pause, forward, and backward controls It utilizes a MediaPlayer instance to handle audio playback, with variables to track the start and final times of the media The class features a Handler for updating the UI, along with a SeekBar for navigation and TextViews to display the current status, start time, final time, and song name Additionally, it defines constants for time manipulation, allowing users to skip forward or backward by 5 seconds.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_media_player);
// Tham chiếu id của các View
// tvSongName.setText("Nguoi Mien Tay"); mediaPlayer = MediaPlayer.create(this,R.raw.nguoi_mien_tay); seekbar=(SeekBar)findViewById(R.id.seekBar); seekbar.setClickable(false); btnPause.setEnabled(false);
} private Runnable UpdateSongTime = new Runnable() { public void run() { startTime = mediaPlayer.getCurrentPosition(); tvStartTime.setText(String.format("%d min, %d sec",
TimeUnit.MILLISECONDS.toMinutes((long) startTime),
TimeUnit.MILLISECONDS.toSeconds((long) startTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS toMinutes((long) startTime)))
); seekbar.setProgress((int)startTime); myHandler.postDelayed(this, 100);
}; public void playAction(View view){ tvStatus.setText("Playing sound"); mediaPlayer.start(); finalTime = mediaPlayer.getDuration(); startTime = mediaPlayer.getCurrentPosition(); if (oneTimeOnly == 0) { seekbar.setMax((int) finalTime); oneTimeOnly = 1;
} tvFinalTime.setText(String.format("%d min, %d sec",
TimeUnit.MILLISECONDS.toMinutes((long) finalTime),
TimeUnit.MILLISECONDS.toSeconds((long) finalTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) finalTime)))
); tvStartTime.setText(String.format("%d min, %d sec",
TimeUnit.MILLISECONDS.toMinutes((long) startTime),
TimeUnit.MILLISECONDS.toSeconds((long) startTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) startTime)))
); seekbar.setProgress((int)startTime); myHandler.postDelayed(UpdateSongTime,100);
} public void pauseAction(View v) { tvStatus.setText("Pausing sound"); mediaPlayer.pause();
} public void forwardAction(View v) { int temp = (int)startTime; if((temp+forwardTime)0){ startTime = startTime - backwardTime; mediaPlayer.seekTo((int) startTime); tvStatus.setText("You have Jumped backward 5 seconds");
} else{ tvStatus.setText("Cannot jump backward 5 seconds");
} Bước 3: Đăng ký sự kiện onClick cho các button
Hình 10.6 onClick cho các button
7 Tạo mới một p roject có tên AndroidCameraDemo
File > New > New Project > Empty Activity
Package name: org.o7planning.androidcamerademo
Thêm cấu hình cho phép đọc và ghi dữ liệu trên thiết bị
AndroidManifest.xml
Hình 10.7 Thiết kế giao diện
Nếu bạn quan tâm tới các bước để thiết kế giao diện ứng dụng này hãy xem phần phụ lục phía cuối bài viết activity_main.xml
The provided XML code defines a `ConstraintLayout` in an Android application, specifying the layout's width and height to match the parent container It includes necessary XML namespaces for Android attributes, application-specific properties, and tools context, ensuring proper functionality within the MainActivity.
To create an ImageView in Android, use the following XML layout code: `` This code specifies the dimensions, margins, and constraints for the ImageView, ensuring it is properly aligned within the parent layout.
To create a responsive video view in your Android layout, use the following XML code snippet: `` This configuration ensures the video view is properly aligned and spaced within the parent layout, enhancing the overall user interface.
The LinearLayout is designed with a width of 0dp and a height set to wrap its content, ensuring it adapts to the size of its children It features margins of 16dp on all sides, providing adequate spacing from adjacent elements The layout is oriented horizontally and is constrained to the parent layout, aligning its start and end edges to the parent’s edges and positioned below a video view.
In the MainActivity.java file of the Android Camera Demo application, essential imports include AppCompatActivity, ActivityCompat, and various Android components for handling media The class defines buttons for capturing images and videos, alongside a VideoView and an ImageView for displaying the captured content It also establishes request codes for read/write permissions, image capture, and video capture, ensuring the app can manage user permissions effectively This setup is crucial for creating a seamless user experience in capturing and displaying media within the app.
In the onCreate method of the activity, the layout is set using setContentView with the main activity's layout The buttons for image and video, as well as the VideoView and ImageView, are initialized by finding their respective IDs An OnClickListener is set for the image button, which triggers the captureImage method when clicked.
}); this.buttonVideo.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { askPermissionAndCaptureVideo();
// Create an implicit intent, for image capture
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Start camera and wait for the results this.startActivityForResult(intent, REQUEST_ID_IMAGE_CAPTURE);
// With Android Level >= 23, you have to ask the user
// for permission to read/write data on the device if (android.os.Build.VERSION.SDK_INT >= 23) {
// Check if we have read/write permission int readPermission = ActivityCompat.checkSelfPermission(this,
Manifest.permission.READ_EXTERNAL_STORAGE); int writePermission = ActivityCompat.checkSelfPermission(this,
To ensure proper access to external storage, check if the WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permissions are granted If either permission is not granted, prompt the user to allow these permissions by requesting them with the appropriate code.
REQUEST_ID_READ_WRITE_PERMISSION
// Create an implicit intent, for video capture
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
File dir = Environment.getExternalStorageDirectory(); if (!dir.exists()) { dir.mkdirs();
// file:///storage/emulated/0/myvideo.mp4
String savePath = dir.getAbsolutePath() + "/myvideo.mp4";
File videoFile = new File(savePath);
Uri videoUri = Uri.fromFile(videoFile);
// Specify where to save video files intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());
// You may get an Error (**) If your app targets API 24+
// "android.os.FileUriExposedException: file:///storage/emulated/0/xxx exposed beyond app through "
// Explanation: https://stackoverflow.com/questions/38200282
// Start camera and wait for the results this.startActivityForResult(intent, REQUEST_ID_VIDEO_CAPTURE); // (**)
Toast.makeText(this, "Error capture video: " +e.getMessage(),
Toast.LENGTH_LONG).show(); e.printStackTrace();
// When you have the request results
@Override public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // switch (requestCode) { case REQUEST_ID_READ_WRITE_PERMISSION: {
// Note: If request is cancelled, the result arrays are empty
// Permissions granted (read/write) if (grantResults.length > 1
Toast.makeText(this, "Permission granted!",
Toast.LENGTH_LONG).show(); this.captureVideo();
Toast.makeText(this, "Permission denied!",
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_ID_IMAGE_CAPTURE) { if (resultCode == RESULT_OK) {
Bitmap bp = (Bitmap) data.getExtras().get("data"); this.imageView.setImageBitmap(bp);
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Action canceled", Toast.LENGTH_LONG).show(); } else {
Toast.makeText(this, "Action Failed", Toast.LENGTH_LONG).show(); }
} else if (requestCode == REQUEST_ID_VIDEO_CAPTURE) { if (resultCode == RESULT_OK) {
Log.i("MyLog", "Video saved to: " + videoUri);
Toast.makeText(this, "Video saved to:\n" + videoUri, Toast.LENGTH_LONG).show(); this.videoView.setVideoURI(videoUri); this.videoView.start();
} else if (resultCode == RESULT_CANCELED) {
Toast.makeText(this, "Action Cancelled.",
Toast.makeText(this, "Action Failed",
} Ứng dụng sẽ lưu video xuống SD Card của thiết bị giả lập (Emulator), vì vậy hãy đảm bảo rằng bạn đã thiết lập SD Card
Thiết lập SD Card cho Android Emulator
OK, bây giờ bạn có thể chạy ứng dụng Ởđây tôi chạy ứng dụng trên thiết bị mô phỏng với Camera cũng là camera mô phỏng
Thêm ImageView, VideoView vào giao diện
Hình 10.9 Thêm ImageView, VideoView vào giao diện Thêm ImageView
Hình 10.10 Thêm ImageView Thêm các Button vào giao diện.
Hình 10.11 Thêm các Button vào giao diện
Set đặt ID, Text cho các thành phần trên giao diện.
Những trọng tâm cần chú ý:
Trình bày được Xây dựng MediaPlayer Audio
Trình bày được Xây dựng MediaPlayer Video
Trình bày và thực hiện Các điều khiển trên MediaPlayer
Thực hiện được thu âm thanh và hình ảnh (recoding)
Tạo một project với Lưu tập tin Media vào MediaStore
Xây dựng ứng dụng xử lý media player trong android cho phép bạn phát một bài hát (Play), dừng một bài hát (Pause), …
Tạo mới một project có tên AndroidCameraDemo
Bài mở rộng và nâng cao
1 Media player trong android – Viết một ứng dụng nghe nhạc cho phép nghe nhạc từ một list
2 Sau đây là ví dụ cụ thể sử dụng MediaPlayer để play video trong ứng dụng
3 Xây dựng chức năng Cho phép sử dụng Camera để chụp ảnh
Yêu cầu đánh giá kết quả học tập
Trình bày được Xây dựng MediaPlayer Audio
Trình bày được Xây dựng MediaPlayer Video
Trình bày và thực hiện Các điều khiển trên MediaPlayer
Thực hiện được thu âm thanh và hình ảnh (recoding)
Tạo một project với Lưu tập tin Media vào MediaStore
Xây dựng ứng dụng xử lý media player trong android cho phép bạn phát một bài hát (Play), dừng một bài hát (Pause), …
Tạo mới một project có tên AndroidCameraDemo
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
Về kiến thức: Đánh giá bằng hình thức kiểm tra viết, trắc nghiệm, vấn đáp.
Tạo một project với Lưu tập tin Media vào MediaStore
Xây dựng ứng dụng xử lý media player trong android cho phép bạn phát một bài hát (Play), dừng một bài hát (Pause), …
Tạo mới một project có tên AndroidCameraDemo
Năng lực tự chủ và trách nhiệm: Tỉ mỉ, cẩn thận, chính xác, linh hoạt và ngăn nắp trong công việc.
TELEPHONE & SMS VÀ BỘ CẢM BIẾN
TELEPHONE
- Tạo cuộc gọi bằng các sử dụng Intent để gọi Dialer có sẵn trong thiết bị Ví dụ:
Intent intent = new Intent(Intetn.ACTION_DIAL, Uri.parse(“tel:123456”)); startActivity(intent);
- Thực hiện hành động gọi ACTION_CALL bằng cách nhấn nút Call trong thiết bị.
- Một số thông tin cần thiết cho việc quản lý chức năng Phone trên thiết bị:
- Để truy xuất được các thông tin này cần thực hiện đăng ký trong AndroidManifest.xml
- Việc truy xuất quản lý bởi lớp TelephonyManager với phương thức getSystemService()
String srvcName = Context.TELEPHONY_SERVICE;
To retrieve the phone type in an Android application, use the TelephonyManager service by calling `getSystemService(srvcName)` After obtaining the TelephonyManager instance, invoke `getPhoneType()` to determine the device's phone type The possible cases include PHONE_TYPE_CDMA, PHONE_TYPE_GSM, and PHONE_TYPE_NONE, allowing for specific handling based on the detected phone type.
String phoneNumber = telephonyManager.getLine1Number();
- Quản lí trạng thái: o Ví dụ: class MyPhoneStateListener extends PhoneStateListener
The method `onCallStateChanged(int state, String incomingNumber)` is overridden to handle different call states It calls the superclass method and uses a switch statement to determine the current state of the call The states include `CALL_STATE_IDLE`, `CALL_STATE_RINGING`, and `CALL_STATE_OFFHOOK`, with specific actions to be defined for each state.
To read connection data and status changes, utilize the methods getDataSet() and getDataActivity() from the TelephonyManager The current data activity can be retrieved with `int dataActivity = telephonyManager.getDataActivity();` and the data state with `int dataState = telephonyManager.getDataState();` Depending on the value of dataActivity, different cases can be handled: DATA_ACTIVITY_INT, DATA_ACTIVITY_OUT, DATA_ACTIVITY_INOUT, and DATA_ACTIVITY_NONE.
Đọc các dữ liệu Network cần thiết:
To obtain the network operator name and type in Android, use the TelephonyManager class The network operator name can be retrieved with `telephonyManager.getNetworkOperatorName()`, while the network type is obtained through `telephonyManager.getNetworkType()` A switch statement can be employed to handle various network types, such as NETWORK_TYPE_1xRTT, NETWORK_TYPE_CDMA, NETWORK_TYPE_EDGE, NETWORK_TYPE_EVDO_0, NETWORK_TYPE_EVDO_A, NETWORK_TYPE_GPRS, NETWORK_TYPE_HSDPA, NETWORK_TYPE_HSPA, NETWORK_TYPE_HSUPA, NETWORK_TYPE_UMTS, and NETWORK_TYPE_UNKNOWN, ensuring proper management of each case.
Đọc các dữ liệu SIM: int simState = telephonyManager.getSimState(); switch (simState) { case case case case case case
(TelephonyManager.SIM_STATE_ABSENT): break;
(TelephonyManager.SIM_STATE_NETWORK_LOCKED): break;
(TelephonyManager.SIM_STATE_PIN_REQUIRED): break;
(TelephonyManager.SIM_STATE_PUK_REQUIRED): break;
(TelephonyManager.SIM_STATE_UNKNOWN): break;
String simOperatorName =telephonyManager.getSimOperatorName(); String simSerial = telephonyManager.getSimSerialNumber(); break;
Các thay đôi trạng thái Phone được quản lý bởi lớp PhoneStateListener
The PhoneStateListener class in Android allows developers to monitor various phone state changes Key methods include onCallForwardingIndicatorChanged(boolean cfi) for tracking call forwarding status, onCallStateChanged(int state, String incomingNumber) for detecting changes in call state, and onCellLocationChanged(CellLocation location) to update cell location information Additionally, it provides onDataActivity(int direction) to observe data activity, onDataConnectionStateChanged(int state) for monitoring data connection states, and onMessageWaitingIndicatorChanged(boolean mwi) to check for message waiting indicators The listener also includes onServiceStateChanged(ServiceState serviceState) to manage service state changes and onSignalStrengthChanged(int asu) for monitoring signal strength variations.
Cần đăng ký với Telephony Manager để khởi tạo các sự kiện muốn lắng nghe để xử lý: telephonyManager.listen(phoneStateListener,
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR|
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |
Hủy đăng ký bằng LISTEN NONE telephonyManager.listen(phoneStateListener,
- Xây dựng ứng dụng thay thế ứng dụng cuộc gọi có sẵn trong ứng dụng Bao gồm 2 bước:
Chặn những Intent đến của ứng dụng Dialer và xử lý.
Tổ chức quản lí các cuộc gọi ra bên ngoài
- Cần đăng ký các Intent cho Activity xử lý:
- Ví dụ đăng kí trong Intent trong AndroidManifest
caction android:name = “android.intent.action.CALL_BUTTON”/> ccategory android:name = “android.intent.category.DEFAULT”/
The provided Android intent configuration includes actions for viewing and dialing, categorized under default and browsable categories, with data scheme set to "tel".
- Ví dụ xử lý cuộc gọi tới phoneStateListner callStateListener = new PhoneStateListner()
{ public void onCallStateChanged( int state, String incomingNumber)
}; telephonyManager.listen(callStateListener, phoneStateListener.LISTEN_CALL_STATE;
SMS 248 3 Giới thiệu sơ lược về cảm biến
- Gửi tin nhắn bằng cách tạo một Intent để gọi ứng dụng Message trong thiết bị.
Intent(Intent.ACTION_SENDTO,Uri.parse(“sms:123456”)); smslntent.putExtra(“sms_body”, “Press send to send me”); startActivity(smsIntent);
- Gửi tin nhắn MMS có chứa tập tin Media.
Uri attached_Uri = Uri.parse("content://media/external/images/media/1");
To send an image via MMS in an Android application, create an intent with `Intent.ACTION_SEND` and attach the image URI Include a message body with the text "Please see the attached image" and specify the recipient's phone number, such as "07912355432" Set the intent type to "image/png" and add the image URI using `Intent.EXTRA_STREAM` Finally, initiate the activity with `startActivity(mmsIntent)`.
- SMS tin nhắn được điều khiển bởi SmsManager o Tạo đối tượng SmsManager
Yêu cầu quyền truy cập khi gửi tin nhắn
- Việc gửi tin nhắn được thực hiện bởi phương thức sendTextMessage của lớp SmsManager
Cú pháp: sendTextMessage(Stringdestination Address,
String myMessage = “Android supports programmatic SMS messaging!”; smsManager.sendTextMessage(sendTo, null, myMessage, null, null);
Để theo dõi và xác nhận tình trạng SMS đã được gửi, bạn cần đăng ký BroadcastReceiver để lắng nghe các hoạt động từ Pending Intent được tạo ra khi gửi tin nhắn BroadcastReceiver sẽ nhận thông báo khi tin nhắn được gửi thành công hoặc gặp lỗi.
■ SmsManager.RESULT_ERROR_GENERIC_FAILURE
■ SmsManager.RESULT_ERROR_RADIO_OFF
■ SmsManager.RESULT_ERROR_NULL_PDU o deliverylntent được gọi lên một khi thiết bị đích nhận được tin nhắn.
- Ví dụ về kiểm soát gửi tin nhắn o Tạo Pending Intent
String SENT_SMS_ACTION = "SENT_SMS_ACTION " ;
String DELIVERED_SMS_ACTION = "DELIVERED_SMS_ACTION " ;
Intent sentIntent = new Intent(SENT_SMS_ACTION);
PendingIntent sentPI = PendingIntent.getBroadcast(getApplicationContext(),0, sentIntent,0); Intent deliveryIntent = new Intent(DELIVERED_SMS_ACTION); PendingIntent deliverPI PendingIntent.getBroadcast(getApplicationContext(),0, deliveryIntent,0);
Tạo Broadcast Receiver cho Send Action registerReceiver(new
In the `onReceive` method, the code handles different result codes from an SMS operation It checks for `Activity.RESULT_OK` to confirm successful transmission Additionally, it accounts for various error scenarios, including `SmsManager.RESULT_ERROR_GENERIC_FAILURE`, `SmsManager.RESULT_ERROR_RADIO_OFF`, and `SmsManager.RESULT_ERROR_NULL_PDU`, ensuring robust error handling in SMS management.
}, new IntentFilter(SENT_SMS_ACTION));
Tạo Broadcast Receiver cho Delivery Action registerReceiver(new
@Override public void onReceive(Context _context, Intent _intent){
}, new IntentFilter(DELIVERED_SMS_ACTION)); smsManager.sendTextMessage(sendTo, null, myMessage, sentPI, deliverPI);
- Xử lý các tin nhắn dài hơn 160 ký tự bằng phương thức divideMessage() và sendMultipartTextMessage()
Cú pháp: sendMultipartTextMessage(Stringdestination Address, String scAddress, ArrayList parts, ArrayList sentIntents, ArrayList deliveryIntents)
ArrayList messageArray = smsManager.divideMessage(myMessage); ArrayList sentIntents = new ArrayList(); for (int i 0; i < messageArray.size(); i++) sentIntents.add(sentPI); smsManager.sendMultipartTextMessage(sendTo,null,messageArray, sentIntents,null);
- Gửi tin nhắn chứa dữ liệu bằng mảng byte
Cú pháp: sendDataMessage(Stringdestination Address, String scAddress, short destination
Port, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent)
Intent sentIntent = new Intent(SENT_SMS_ACTION);
PendingIntent sentPI PendingIntent.getBroadcast(getApplicationContext(),0,sentIntent,0); short destinationPort = 80; byte[] data = [ your data ]; smsManager.sendDataMessage(sendTo,null,destinationPort,data, sentPI,null);
- Để ứng dụng nhận được SMS, cần đăng ký: o BroadcastReceiver với action
caction android:name="android.provider.Telephony.SMS_RECEIVED"/>
Cung cấp quyền truy cập nhận SMS tin nhắn
- Ví dụ tạo Broadcast Receiver để nhận tin nhắn public class MySMSMonitor extends BroadcastReceiver
{ private static final String ACTION “android.provider.Telephony.SMS_RECEIVED”; @Override public void onReceive(Context context, Intent intent)
{ if(intent != null && intent.getAction() != null &&
Object[] pduArray = (Objectp[] intent getExtras() get(“pdus”); SmsMessage[] messages = new SmsMessage[pduArray.length]; for( int i = 0; i < pduArray.length; i++) { Messages[i] = SmsMessage.createFromPdu((byte[])pduArray[i]);
Log.d(“MySMSMonitor”, “From: ” + messages[i].getOriginatingAddress());
Log.d(“MySMSMonitor”, “Msg: ” + messages[i].getMessageBody()); Log.d(“MySMSMonitor”, “SMS Message Received”);
- Làm việc với các thư mục tin nhắn, cần đăng ký quyền trong AndroidManifest.xml }
- Thực hiện truy vấn để lấy ra các thông tin về tin nhắn trong các thư mục với URI tương ứng: All: content://sms/all
In this example, we demonstrate how to retrieve SMS messages from the Inbox using the SMSlnboxDemo class, which extends ListActivity The class utilizes a ListAdapter to display the messages, and it accesses the SMS Inbox content through the URI: content://sms/inbox.
@Override public void onCreate(Bundle bundle)
Cursor c = getContentResolver().Query(SMS_INBOX,null,null,null, null); startManagingCursor(c);
String[] colums = new String[] {“body”}; int[] names = new int[] {R.id.row}; adapter=new SimpleCursorAdapter(this,R.layout.sms_inbox,c, colums, names); setListAdapter(adapter);
3 Giới thiệu sơ lược về cảm biến
Cảm biến là phần cứng tích hợp trong các thiết bị, có chức năng chuyển đổi các hành động từ thế giới thực thành dữ liệu cho ứng dụng hoạt động trên thiết bị.
- Các hành động trong cảm biến được thực hiện một chiều và chúng chỉ cho phép thực hiện các hành động mặc định sẵn (trừ NFC).
- GPS cũng là một bộ cảm biến nhưng không được tích hợp vào nền tảng cảm biến trong Android
- Các loại cảm biến có thể có trong một thiết bị:
Near Field Communication Sensor (Android 2.3)
- Có 2 cách để nhận biết thiết bị hổ trợ những loại cảm biến nào:
Sử dụng đối tượng thuộc lớp SensorManager để thực hiện thao tác lấy về danh sách các loại cảm biến trên thiết bị.
Thiết lập trong tập tin AndroidManifest để chỉ định các tính năng thiếtbị cần có cho ứng dụng. uses-feature android:name= “android.hardware.sensor.proximity”/>
- Ví dụ lấy thông tin cảm biến trên thiết bị thông qua SensorManager:
SensorManager mgr = (SensorManager)this.getSystemService(SENSOR_SERVICE); List sensors = mgr.getSensorList(Sensor.TYPE_ALL);
StringBuilder message = new StringBuilder(2048); message.append("The sensors on this device are:\n"); for(Sensor sensor : sensors) { message.append(sensor.getName() + "\n"); message.append(" Type: " + sensorTypes.get(sensor.getType()) +
"\n"); message.append("Vendor: " + sensor.getVendor() + "\n"); message.append(" Version: " + sensor.getVersion() + "\n"); message.append(" Resolution: " + sensor.getResolution() + "\n"); message.append(" Max Range: " + sensor.getMaximumRange() + "\n"); message.append(" Power: " + sensor.getPower() + " mA\n");
Lấy thông tin và điều khiển cảm biến
- Cần đăng ký một bộ lắng nghe (Listener) sự thay đổi của cảm biến để thực hiện lấy các thông tin.
To create a class that implements the SensorEventListener interface, you can define it as follows: `public class MainActivity extends Activity implements SensorEventListener` Within this class, initialize the SensorManager, declare a Sensor for light detection, and set up a TextView to display data Additionally, use a StringBuilder with a capacity of 2048 to manage messages efficiently.
@Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); mgr = (SensorManager) this.getSystemService(SENSOR_SERVICE); light mgr.getDefaultSensor(Sensor.TYPE_LIGHT); text = (TextView) findviewById(R.id.text);
- Override các onResume và onPause để thực hiện các thiết lập trên cảm biến.
- Ví dụ: đăng ký và hủy đăng ký bộ lắng nghe
@Override protected void onResume(){ mgr.registerListener(this, light,
SensorManager.SENSOR_DELAY_NORMAL); super.onresume();
{ mgr.unregisterListener(this, light); super.onPause();
- Trong phương thức registrerListener() ta thiết lập thông số để nắm bắt các giá trị thay đổi của cảm biến
- Theo dõi các hoạt động của cảm biến
-Ví dụ: thực hiện callback 2 phương thức onAccuracyChanged() và onSensorChanged() public void onAccuracyChanged(Sensor sensor, int accuracy)
{ msg.insert(0, sensor.getName() + “accuracy changed: “ + accuracy +
(MED)”:“(HIGH)”))+“\n”); text.setText(msg); text.invalidate();
} public void onSensorChangeed(SensorEvent event)
{ msg.insert(0, “Got a sensor event: “ + event.values[0] + “SI lux units\n”); text.setText(msg); text.invalidate();
- Một số vấn đề phát sinh khi sử dụng Cảm biến
Phương thức onAccuracyChanged() sẽ được gọi lại mỗi khi một loại cảm biến được sử dụng và được thiết lập thông số cao nhất.
Khó khăn trong việc truy cập trực tiếp các giá trị của cảm biến theo thời gian yêu cầu phải sử dụng các phương thức API của driver cảm biến và thiết lập lại giao diện.
Tốc độ truy xuất dữ liệu của cảm biến hiện tại không đủ nhanh để đáp ứng một số tác vụ nhất định Tuy nhiên, có thể tùy chỉnh tốc độ này thông qua các phương thức có sẵn trong thư viện bằng cách sử dụng cơ chế JNI.
Android 2.1 không hổ trợ duy trì các cảm biến khi màn hình hiển thị tắt.
5 XỬ LÝ THÔNG TIN MỘT SỐ CẢM BIẾN
Cảm biến gia tốc là thiết bị quan trọng giúp thu nhận và đo lường các thay đổi về hướng và vị trí trong không gian, liên quan chặt chẽ đến trọng lực và các lực tác động lên thiết bị.
Các thông số trên các trục x, y, z sẽ được tổng hợp và chuyển đổi thành một giá trị duy nhất là Rotation khi thiết bị thay đổi trạng thái phương hướng.
- Ví dụ sử dụng cảm biến gia tốc
SensorManager sm (SensorManager)getSystemService(Context.SENSOR_SERVICE); Int sensorType = Sensor.TYPE_ACCELEROMATER;
Sm.registerListener(mySennorEventListener, sm.getDefaultSensor(sensorType),
The SensorManager detects changes in sensor data, specifically for the accelerometer type When the sensor data changes, the SensorEventListener captures the values along the x-axis, y-axis, and z-axis, allowing for real-time monitoring of lateral, longitudinal, and vertical acceleration.
5.2 Near Field Communacation Sensor (NFC)
NFC (Giao tiếp tầm ngắn) là công nghệ cho phép các thiết bị di động giao tiếp với các thẻ thông tin, được gọi là NFC Tags, hoặc với các thiết bị khác một cách nhanh chóng và tiện lợi.
- Có 3 kiểu tiếp nhận dữ liệu bằng NFC:
Tương tác với các thẻ tag cho việc nhận và ghi thông tin trên thiết bị di động.
Thiết bị di động được xem như nơi để các thiết bị khác truy xuất thông tin.
Hai thiết bị cùng trao đổi và tiếp nhận các thông tin của nhau.
NFC hoạt động dựa trên định dạng dữ liệu NDEF (NFC Data Exchange Format) và sử dụng hệ thống Tag Dispatch để nhận diện các loại dữ liệu khác nhau, từ đó khởi động ứng dụng phù hợp.
- Hệ thống Tag Dispatch thực hiện theo cơ chế:
Phân tích dữ liệu NDEF và chuyển dữ liệu sang kiểu MIME hoặc URI.
Đóng gói dữ liệu MIME và URI vào Intent
Khởi động ứng dụng tương ứng với gói Intent.
- Dữ liệu NDEF được gói trong NdefMessage và chứa dạng các NdefRecord với các trường dữ liệu sau:
3-bit TNF (Type Name Format ): trường chỉ định định dạng dữ liệu.
Variable Length Type: kiểu độ dài dữ liệu.
Variable Length ID: Id chỉ định record
Variable Length Playload: dữ liệu của record
- Cảm biến NFC được điều khiển bởi NFCAdapter để nhận các gói Intent:
NfcManager manager (NfcManager)context.getSystemService(Context.NFC_SERVICE); NfcAdapter adapter = manager.getDefaultAdapter();
Cần thực hiện phương thức isEnable() để kiểm tra trạng thái của cảm biến NFC
Không có phương thức cho phép tắt mở NFC. startActivityForResult( new Intent( android.provider.Settings.ACTION_WIRELESS_SETTINGS), 0);
- Thứ tự ưu tiên xử lý các gói Intent được gửi tới thiết bị:
ACTION_NDEF_DISCOVERED: intent được sử dụng để khởi chạy một Activity trong ứng dụng có đăng ký xử lý gói intent này.
ACTION_TECH_DISCOVERED: nếu không có Activity nào đăng ký việc xử lý gói intent đến, hệ thống sẽ khởi động ứng dụngthích hợp.
ACTION_TAG_DISCOVERED: hệ thống chuyển sang xử lý kiểu dữ liệu Tag thông thường.
Hình 11.4 ưu tiên xử lý
- Cần đăng kí trong AndroidManifest để sử dụng NFC
- Lưu ý phiên bản của ứngdụng:
- Cho phép ứng dụng chỉ cài đặt trên các thiết bị có hỗ trợ NFC:
Bài tập thực hành của sinh viên
1 Trình bày được Telephone trong Android
3 Trình bày và thực hiện Lấy thông tin và điều khiển cảm biến
4 Thực hiện được xử lý thông tin một số cảm biến
5 Thiết kế gửi một tin nhắn SMS bằng cách sử dụng ứng dụng SMS của thiết bị
6 Sử dụng một ứng dụng quay số hoặc trực tiếp từ ứng dụng để giúp dễ dàng hơn cho người dùng
7 Thiết kế một ứng dụng bằng cách sử dụng cảm biến
1 Trình bày được Telephone trong Android
3 Trình bày và thực hiện Lấy thông tin và điều khiển cảm biến
4 Thiết kế gửi một tin nhắn SMS bằng cách sử dụng ứng dụng SMS của thiết bị, tham khảo ở mục 1.4 trong bài 10 của giáo trình
5 Thiết kế gửi một tin nhắn SMS bằng cách sử dụng ứng dụng SMS của thiết Thiết lập Layout bị
Trước tiên, chúng ta cần phải thay đổi layout chính của chúng ta để có một trường EditText cho tin nhắn và một nút Send Message (gởi tin nhắn)
Inside the onCreate() method of the MainActivity class, an intent is created with ACTION_SENDTO as the first argument and a URI formatted as smsto: as the second argument The text message will be set as the value of the extra parameter sms_body.
Button sendMessageBtn = (Button) findViewById(R.id.btn_send_message);
16 final EditText messagetEt = (EditText) findViewById(R.id.et_message); sendMessageBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String message = messagetEt.getText().toString();
To send an SMS message in Android, first retrieve the phone number from the input field using `mPhoneNoEt.getText().toString()` Ensure that both the message and phone number are not empty by using `TextUtils.isEmpty()` If both conditions are met, create an `Intent` with `Intent.ACTION_SENDTO`, specifying the phone number in the URI format "smsto:" Then, add the message body with `putExtra("sms_body", message)` and initiate the SMS activity with `startActivity(smsIntent)`.
Tại đây, ứng dụng SMS sẽ theo dõi trạng thái gửi tin nhắn
Khi hoàn tất việc nhập thông tin vào tất cả các trường, người dùng chỉ cần nhấn nút "Send SMS" để mở ứng dụng SMS trên thiết bị của mình Nếu chưa có ứng dụng SMS nào được chọn, hệ thống sẽ cung cấp cho người dùng các tùy chọn để lựa chọn ứng dụng phù hợp.
6 Sử dụng một ứng dụng quay số hoặc trực tiếp từ ứng dụng để giúp dễ dàng hơn cho người dùng
Hiện giờ, layout của chúng ta sẽ chỉ có một trường EditText và một nút Dial:
The provided XML code defines a LinearLayout for an Android application, specifying its orientation as vertical and setting both the width and height to match the parent view It includes padding on all sides, defined by dimensions specified in the resources, and centers its content both horizontally and vertically The layout is associated with the MainActivity class in the com.chikeandroid.tutsplust_telephony package, ensuring proper context for the user interface elements contained within.
In the code snippet below, we create an ACTION_DIAL intent to display the dialer interface The phone number is extracted from our tel URI scheme: tel:XXXXXXXX Notably, no permissions are required to perform this action.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Button mDialButton = (Button) findViewById(R.id.btn_dial); final EditText mPhoneNoEt = (EditText) findViewById(R.id.et_phone_no); mDialButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
String phoneNo = mPhoneNoEt.getText().toString(); if(!TextUtils.isEmpty(phoneNo)) {
String dial = "tel:" + phoneNo; startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(dial)));
Toast.makeText(MainActivity.this, "Enter a phone number", Toast.LENGTH_SHORT).show(); }
Khi bạn nhấp vào nút Dial trong ứng dụng, bạn sẽ được chuyển đến ứng dụng quay số để thực hiện cuộc gọi Để tạo cuộc gọi trực tiếp từ ứng dụng của mình, bạn chỉ cần thay đổi intent từ ACTION_DIAL thành ACTION_CALL, nhưng điều này yêu cầu quyền android.permission.CALL_PHONE.
Hình 11.3 giao diện cuộc gọi
7 Thiết kế một ứng dụng bằng cách sử dụng cảm biến
Bước 1.Tạo project mới trong Android Studio: File ⇒ New Project và set minimum SDK version là Android 6.0 (API 23)
Bước 2.Vì chúng ta sẽ làm việc cùng với xác thực vân tay, chúng ta cần thêm quyền USE_FINGERPRINT trong file AndroidManifest.xml
Bước 3.Chọn thư mục res ⇒values và cập nhật file colors.
Bước 4 Chọn thư mục res ⇒ values và cập nhật file strings
Step 5: Create a fingerprint icon with the assistance of Android Image Assets Right-click on the drawable folder, then select New ⇒ Image Asset, and name it ic_action_fingerprint.