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 và có thể được sử dụng bởi nhiều người Các dữ liệu này được tổ chức theo một mô hình nhất định, giúp dễ dàng quản lý và truy xuất thông tin.
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ữ, tạo nên một không gian dữ liệu hay còn gọi là "thế giới nhỏ" (miniworld).
Cơ sở dữ liệu (CSDL) là tập hợp dữ liệu liên kết một cách logic và mang ý nghĩa cụ thể, được thiết kế cho mục đích riêng Hệ quản trị cơ sở dữ liệu (DBMS) là tập 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ữ "hệ cơ sở dữ liệu" thường được sử dụng để chỉ cả CSDL và hệ quản trị của nó.
Hệ quản trị cơ sở dữ liệu (DBMS) là phần mềm được thiết kế để quản lý cơ sở dữ liệu, hỗ trợ lưu trữ, sửa chữa, xóa và tìm kiếm thông tin Có nhiều loại DBMS, từ phần mềm đơn giản cho 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, DB2, và Infomix Các 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, 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ã nguồn mở, được tích hợp dưới dạng thư viện nhúng trong Android, cung cấp các tính năng quan hệ tiêu chuẩn như cú pháp, giao dịch và các câu lệnh Nó được sử dụng phổ biến trong các ứng dụng di động trên Android và iOS, đồng thời cũng được Mozilla Firefox áp dụng để lưu trữ dữ liệu cấu hình.
SQLite là một bộ thư viện tích hợp sẵn, cho phép lập trình viên 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 động của SQLite giúp người dùng kiểm soát thông tin dữ liệu hiệu quả.
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 được cấp phát một thư mục riêng để lưu trữ cơ sở dữ liệu, chỉ ứng dụng đó mới có quyền truy cập Để chia sẻ dữ liệu giữa các ứng dụng, người dùng 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 hỗ trợ tạo cơ sở dữ liệu sử dụng SQLite, do SQLite không cung cấp 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 quan trọng để khởi tạo và nâng cấp cơ sở dữ liệu, đồng thời tạo đối tượng cho phép truy cập cơ sở dữ liệu để thực hiện các thao tác đọc và ghi.
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, with _id serving as the primary key that auto-increments In the MySQLiteHelper class, the database is named "COUNTRY_DB," and the table is defined as "COUNTRY." The column names include 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 chúng ta mở rộng lớp cursor để kế thừa các phương thức và truy vấn cần thiết Khi thực hiện điều này, ta sử dụng một instance của CursorFactory để tham chiếu đến lớp tùy chỉnh thay vì lớp mặc định Nếu không cần sử dụng lớp mặc định, ta có thể để giá trị 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, 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>;
- 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, reference and utilize the AnimationDrawable object from the View displaying the Drawable by using the getBackgroundResource() method Then, invoke the start() method on the AnimationDrawable object to initiate the animation.
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 width, height trước khi vẽ Để sử dụng BitmapDrawable, bạn có thể làm theo các bước sau.
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 provided XML snippet defines a TextView for a chat message in an Android layout, featuring a margin of 20dp, a white text color, and a background drawable resembling Facebook's chat style The TextView is set to wrap its content both in width and height, and it displays the text "This is message."
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 vượt trội giúp cải thiện vẻ đẹp của các view Hãy cùng khám phá thêm các loại drawable khác để hiểu rõ hơn về khả năng của chúng trong việc nâng cao 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 render these states, particularly for buttons and items in ListView or RecyclerView.
Hình ảnh dưới đây minh họa 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
To create a button in Android with the text "Save Change," use the following XML code: `` This code configures the button's appearance, including its background, text color, and dimensions, ensuring it is centered within its parent layout.
Hãy thử chạy chương trình và kiểm tra xem có sự khác biệt nào trong kết quả không Trong Android, ngoài hai trạng thái normal và pressed, còn 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, 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
In the Vector Asset Studio dialog, click "Choose" to select the icon you wish to export as a vector drawable 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 nắm rõ hơn về khái niệm Drawable trong Android.
The ArcDrawable class extends the Drawable class and is designed to create a custom arc shape It initializes a Paint object with anti-aliasing for smoother edges, sets the desired color, and configures the paint style to STROKE Additionally, it specifies a round stroke cap and a stroke width of 10 pixels, allowing for visually appealing arc drawings in Android applications.
In the overridden draw method, a RectF object is initialized if it is null, and its dimensions are set based on the bounds of the drawing area, adjusted by the stroke width of the paint The left and top coordinates are offset by half the stroke width, while the right and bottom coordinates are reduced by the stroke width and an additional 2 pixels Finally, an arc is drawn on the canvas using the defined rectangle, starting at 45 degrees and spanning 270 degrees, without filling the arc.
@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 Android như 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 tối ưu hóa tài nguyên hạn chế 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ể xử lý ứng dụng như trên PC hay laptop Do đó, cần tinh giản và tối ưu hóa các thuật toán để tiết kiệm tài nguyên và nâng cao hiệu suất hoạt động.
Thread là đơn vị nhỏ nhất của tiến trình, được hệ điều hành định thời và bao hàm trong các tiến trình thực thi của máy tính Mỗi thread sở hữu một callstack riêng để quản lý các phương thức, đối số và biến cục bộ.
Android hoạt động trên hệ điều hành Linux và các ứng dụng của nó được viết bằng ngôn ngữ Java, chạy trong máy ảo Dalvik, không phải JVM Mỗi máy ảo Android khởi động với ít nhất một thread chính và có thể tạo thêm nhiều thread khác để quản lý tiến trình Ứng dụng có khả năng khởi động thêm thread phụ cho các mục đích cụ thể Các thread trong cùng một máy ảo tương tác và được đồng bộ hóa thông qua các đối tượng chia sẻ và monitor liên quan.
Mỗi Thread trong lập trình có một độ ưu tiên từ 1 đến 10, được xác định thông qua phương thức setPriority(int) Độ ưu tiên này quyết định thời gian CPU mà thread đó có thể sử dụng, ảnh hưởng đến hiệu suất và tốc độ thực thi của ứng dụng.
- 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 trong cùng một ứng dụng mà không cần phải chờ đợi Tương tự như cơ chế đa nhiệm của hệ điều hành cho phép nhiều ứng dụng chạy song song, multithreading cho phép thực hiện nhiều tác vụ cùng lúc trong một ứng dụng.
- Ưu điểm của việc sử dụng Multithreading:
Các thread trong lập trình cho phép 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 Việc sử dụng multi-threading sẽ mang lại lợi ích lớn khi phát triển ứng dụng đ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
Main Thread thường được gọi là UI Thread, nhưng điều này không đúng trong trường hợp một chương trình có nhiều hơn một Thread đảm nhận 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 thêm cho chương trình nhằm thực hiện các công việc không liên quan đến giao diện.
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, các 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ể khiến UI bị block, làm 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 chọn đóng ứng dụng hoặc chờ đợi Để tránh những phiền toái này, Android đã đề 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
Ví dụ dưới đây cho thấy một đoạn mã có thể gặp vấn đề Hàm onClick được định nghĩa để thực hiện một tác vụ trong một luồng mới, nhưng cần kiểm tra xem có lỗi nào không trong quá trình thực thi.
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 rule thứ nhất, 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), không tuân thủ rule 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 khả thi Do đó, Android đã cung cấp cho Worker Thread một số phương thức để thực hiện điều này.
The following example demonstrates how to load an image from a network in Android When a view is clicked, a new thread is initiated to fetch the image using the specified URL Once the image is successfully loaded, it is posted back to the main thread to be displayed in the ImageView.
Bây giờ, mã code đã có thể chạy một cách hiệu quả, nhưng ba phương thức đã đề cập chỉ thích hợp cho một số bài toán nhất định Nếu không có tham số là một View hoặc Activity để truyền vào, việc cập nhật giao diện sẽ không thể thực hiện được Hơn nữa, trong trường hợp xử lý dữ liệu lớn, phương pháp này cũng không khả thi Giải pháp cho vấn đề này là sử dụng hai công cụ: Handler hoặc AsyncTask.
ASYNCTASK
AsyncTask là một đối tượng trong lập trình Android cho phép thực hiện các tác vụ xử lý ở nền (background) mà không cần phải quản lý trực tiếp các Thread hoặc Handler Nó giúp trả kết quả về UI thread một cách dễ dàng, cải thiện trải nghiệm người dùng bằng cách giữ cho giao diện luôn mượt mà và phản hồi nhanh chóng.
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 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 phương thức 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() sẽ tự động được gọi khi tiến trình hoàn tất, 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ó chạy trên một thread riêng biệt với UI thread, do đó không thể cập nhật giao diện tại đây Để cập nhật giao diện trong khi tác vụ đang thực hiện, chẳng hạn 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ể tạm dừng bất kỳ lúc nào mà không cần chờ AsyncTask hoàn thành Để làm điều này, chỉ cần gọi hàm cancel(boolean).
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ề AsyncTask trong Android đã được trình bày rõ ràng Khi bạn hiểu rõ bản chất của AsyncTask, việc áp dụng và xử lý 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 distinction 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 để quản lý hàng đợi, cho phép xử lý các Messages và Runnables Việc xác định xem các tác vụ này nên được thực hiện trên main thread hay background thread không phải là vấn đề quan trọng.
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 và thực hiện các 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ó thể được 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 ngược 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 người dùng để tương tác Một số tác vụ tiêu tốn thời gian như 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, là ví dụ điển hình cho chức năng của dịch vụ này.
- 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" là loại dịch vụ đượ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 công việc đơn lẻ, như tải xuống hoặc tính toán, hoàn thành Sau khi công việc kết thúc, dịch vụ sẽ tự động dừng lại.
Dịch vụ "Bound" là loại 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() Dịch vụ này cung cấp giao diện Client - Server, cho phép các thành phần ứ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 dụng 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 dedicated ServiceConnection object for managing the opening and closing of connections to a Service, override the two methods onServiceDisconnected() and onServiceConnected() This allows for binding to MyService effectively The implementation includes setting the mBound variable to false in the onServiceDisconnected() method to indicate that the connection has been lost.
@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 ID of the clicked view, specifically handling the case for R.id.btnCallService, ensuring that the function is only called when the service is bound.
//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à thành phần quan trọng trong Android, có chức năng nhận và xử lý các Intent theo chỉ định của lập trình viên Nó cho phép mở ứng dụng để xử lý các Intent được gửi từ hệ thống, giúp quản lý các sự kiện và tương tác trong ứng dụng một cách hiệu quả.
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 theo dõi hiệu quả thông qua Broadcast Receiver, giúp ứng dụng xử lý các tình huống này một cách nhanh chóng và chính xác.
- Để 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 trải nghiệm sử dụng thiết bị Khi nhận được tin nhắn hoặc email, thiết bị sẽ sử dụng Notification để thông báo qua âm thanh, đèn nền và biểu tượng trên thanh tác vụ, giúp người dùng dễ dàng nhận biết thông tin mới mà không cần mở ứng dụng.
Hình 6.3 Các dạng thông báo với Notification
Thông báo tự động được kích hoạt để thông báo cho người dùng rằng ứng dụng đã hoàn thành một công việc Người dùng có thể nhấp vào thông báo để khởi động lại ứng dụng khi nó đang ở trạng thái 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 trong 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 trong quá trình 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ó thường được sử dụng để thông báo về các thiết lập cấu hình hoặc để cung cấp thông tin tạm thời, chẳng hạn như kiểm tra sự cố.
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.
Trong lập trình Android, có hai giá trị mặc định cho thời gian 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 Việc sử dụng các giá trị này thay vì nhập số cụ thể giúp đảm bảo tính nhất quán và dễ bảo trì cho ứng dụng.
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 in an Android application, specifying the layout's width and height to match the parent container It includes necessary namespaces for Android, app attributes, and tools, ensuring compatibility and proper rendering within the MainActivity context.
The button in the Android layout is defined with the ID "button_play" and is designed to have a width and height that wrap its content It includes a top margin of 28dp and displays the text "Play." The button is constrained to align with both the start and end of the parent layout, as well as the top of the parent.
The provided XML code snippet defines a button in an Android layout with the ID "button_stop." This button is configured to have a width and height that wrap its content, a top margin of 37dp, and the text label "Stop." It is positioned in relation to the parent layout, aligning its start and end to the parent's edges and placing it below another button with the ID "button_play."
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 for audio playback This service extends the Android Service class and includes essential methods for managing media playback, allowing seamless integration of audio features in applications.
// 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, extending AppCompatActivity It imports necessary Android libraries and defines two buttons, buttonPlay and buttonStop, for controlling song playback within the application The activity is set up in the onCreate method, which initializes the user interface components.
In the onCreate method of the activity, the layout is set using setContentView, and the play and stop buttons are initialized by finding their respective views An OnClickListener is attached to the play button, triggering the playSong method when clicked.
}); 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 (Bouned Service) là một ứng dụng cung cấp thông tin thời tiết cho ngày hiện tại, cho phép người dùng nhập vào vị trí địa lý như Hà Nội, Chicago, và nhận kết quả về tình hình thời tiết như mưa, 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.).
Sau khi truy xuất, các tài nguyên sẽ được chuyển đổi thành dữ liệu dễ hiểu cho người dùng thông qua các API tương ứng Android cung cấp đầy đủ 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 cho phép 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 vấn đề 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 tạo một 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 (ví dụ: http://m.t3h.vn), giúp lập trình viên tiết kiệm thời gian phát triển ứng dụng cho từng hệ điều hành Tuy nhiên, việc sử dụng Web App vẫn gặp phải một số hạn chế mà chỉ có ứng dụng gốc mới có thể khắc phục.
Vấn đề băng thông trong việc sử dụng trình duyệt để truy cập ứng dụng web là một thách thức lớn, khi tất cả 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 đáng kể Thay vì tiếp tục tải lại các dữ liệu tĩnh, việc xây dựng ứng dụng có khả năng lưu trữ dữ liệu này một cách hiệu quả sẽ giúp giảm thiểu băng thông cần thiết và cải thiện hiệu suất truy cập.
Lưu cache là một tính năng quan trọng giúp các ứng dụng lưu trữ dữ liệu một cách hiệu quả, vượt qua giới hạn của trình duyệt Trong khi trình duyệt chỉ có thể giữ lại một lượng thông tin nhỏ, ứng dụng có khả năng lưu trữ mọi dữ liệu mà lập trình viên muốn, từ thông tin truy xuất đến các thao tác của người dùng Khi xảy ra sự cố kết nối, ứng dụng sẽ tự động lưu lại thông tin tại thời điểm mất kết nối và xử lý lại khi thiết bị được kết nối trở lạ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 có thể giúp chúng ta quản lý và duy trì các kết nối một cách hiệu quả hơn khi cần thiết.
Các ứng dụng nền web thường gặp khó khăn trong việc truy cập vào 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 xuất các đặc tính này thông qua các API mà bộ SDK cung cấp.
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:
Mobile Internet là một hình thức kết nối thông 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òn có khả năng phát tín hiệu mạng cho các thiết bị khác, tạo 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 xuất 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 proper functionality, the application must include the permission `` and avoid making direct Internet connections on the main application thread Instead, utilize AsyncTask or Thread for these operations to maintain performance and responsiveness.
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 xuống 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ụ nền, giúp quản lý và giám sát các kết nối HTTP cũng như các hoạt động khởi động lại của thiết bị, đảm bảo rằng mọi nội dung được tải xuống một cách hoàn chỉnh.
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 mà không bị gián đoạn Nó đảm bảo quá trình tải hoàn thành một cách hiệu quả, ưu tiên việc hoàn tất nội dung tải về.
- 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, bạn 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, bạn cần tạo một đối tượng Request với tham số là một Uri, đại diện cho địa chỉ kết nối đến máy chủ chứa nội dung cần tải Đối tượng Request này sẽ được đưa vào hàng đợi để bắt đầu quá trình tải thông qua 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) đã 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à hệ thống 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ột 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à công nghệ quan trọng giúp 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 chung được mô tả bằng XML Dịch vụ này có thể xác định bằng 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ó được hình thành bằng cách đóng gói các chức năng để các ứng dụng khác dễ dàng truy cập và yêu cầu thông tin từ dịch vụ Web khác Dịch vụ Web 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 chủ yếu được sử dụng để tích hợp các hệ thống, đóng vai trò quan trọng trong quá trình phát triển hệ thống Trong bối cảnh này, 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 dùng tương tác để phân tích và truy xuất dữ liệu Gần đây, sự phát triển mạnh mẽ của thương mại điện tử và B2B đã tạo ra nhu cầu cấp thiết cho các hệ thố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 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 Hiện nay, nhiều Web Services miễn phí đang ngày càng được phát triển nhằm phục vụ cho 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 và 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 về các chuẩn dịch vụ WEB là điều 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 Dưới đây là một số chuẩn chính mà bạn nên biết.
- 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à 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à hợp tác hiệu quả HTTP đóng vai trò là nền tảng giao tiếp dữ liệu chính 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 Uniform Resource Identifier (URI) is a string used to identify a resource on the internet A Uniform Resource Locator (URL) is a specific type of URI that indicates the existence of a resource and provides a method to access it In contrast, a Uniform Resource Name (URN) 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
When configuring your web application, ensure to accept a variety of file types, including application/x-ms-application, image/jpeg, image/gif, and application/vnd.ms-excel, among others Additionally, set the Accept-Language header to vi-VN to cater to Vietnamese users effectively.
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 cấu trúc dưới dạng XML, cho phép các ứng dụng trao đổi thông tin một cách hiệu quả.
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 giữa các thành phần trong môi trường phân tán Được thiết kế nhằm giảm chi phí tích hợp hệ thống phân tán trên nhiều nền tảng khác nhau, SOAP định nghĩa một 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 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 bộ soạn thảo văn bản đơn giản, cho phép làm việc trên hầu hết mọi 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 Ngoài ra, SOAP không hỗ trợ garbage collection phân tán và không có cơ chế tham chiếu, do đó, client SOAP 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ác đặc điểm này, hệ thống không phụ thuộc vào công nghệ cụ thể nào, miễn là người dùng sử dụng 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, chỉ cần nó có khả năng xử lý các tin nhắn định dạng XML.
Trong 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ù đây là mô hình cơ bản nhất trong việc trao đổi thông điệp SOAP, nhưng nó thường không đáp ứng đủ các chức năng cần thiết Tuy nhiên, từ mô hình đơn giản này, các mô hình trao đổi phức tạp hơn sẽ được phát triển.
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, ứng dụng Google Play Store do Google cung cấp trên thiết bị người dùng, cho phép hiển thị các ứng dụng phát triển bởi lập trình viên, giúp người dùng tải và cài đặt ứng dụng trực tiếp trên thiết bị của họ.
Trong hướng dẫn này, chúng ta sẽ khám phá dịch vụ OnlineShop, nơi 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 và có thể bổ sung các quyền liên quan như kiểm soát kết nối Internet.
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 để quản lý vấn đề này là sử dụng Broadcast Receiver.
@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");
Phương thức setRequestMethod cho phép chúng ta tự do chỉ định tên phương thức gọi dịch vụ RESTful như GET, POST, PUT, tùy thuộc vào loại phương thức mà dịch vụ cung cấp Trong ví dụ này, vì thực hiện gọi theo phương thức GET và không có tham số truyền vào, nên cách thực hiện không khác nhiều so với phần đầu chương.
Để đăng nhập vào dịch vụ này, bạn cần khảo sát cách thức thực hiện Cần gửi dữ liệu người dùng dưới dạng JSON và sử dụng phương thức POST để đả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 and open an HTTP connection Set connection and read timeouts to 10 seconds, use the POST method, and specify the content type as JSON Enable output for the connection and allow it to follow redirects.
BufferedOutputStream(connection.getOutputStream()); outputSt ream.write(incomingParams.getBytes()); outputStream.flush(); outputStream.close();
Dữ liệu incomingParams được chia thành từng byte nhỏ bằng phương thức getBytes() trước khi gửi vào Outputstream của kết nối Khi dịch vụ nhận dữ liệu, nó được định dạng dưới dạng JSON thông qua phương thức setRequestProperty().
Sử dụng các lớp trong gói org.apache.http giúp tường minh hơn trong việc gọi đến Service Chẳng hạn, việc sử 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à rõ ràng hơn.
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);
HttpPost: Đối với phương thức POST, cần xác định định dạng dữ liệu cần gửi lên dịch vụ Dưới đây là ví dụ 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 chủ yếu dựa vào việc xử lý InputStream, không phụ thuộc nhiều vào cách gọi dịch vụ Chúng ta chỉ cần đọc dòng dữ liệu từ InputStream và chuyển đổi nó thành định dạng dữ liệu phù hợp để tương tác Dưới đây là ví dụ về cách đọc dữ liệu từ InputStream và chuyển đổi 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, we have implemented the startService() and stopService() methods to manage the service lifecycle effectively The package is defined as com.example.MyApplication, and essential imports include android.os.Bundle, android.app.Activity, android.view.Menu, android.content.Intent, and android.view.View This setup allows for seamless integration of service management within the 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 is from the file src/com.example.MyApplication/MyService.java, which may contain the implementation of one or more methods associated with a Service based on requirements Currently, 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 MyService class 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 is defined with XML attributes for Android, setting its width and height to match the parent dimensions It includes padding on all sides, specified by the defined dimensions for horizontal and vertical margins The layout is associated with the MainActivity context, ensuring proper integration within the application.
This example showcases a TextView in Android development, featuring an ID of "textView1." It is designed to wrap content and align at the top center of its parent layout, with a text size set to 30dp The displayed text reads "Example of services."
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 chung 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 vớ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 chương trình sửa đổi và kiểm tra tính hợp lệ mà không cần hiểu biết trước 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 XML output properties in Java, create a new Properties object and set various parameters Enable indentation by setting the "OutputKeys.INDENT" property to "yes." Specify the output method as XML by using "OutputKeys.METHOD" with the value "xml." Ensure the XML declaration is included by setting "OutputKeys.OMIT_XML_DECLARATION" to "no." Define the XML version as "1.0" with "OutputKeys.VERSION" and set the character encoding to "UTF-8" using "OutputKeys.ENCODING." Finally, apply these output properties to the transformer by calling "transformer.setOutputProperties(outFormat)."
// 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 hiển thị 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
To create an XML document using a StringWriter, initialize the StringWriter and set it as the output for the XML serializer Begin the document with UTF-8 encoding and start the "data" tag, including an attribute for the source as "weather.t3h.vn" Within the "weather" tag, add a "date" tag with the text "20-06-2014", followed by "tempMaxC" with a value of "13" and "tempMaxF" with a value of "56" Finally, close all opened tags and end the document, setting the text of the textXML element to the generated XML string.
- 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:
To implement a Google Map in your Android application, use the following XML code snippet: `` This code defines a MapFragment that occupies the full width and height of its parent layout, allowing for seamless integration of Google Maps functionality within your app.
- 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
Marker là lớp được thiết kế để hỗ trợ định vị tọa độ trên bản đồ, hiển thị thông tin địa điểm và tạo điều kiện tương tác với người dùng Ví dụ về cách sử dụng lớp Marker có thể được thể hiện qua đoạn mã: 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 methods available for manipulating geographic data include retrieving a list of points with `getPoints()`, setting the width of a shape using `setWidth(float width)`, and adjusting its visibility with `setVisible(boolean visible)` The `setColor(int color)` method allows for color customization, while `setGeodesic(boolean geodesic)` determines if the shape follows a geodesic path The `getZIndex()` method retrieves the shape's stacking order, and `setZIndex(float zIndex)` allows for adjustment Additionally, `isGeodesic()` checks if the shape is geodesic, and `isVisible()` verifies its visibility The `remove()` method deletes the shape, and `hashCode()` provides a unique identifier for it.
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 đã khép kín một cách linh hoạt.
- 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 article discusses various methods for managing and manipulating graphical elements, including retrieving the ID, radius, stroke color, stroke width, and Z-index of an object It also covers visibility settings and provides functions to remove the object, set its center using latitude and longitude coordinates, and adjust its fill color, radius, stroke color, stroke width, visibility, and Z-index.
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) được sử dụng để giao dịch giữa các ứng dụng và máy chủ hỗ trợ đầu cuối Hiện nay, Cloud Messaging đã được tích hợp vào Google Play Services, mang đến những 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) Nhờ đó, thiết bị có khả năng gửi phản hồi trở lại máy chủ, không còn giới hạn chỉ một chiều từ máy chủ đến thiết bị như trước đây.
Nhờ tính năng truyền tải ngược, bạn có thể đồng bộ hóa các thông báo đã nhận và bỏ lỡ trên thiết bị này với thiết bị khác Điều này giúp bạn tránh việc phải kiểm tra lại nhiều thông báo giống nhau khi chuyển từ điện thoại sang 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 Hệ thống gửi tin nhắn tới thiết bị Android một cách tức thời thông qua 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 trên thiết bị Android khi có email mới GCM gửi thông báo cho người quản lý khi có đơn đặt hàng trên trang web của họ.
Gửi tin nhắn tới cộng đồng như nhân viên trong công ty, học sinh hoặc phụ huynh của trường học với chi phí thấp và hiệu quả cao.
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, start by launching Android Studio Then, 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 illustrates 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 requires a Context parameter for its constructor, allowing it to operate within the specified context.
@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 qua HTTP để sử dụng GCM/HTTP hoặc CSS trong việc gửi tin nhắn đến các ứng dụng của bạn Thực hiện lệnh regService.register(regId).execute(); để hoàn tất quá trình đăng ký.
} 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 thêm 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 chèn đoạn mã vào tập tin 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 a module to App Engine, select Build → Deploy Module to App Engine A dialog box will appear prompting you to choose a Google Developers Console project (ensure you are logged into your Google account) Click on Deploy to proceed If you do not have an existing Google Developers Console project, select "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 dữ liệu bản đồ từ Google và hiển thị chúng Để thực hiện điều này, bạn cần đăng ký một Google Map API Key và 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 loại fragment được thư viện cung cấp, chứa đối tượng GoogleMap Bạn có thể lựa chọn 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 đó.
In the MyMapFragment.java file, located in the org.o7planning.mygooglemap package, we import essential classes from the Google Maps API, including CameraUpdateFactory, GoogleMap, OnMapReadyCallback, and SupportMapFragment This class, MyMapFragment, extends SupportMapFragment, enabling the integration of Google Maps functionality into our application It allows for the manipulation of map features, such as adding markers and updating the camera position, thereby enhancing user interaction with geographical data.
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 defines a `ConstraintLayout` for an Android application, specifying the layout's width and height to match the parent container It includes essential namespaces for Android attributes, auto-resources, and tools, ensuring compatibility with the development environment and design tools This layout serves as the foundation for the user interface in the `MainActivity`.
The provided XML fragment represents a layout configuration for a Google Map in an Android application It defines a `MyMapFragment` with specific dimensions set to zero, allowing it to adapt to the constraints of its parent layout The fragment is centered within the parent, with equal margins of 8dp on all sides, ensuring a balanced appearance within the user interface.
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 một cách hiệu quả.
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 several control methods, including getDuration, getCurrentPosition, and seekTo You can start playback with mediaPlayer.start(), retrieve the current position using int pos = mediaPlayer.getCurrentPosition(), and obtain the total duration with int duration = mediaPlayer.getDuration() To seek forward, use mediaPlayer.seekTo(pos + (duration - pos) / 10) After a designated wait time, you can stop playback with mediaPlayer.stop().
Một số phương thức hỗ trợ âm thanh bao gồm việc chống khóa màn hình trong quá trình thu phát và thiết lập các chế độ phát lại Để 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 lại, bạn có thể kiểm tra và thiết lập như sau: 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 bạn 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 and specify the output path for the saved 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 MediaRecorder for capturing audio and video, initialize it by configuring the audio source to the microphone and the video source to the camera Specify the output format as default and select the appropriate audio and video encoders Designate the output file path, such as "/sdcard/taptinxuatra.mp4", and set the preview display using the surface holder Finally, prepare the MediaRecorder 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 được trả về để 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, extending `AppCompatActivity`, manages media playback with various controls including forward, pause, play, and backward buttons It utilizes a `MediaPlayer` instance to handle audio playback, while tracking the playback time with variables for start and final times A `Handler` is implemented to update the UI, and the class defines constants for seeking forward and backward by 5 seconds Additionally, it incorporates a `SeekBar` and `TextView` elements to display playback status, elapsed time, and song information, ensuring a seamless user experience with a focus on media control functionality.
@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 snippet defines a `ConstraintLayout` for an Android application, setting the layout width and height to match the parent dimensions It includes necessary XML namespaces for Android attributes, application-specific attributes, and tools, indicating that it is used within the context of the `MainActivity`.
To create an ImageView in Android, use the following XML code: `` This code sets the ImageView's width to 0dp, height to 175dp, and applies margins to position it properly within its parent layout, while also specifying a drawable resource for the image.
To create a video view in an Android layout, use the following XML code: `` This configuration sets the video view's dimensions, margins, and constraints, ensuring it is properly positioned relative to other elements in the layout.
The provided XML code defines a horizontal LinearLayout in Android with specific layout parameters It has a width of 0dp and a height that wraps its content The layout includes margins on all sides, specifically 16dp for start, left, end, and right, along with a top margin of 8dp Additionally, it is constrained to the parent layout, aligning its start to the parent's start and its end to the parent's end, while positioning itself below a video view identified by the ID "videoView."
In the MainActivity.java file of the Android Camera Demo application, essential imports include AppCompatActivity, ActivityCompat, and various Android libraries for handling media The class defines buttons for capturing images and videos, along with UI elements such as a VideoView and an ImageView It also establishes constants for permission requests and activity results, specifically for read/write permissions, image capture, and video capture This foundational setup enables users to interact with the camera and media functionalities within the app.
In the `onCreate` method of the activity, the layout is set using `setContentView(R.layout.activity_main)`, and various UI components are initialized, including buttons for image and video capture, a `VideoView`, and an `ImageView` The image button is assigned an `OnClickListener` that 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 functionality of the app, it is essential to check for the necessary permissions, specifically WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE If these permissions are not granted, the app should prompt the user to allow access by requesting the required permissions.
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 by calling `getSystemService(srvcName)` The phone type can be determined using `telephonyManager.getPhoneType()`, which may return values such as PHONE_TYPE_CDMA, PHONE_TYPE_GSM, or PHONE_TYPE_NONE Depending on the result, you can implement specific logic for each phone type within a switch statement.
String phoneNumber = telephonyManager.getLine1Number();
- Quản lí trạng thái: o Ví dụ: class MyPhoneStateListener extends PhoneStateListener
In the overridden method `onCallStateChanged(int state, String incomingNumber)`, the call state is monitored using a switch statement The method handles three specific call states: `CALL_STATE_IDLE`, which indicates no active call; `CALL_STATE_RINGING`, signifying an incoming call; and `CALL_STATE_OFFHOOK`, representing an active call Each case is prepared to execute specific actions based on the call's current state.
To read connection data and monitor state changes, utilize the methods getDataSet() and getDataActivity() For instance, you can retrieve the data activity using `int dataActivity = telephonyManager.getDataActivity();` and the data state with `int dataState = telephonyManager.getDataState();` The data activity can be evaluated using a switch statement, which includes cases for 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 retrieve the current network operator name and type in Android, use the TelephonyManager class The network operator name can be obtained with `telephonyManager.getNetworkOperatorName()`, while the network type is determined using `telephonyManager.getNetworkType()` A switch statement can then be employed to handle various network types, such as NETWORK_TYPE_1xRTT, NETWORK_TYPE_CDMA, NETWORK_TYPE_EDGE, and others, allowing for specific actions to be taken based on the detected network type.
Đọ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 provides a way to monitor various phone state changes It includes methods to handle call forwarding indicators, call state changes, cell location updates, data activity direction, data connection state changes, message waiting indicators, service state changes, and signal strength updates Each method is triggered by specific events, allowing developers to respond to changes in the phone's status effectively.
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 Android manifest includes essential intent filters for handling specific actions It defines actions such as "VIEW" and "DIAL" to facilitate user interactions Additionally, it categorizes intents under "DEFAULT" and "BROWSABLE," allowing for versatile app functionality The manifest also specifies a data scheme for telephone links, enabling seamless dialing capabilities within the application.
- 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 Android, create an Intent with the action `Intent.ACTION_SEND` and specify the URI of the attached image Use `putExtra` to include the SMS body text, recipient's address, and the image URI Set the MIME type to "image/png" before launching 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 tin nhắn SMS đã được gửi, bạn cần đăng ký BroadcastReceiver nhằm 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 application handles different result codes from SMS operations When the result code is `Activity.RESULT_OK`, no action is taken Conversely, if the result indicates a generic failure, radio is off, or there is a null PDU, the method also breaks without performing any additional tasks.
}, 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
This article demonstrates how to retrieve SMS messages from the Inbox using the SMS inbox URI The example code provided defines a class, SMSlnboxDemo, which extends ListActivity and utilizes a ListAdapter to display the retrieved messages The static final URI for accessing the SMS inbox is specified as "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 trên các thiết bị, giúp chuyển đổi các hành động từ thế giới thực thành dữ liệu cho ứng dụng.
- 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 implement the SensorEventListener interface in an Android application, create a class named MainActivity that extends Activity Within this class, initialize a SensorManager and a Sensor for light detection, and declare a TextView for displaying results Additionally, utilize a StringBuilder to manage messages efficiently, ensuring optimal performance in handling sensor data.
@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.
Để truy cập trực tiếp các giá trị của cảm biến theo thời gian, cần thực hiện các phương thức API của driver cảm biến và thiết lập lại giao diện sử dụng.
Tốc độ truy xuất dữ liệu của cảm biến không đủ nhanh để đáp ứng yêu cầu của một số tác vụ Tuy nhiên, người dùng có thể tùy chỉnh các phương thức trong thư viện thông qua cơ chế JNI để cải thiện hiệu suất.
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 để ghi nhận các biến đổi về hướng và vị trí của thiết bị trong không gian, liên quan chặt chẽ đến trọng lực và các lực tác động.
Các thông số trên các trục x, y, z sẽ được tổng hợp và trả về 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 class is utilized to manage sensor events, specifically the accelerometer, which detects changes in motion A SensorEventListener is implemented to handle these changes, capturing the sensor data when the accelerometer is triggered The values obtained represent the lateral, longitudinal, and vertical axes of acceleration, with xAxis_lateralA, yAxis_longitudinalA, and zAxis_verticalA corresponding to the respective axes.
5.2 Near Field Communacation Sensor (NFC)
NFC (Giao tiếp tầm ngắn) là một tiêu chuẩn giao tiếp cho phép thiết bị di động tương tác 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.
- 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à áp dụng hệ thống Tag Dispatch để phân loại các loại dữ liệu khác nhau, từ đó khởi động ứng dụng tương ứng.
- 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 using ACTION_SENDTO as the first argument and a URI formatted as smsto: as the second argument The text message is 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 in an Android application, retrieve the phone number from the input field and ensure that both the message and phone number are not empty Create an intent with the action `ACTION_SENDTO` using the `smsto:` URI scheme, and include the message body as an extra Finally, 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 tất cả các trường thông tin đã được điền đầy đủ, người dùng chỉ cần nhấp vào 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 đượ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 layout defines a LinearLayout for an Android application, setting its orientation to vertical and matching the parent dimensions for both width and height It includes padding on all sides, specified by the activity's horizontal and vertical margin dimensions, ensuring a well-spaced layout Additionally, the layout is centered both horizontally and vertically, enhancing the visual appeal of the user interface The tools namespace indicates that this layout is associated with the MainActivity class in the com.chikeandroid.tutsplust_telephony package.
In the code snippet below, we create an ACTION_DIAL intent to display the dialer interface, with the phone number extracted from our tel URI scheme: tel:XXXXXXXX It's important to note that no special permissions are required for this functionality.
@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 chạy ứng dụng và nhấp vào nút Dial, ứng dụng sẽ chuyển đến giao diện quay số, cho phép bạn thực hiện cuộc gọi Để tạo cuộc gọi trực tiếp từ ứng dụng của bạn, hãy thay đổi intent từ ACTION_DIAL thành ACTION_CALL, nhưng cần lưu ý rằ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 using Android Image Assets Right-click on the drawable folder, select 'New,' and then choose 'Image Asset' to name it ic_action_fingerprint.