Bài viết trước bạn đã hiểu Activity lifecycle rồi đúng không? Như vậy là lý thuyết nền tảng đã xong, bước tiếp theo là làm sao có thể tạo và sử dụng Activity để tương tác với người dùng.
Chúng ta cùng nhau tiếp tục nhé. Và đừng quên mở Forget Me not project mà chúng ta đã tạo ở bài viết trước nhé.
À chưa đọc bài cũ thì đọc ngay nhé vòng đời Activity
Nội dung chính của bài viết
Từng bước tạo và sử dụng Activity
Mình lưu ý là ở phần 2 này, chúng ta sẽ phải code nhiều hơn để vừa tu luyện khả năng thực hành vừa hiểu lý thuyết hơn
Nhưng đừng sợ! Mình sẽ cố gắng hỗ trợ để các bạn hiểu được nhiều nhất có thể
Đây là giao diện ứng dụng Forget me not mà chúng ta đã tạo từ bài viết trước
Cách chạy một Activity
Đến lúc này, ứng dụng Forget me not vẫn còn khá vô dụng bởi bạn không thể thêm bất cứ thứ gì vào danh sách việc cần làm. Để nó đỡ mang tiếng vô dụng, chúng ta sẽ bắt tay vào việc code tính năng: Thêm task mới vào danh sách
Bạn mởi MainActivity.kt, sau đó định nghĩa một hằng số ở đầu class:
private val ADD_TASK_REQUEST = 1
Bạn sẽ sử dụng hằng số này cho việc định danh cho việc khởi tạo một activity( Hay nói cách khác là start một activity)
Viết hàm xử lý logic addTaskClicked()
khi người dùng chạm vào nút “ADD A TASK” như dưới đây:
val intent = Intent(this, TaskDescriptionActivity::class.java) startActivityForResult(intent, ADD_TASK_REQUEST)
Khi người dùng chạm vào nút “ADD A TASK”, Android sẽ gọi hàm addTaskClicked()
. Ở đây bạn tạo một Intent để chạy TaskDescriptionActivity từ MainActivity.( Từ khóa this ám chỉ đến Activity mà nó hiện diện trong code)
Sẽ xuất hiện lỗi biên dịch vì đơn giản là bạn chưa tạo TaskDescriptionActivity. Cứ bình tĩnh, chúng ta sẽ tạo nó ở bước sau.
Bạn có thể chạy một activity theo hai cách: startActivity()
hoặc startActivityForResult()
. Chúng tương tự nhau ngoại trừ việc startActivityForResult()
sẽ trả về kết quả tại hàm onActivityResult()
khi TaskDescriptionActivity kết thúc.
Nhưng trước tiên, Chúng ta cần phải xử lý phần nhập thông tin cho task mới bằng cách tạo Activity: TaskDescriptionActivity.
Tạo Activity để xử lý thêm Task mới
Để tạo một Activity trong Android Studio rất đơn giản. Bạn có thể đọc lại chi tiết các tạo tại đây: Sử dụng Android Studio để tạo Activity
Layout được tạo sẵn khi bạn chọn template là Empty Activity trong Android Studio 3.0 mặc định sử dụng một ConstraintLayout cho view gốc. ConstraintLayout là một loại Layout mới được Google ra mắt năm 2017 với rất nhiều tính năng hay ho. Mình sẽ có một bài viết chi tiết cách sử dụng ConstraintLayout, các bạn chờ nhé.
Ngoài ra, bạn sẽ thấy AndroidManifest.xml được tự động thêm mới dòng sau:
<activity android:name=".TaskDescriptionActivity"></activity>
Đây là phần chúng ta khai báo với hệ thống về một Activity. Android yêu cầu tất cả các ứng dụng khi sử dụng Activity đều phải được khai báo trong AndroidManifest.xml nếu không sẽ bị crash. Điều này đảm bảo ứng dụng của bạn chỉ có quyền sử dụng các Activity được khai báo. Ứng dụng của bạn không thể vô tình sử dụng Activity của ứng dụng khác mà không được phép ( đơn giản chỉ vì có cùng tên Activity)
Có một vài thuộc tính mà bạn có thể đưa vào để xác định thuộc tính cho Activity. Chẳng hạn như label hay icon, hoặc theme để tạo style cho giao diện người dùng.
Trong đó android:name là thuộc tính bắt buộc duy nhất.
Như vậy là xong rồi đấy, bạn thử build và chạy ứng dụng xem kết quả thế nào nhé.
Khi click vào nút ” ADD A TASK “, ứng dụng sẽ nhảy sang màn hình TaskDescriptionActivity. Tất nhiên hiện tại nó chỉ là activity trống. Chúng ta sẽ “đắp thịt” cho nó ngay bây giờ.
Trong TaskDescriptionActivity vừa tạo của bạn, hãy viết thêm đoạn code sau (Bạn có thể copy và paste đè bất cứ thứ gì khác ngoại trừ phần khai báo class và các dấu ngoặc của nó)
// 1 companion object { val EXTRA_TASK_DESCRIPTION = "task" } // 2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_task_description) } // 3 fun doneClicked(view: View) { }
Khi Android Studio báo lỗi vì chưa import thư viện cần thiết cho bất kì hàm nào đó. Đơn giản là bạn chỉ cần để con trỏ vào hàm bị báo lỗi và nhấn Alt-Enter( cho bản Android Studio trên Window)
Mình sẽ giải thích đoạn code trên:
- Sử dụng companion object của Kotlin để định nghĩa các thuộc tính phổ biến được sử dụng trong class. Khái niệm cũng tương tự như static trong Java.
- Overriden hàm onCreate()để thiết lập layout cho Activity thông qua hàm setContentView()
- Ngoài ra, chúng ta viết sẵn hàm để xử lý sự kiện click cho nút Done.
Giờ chúng ta chuyển sang thiết kế giao diện cho màn hình này nhé. Mở res/layout/activity_task_description.xml và sử dụng đoạn code sau:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/default_padding" tools:context="com.raywenderlich.android.forgetmenot.TaskDescriptionActivity"> <TextView android:id="@+id/descriptionLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="@dimen/default_padding" android:text="@string/description" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <EditText android:id="@+id/descriptionText" android:layout_width="match_parent" android:layout_height="100dp" android:inputType="textMultiLine" android:padding="@dimen/default_padding" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/descriptionLabel" /> <Button android:id="@+id/doneButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="doneClicked" android:padding="@dimen/default_padding" android:text="@string/done" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@+id/descriptionText" /> </android.support.constraint.ConstraintLayout>
Chạy lại ứng dụng, chạm vào “ADD A TASK” và màn hình thêm task của bạn đã trông thú vị hơn rất nhiều đấy.
Cách hủy một Activity trong Android (Stopping an Activity)
Cũng quan trọng không kém việc tạo và chạy một Activity thì việc hủy một activity đúng cách cũng vậy.
Trong class TaskDescriptionActivity.kt, bạn kiểm tra xem đã import Kotlin Android Extensions hay chưa?
import android.app.Activity import android.content.Intent import kotlinx.android.synthetic.main.activity_task_description.*
Sau đó lại hàm xử lý click cho nút Done: doneClicked()
// 1 val taskDescription = descriptionText.text.toString() if (!taskDescription.isEmpty()) { // 2 val result = Intent() result.putExtra(EXTRA_TASK_DESCRIPTION, taskDescription) setResult(Activity.RESULT_OK, result) } else { // 3 setResult(Activity.RESULT_CANCELED) } // 4 finish()
Đoạn code đơn giản là lấy giá trị mà người dùng nhập vào EditText. Sau đó đóng gói giá trị đó vào Intent rồi trả lại cho MainActivity. Sau khi trả xong thì gọi hàm finish()
để kết thúc activity
Một khi bạn gọi hàm finish()
thì tại MainActivity hàm onActivityResult()
sẽ được gọi. Tại đây, nhiệm vụ của chúng ta là thêm task mới vừa được tạo vào danh sách.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { // 1 if (requestCode == ADD_TASK_REQUEST) { // 2 if (resultCode == Activity.RESULT_OK) { // 3 val task = data?.getStringExtra(TaskDescriptionActivity.EXTRA_TASK_DESCRIPTION) task?.let { taskList.add(task) // 4 adapter.notifyDataSetChanged() } } } }
Vậy là xong rồi đấy. Bạn lại thử build và chạy lại để kiểm tra ứng dụng nhé.
Activity Configuration Changes là gì? Cách xử lý Configuration Changes như thế nào?
Mình sẽ lấy một ví dụ đơn giản để các bạn dễ hiểu: Khi ứng dụng của chúng ta đang hiển thị một dialog. Trong lúc đó, bạn lại xoay màn hình điện thoại. Dialog sẽ biến mất. Tại sao? Vì khi xoay điện thoại, Activity sẽ bị destroy và được hệ thống tự động tạo lại. Hành động xoay điện thoại là một sự kiện Configuration changes.
Configuration changes tập hợp các sự kiện chẳng hạn như xoay màn hình, hiển thị bàn phím,.. khiến activity bị destroy và khởi động lại. Bạn có thể tìm thấy danh sách các sự kiện của hệ thống khiến activity phải tạo lại ở đây.
Vậy làm sao để activity không bị destroy?
Đây là cách đơn giản nhất: Trong AndroidManifest.xml, tìm thẻ Activity mà bạn muốn. Ví dụ:
<activity android:name=".MainActivity">
Và thêm thẻ configChanges
<activity android:name=".MainActivity" android:configChanges="orientation|screenSize">
Thẻ configChanges có tác dụng là thông báo với hệ thống rằng MainActivity sẽ tự xử lý khi có bất kì sự kiện kiểu như: Xoay màn hình, hoặc thay đổi ngôn ngữ hệ thống…mà hệ thống không phải tái tạo lại Activity đó.
Như đã nói ở trên, MainActivity sẽ phải tự xử lý logic (nếu có) và điều này sẽ được thực hiện trong hàm onConfigurationChanged()
. Trong MainActivity.kt, thêm phương thức onConfigurationChanged()
sau onStop()
:
override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) }
Tại đây, bạn chỉ đơn giản là gọi phương thức onConfigurationChanged()
của lớp cha vì bạn không có logic gì phải xử lý cả.
Ví dụ như ứng dụng chúng ta đang xây dựng Forget me not. Mình có một dialog để xóa một Task. Khi chúng ta áp dụng xử lý Configuration changes như ở trên thì xoay điện thoại thoải mái, dialog không bị mất. (Xem cách tạo Dialog ở đây)
Ngoài ra, với các ứng dụng lớn và sử dụng Fragment thì việc giữ lại Fragment
đang là cách thích hợp nhất để xử lý Configuration changes. Bạn có thể tham khảo bài viết rất chi tiết về Frament và cách sử dụng tại đây: Hướng dẫn toàn tập về Fragment
Tổng kết
Các bạn download toàn bộ source code của ứng dụng mẫu của bài viết bên dưới
Như vậy là mình đã hoàn thành toàn bộ bài viết về cách sử dụng Activity. Mặc dù vẫn chưa phải là tất cả nhưng đây là những kiến thức rất căn bản và bạn hoàn toàn có thể sử dụng cho các dự án thực tế. Bài viết tiếp trong khóa học tự học lập trình Android trong 24 giờ sẽ là một chủ đề khá thú vị: Tìm hiểu Layout là gì và cách thiết kế giao diện hỗ trợ nhiều kích thước màn hình. Các bạn đón đọc nhé
Lỗi này là gì vậy ad:
taskListView.adapter = adapter //taskListView này nó báo là chưa được khai báo, tuy nhiên bên phần activity_main.xml thì đã có code:
tương tự các item sau cũng đều hiện lỗi:
dateTimeTextView,
Và phần import này cũng đang lỗi nữa
import kotlinx.android.synthetic.main.activity_main.*
Bạn thử sync lại gradle xem có fix đc kg nhé!
sao e tải file app hoàn chỉnh về mở bằng Android Studio thì ko chạy được vậy ạ. Chỗ nút run của Android Studio nó xám ko bấm được ạ
Bạn có thể chụp ảnh screenshot cho mình xem đc không?
ad ơi hàm này chèn vào đâu
val intent = Intent(this, TaskDescriptionActivity::class.java)
startActivityForResult(intent, ADD_TASK_REQUEST)
Hi,
bạn viết vào hàm: addTaskClicked() . Đây là hàm được gọi khi người dùng click vào nút “ADD TASK”