Truyền Dữ Liệu Qua Lại Giữa Các Activity

Cho đến bài học hôm nay, chắc hẳn các bạn đã rất tự tin với việc thao tác với Activity rồi. Tuy nhiên Activity vẫn còn nhiều điều hay ho khác mà bạn vẫn nên biết. Một trong những điều đó chính là việc làm thế nào mà các Activity có thể “nói chuyện” được với nhau, hay nói cách khác là truyền dữ liệu cho nhau.

Nếu bạn là người mới tiếp cận Android, ngay lúc này đây, có thể bạn vẫn chưa thấy được nhu cầu từ việc truyền dữ liệu qua lại giữa các Activity. Nhưng tin mình đi, mình và những bạn có kinh nghiệm khác đều đã gặp phải nhu cầu này khá sớm. Ngay cả TourNote cũng cần phải xây dựng chức năng truyền dữ liệu qua lại giữa hai Activity rồi đấy. Nếu thấy thú vị thì mời các bạn cùng xem tiếp bài học nhé.

1. Tại Sao Phải Truyền Dữ Liệu Qua Lại Giữa Các Activity?


Bạn cũng đã biết, mỗi Activity chính là một màn hình của ứng dụng (cho đến bài học hôm nay thì đúng là vậy). Và bạn cũng đã thấy mỗi Activity là một đơn vị độc lập, chẳng hạn mỗi chúng đều có một vòng đời khác nhau. Như vậy sẽ rất khó nếu như chúng không có một cơ chế nào đó truyền đạt dữ liệu qua cho nhau.

Mình giả sử bạn đang xây dựng ứng dụng email. Trong ứng dụng của bạn có một Activity hiển thị danh sách tóm tắt các email đến, giả sử Activity này có tên là ListActivity. Và một Activity hiển thị nội dung cụ thể của từng email, giả sử tên của nó là DetailActivity. Ban đầu khi mở ứng dụng, người dùng sẽ nhìn thấy ListActivity trước, khi họ nhấn vào một email trong danh sách các email ở Activity này, ứng dụng sẽ kích hoạt DetailActivity, và truyền thông tin của item mà người dùng đã nhấn để DetailActivity hiển thị nội dung email tương ứng. Tiếp theo nếu người dùng đọc xong email đó ở DetailActivity mà không thấy email quan trọng, họ có thể nhấn nút xóa email, khi này ứng dụng sẽ quay lại ListActivity, và có thông tin trả về từ DetailActivity cho biết email đã bị xóa, ListActivity sẽ xóa item tương ứng với thông tin trả về đó.

Bạn thấy dó, một ví dụ nhỏ thôi mà có khá nhiều lý do để truyền dữ liệu qua lại giữa các Activity rồi. Và thực tế kinh nghiệm của mình thấy rằng hầu hết các Activity trong ứng dụng đều cần kiến thức của bài hôm nay cả.

Vậy chúng ta cùng xem cụ thể cách để truyền dữ liệu qua lại giữa các Activity như thế nào nhé.

2. Cách Truyền Dữ Liệu Qua Lại Giữa Các Activity


Nếu bạn đã thử khai báo các thuộc tính static trong ứng dụng để lưu trữ các dữ liệu mà tất cả các Activity có thể đọc được và chỉnh sửa được. Và bạn cho rằng thuộc tính static này là cách trao đổi dữ liệu giữa các Activity, thì bạn đã sai rồi. Các thuộc tính static trong ứng dụng chỉ nên là các hằng số, hoặc các giá trị dùng chung khác như các link ví dụ mình để ở đây cho bạn xem. Nếu bạn khai báo một thuộc tính static, và set giá trị cho nó, rồi bạn kích hoạt một Activity khác có sử dụng dữ liệu ở thuộc tính static này, sẽ không chắc dữ liệu đó đúng như bạn mong muốn đâu. Một lần nữa, đừng dùng thuộc tính static để chia sẻ dữ liệu giữa các Activity nhé.

Chúng ta chỉ có duy nhất một cách để truyền dữ liệu qua lại giữa các Activity. Đó là cách “nhét” dữ liệu vào Intent và nhờ thành phần này chuyển giúp. Hệ thống sẽ đảm bảo dữ liệu được gửi qua “nguyên vẹn” và kịp thời ở Activity mới.

Ồ, vậy Intent ngoài việc kích hoạt các thành phần của Android, trong đó có Activity như bạn đã biết, nay lại có công năng của “người vận chuyển” nữa.

3. Loại Dữ Liệu Được Sử Dụng Trong Intent


Ở mục trên bạn đã biết rằng, Intent có tác dụng vận chuyển dữ liệu qua các Activity. Vậy dữ liệu sẽ được tổ chức bên trong Intent như thế nào?

Dữ liệu được “nhét” vào trong Intent và được lấy ra khỏi Intent theo các cặp dữ liệu dạng key/valueKey ở đây là một chuỗi, giúp định danh cho dữ liệu value. Nếu bạn để vào trong Intent cặp key/value nào, thì bạn phải lấy ra bởi cặp key/value đó, phải đảm bảo khai báo đúng key và lấy ra đúng kiểu dữ liệu của value khi để vào. Điều này tương tự như khi bạn di chuyển đi chơi xa, thì khi đóng gói hành lý của bạn, nhân viên tiếp nhận hành lý phải dán nhãn tên của bạn hay ID của bạn lên hành lý, để đảm bảo bạn lấy đúng hành lý (chính là value) khi đến nơi dựa vào nhãn tên hay ID đó (chính là key).

Tuy có một cách thôi, nhưng bạn có thể sử dụng một trong hai hình thức sau. Một là sử dụng Extra, hoặc sử dụng Bundle. Sự khác nhau giữa hai cách này theo mình là không quan trọng, bạn nên biết cả hai cách, và sẽ có lời khuyên của mình nên sử dụng cách nào ở bên dưới.

3.1. Dùng Extra

Có thể nói, truyền nhận dữ liệu bằng Extra là cách dễ nhất.

Gửi Dữ Liệu

Đầu tiên, để gửi dữ liệu bằng Extra. Sau khi khai báo Intent và trước khi bạn dùng nó để kích hoạt activity nào đó, bạn có thể sử dụng các phương thức được nạp chồng của nó để gửi dữ liệu. Các phương thức đó có chung một tên là putExtra().

Các phương thức giúp đặt dữ liệu vào Extra
Các phương thức giúp đặt dữ liệu vào Extra

Bạn nhớ là các phương thức putExtra() này không có s đằng sau Extra nhé. Extra có s sẽ dành cho mục Bundle dưới đây.

Với mỗi putExtra() như vậy, tham số đầu tiên chính là key mà mình có nói trên kia. Tham số thứ hai tương tự chính là value. Phương thức này được nạp chồng làm nhiều bản để bạn dễ dàng sử dụng từng loại value mà bạn muốn. Tuy nhiên bạn đừng để ý hai kiểu value là Parcelable và Serializable, hai kiểu này hơi phức tạp một chút, chúng ta sẽ có một bài viết riêng về hai kiểu này khi thích hợp.

Đoạn code sau ví dụ cách để đặt dữ liệu vào Intent bằng Extra.

Nhận Dữ Liệu

Khi này, theo như ví dụ trên thì ContactActivity sẽ được kích hoạt với dữ liệu là ba cặp key/value được truyền qua. Ở phương thức onCreate() hoặc bất cứ chỗ nào của ContactActivity, bạn đều có thể lấy bất cứ cặp key/value nào ra dùng. Bằng cách gọi đến getXxxExtra().

Các phương thức giúp lấy dữ liệu khỏi Extra
Các phương thức giúp lấy dữ liệu khỏi Extra

Mình ghi chung là Xxx, vì Xxx này sẽ được bạn thay thế bằng kiểu dữ liệu phù hợp với key bên “đóng gói”, như getBooleanExtra()getStringExtra()getIntExtra(),… Dĩ nhiên tham số name truyền vào phương thức này phải đúng là key bên đóng gói luôn.

Một số phương thức cần phải có tham số thứ hai, tham số này chính là dữ liệu mặc định nếu như hệ thống không tìm thấy dữ liệu với key mà bạn cung cấp. Việc cung cấp tham số thứ hai này tránh một số lỗi xảy ra đối với chương trình của chúng ta.

Đoạn code sau minh họa cách lấy dữ liệu ra khỏi Intent bằng Extra ở onCreate() của Activity. Bạn có thể thấy từng cặp key/value khớp với khi bạn đặt dữ liệu vào trên kia.

3.2. Dùng Bundle

Thực ra Bundle và Extra không khác gì nhau hết. Nếu như Extra trên kia sẽ “xé lẻ” dữ liệu ra và gởi theo từng dòng. Thì Bundle sẽ giúp bạn “đóng gói” dữ liệu lại và gởi nguyên kiện. Tất nhiên Bundle sẽ tiện hơn trong trường hợp bạn muốn gởi cùng một bộ dữ liệu đến nhiều Activity khác nhau.

Ngoài nhiệm vụ đóng gói dữ liệu để truyền qua lại giữa các Activity ở bài học này, thì Bundle còn dùng trong một số mục đích khác, đơn cử như truyền dữ liệu qua Fragment mà bạn sẽ được biết ở bài sau. Nên tốt hơn hết bạn nên học cách sử dụng Bundle ngay từ bài này nhé.

Gửi Dữ Liệu

Chỉ có phát sinh vài dòng code so với Extra trên kia thôi, đầu tiên là dòng tạo ra Bundle. Sau đó vẫn là các dòng đặt dữ liệu vào Bundle, các dòng này có hơi khác với các dòng đặt dữ liệu vào Extra một chút, nếu với Extra bạn dùng các phương thức nạp chồng với cùng một tên putExtra() thì với Bundle bạn phải dùng đúng phương thức putXxx() với Xxx là kiểu dữ liệu bạn cần dùng.

Các phương thức giúp đặt dữ liệu vào Bundle
Các phương thức giúp đặt dữ liệu vào Bundle

Khi Bundle đã chứa đủ dữ liệu, bạn cần phải đặt Bundle này vào trong Intent bằng một dòng code putExtras() (nhớ là có s nhé). Bạn xem code như sau.

Nhận Dữ Liệu

Cũng tương tự như bên gửi thôi, nếu đã gửi theo Bundle, thì bên nhận cũng sẽ nên nhận theo Bundle trước rồi mới lấy từng dữ liệu ra dùng. Để lấy Bundle ra khỏi Intent thì chúng ta có phương thức getExtras().

Sau khi lấy Bundle ra khỏi Intent, việc tiếp theo sẽ gọi đến các phương thức getXxx() của nó. Các phương thức này của Bundle cũng giống như các phương thức getXxxExtra() của Extra trên kia. Chỉ khác một chỗ getXxx() của Bundle thường có hai phương thức nạp chồng, giúp bạn linh động hơn. Thường thì bạn nên dùng getXxx() với hai tham số, như vậy bạn có thể định nghĩa được giá trị mặc định cho từng phương thức khi mà nó không tìm thấy dữ liệu từ key mà bạn cung cấp, giúp tránh một số lỗi không cần thiết.

Các phương thức giúp lấy dữ liệu khỏi Bundle
Các phương thức giúp lấy dữ liệu khỏi Bundle

Để chắc chắn thì khi nhận dữ liệu với Bundle, bạn nên kiểm tra xem Bundle đó có tồn tại hay không (kiểm tra khác null) trước nhé.

Bạn vừa xem qua cách thức chuyển dữ liệu qua lại giữa các Activity. Giờ là lúc chúng ta thực hành xây dựng một chút cho TourNote rồi.

4. Thực Hành Gửi Dữ Liệu Từ MainActivity Qua ContactActivity


Ở mục thực hành của bài 26 chúng ta đã xây dựng sự kiện nhấn cho hai menu item trên ActionBar của MainActivity, sao cho khi người dùng nhấn vào About App hay Help cũng sẽ mở ra ContactActvitity cả. Như hình dưới đây.

Nhìn lại việc mở ContactActivity từ bài hôm trước
Nhìn lại việc mở ContactActivity từ bài hôm trước

Thực ra ContactActivity mà mình muốn hướng đến sẽ chứa hai loại nội dung. Một là thông tin về ứng dụng, hai là thông tin giúp đỡ. Việc phân biệt nội dung nào được hiển thị sẽ dựa vào lựa chọn của người dùng trên menu item của MainActivity. Chính vì vậy chúng ta sẽ xây dựng ContactActivity sao cho có thể nhận được dữ liệu từ MainActivity chuyển qua, dữ liệu này chỉ đơn giản báo cho ContactActivity biết người dùng vừa nhấn chọn About App hay Help.

Bạn đã hiểu yêu cầu của bài thực hành hôm nay rồi đúng không nào. Nên nhớ là chúng ta chỉ nói đến cách thức gửi nhận dữ liệu để ContactActivity hiểu được chuyện gì đang xảy ra thôi nhé, do đó bài này chúng ta chỉ sử dụng Toast để kiểm chứng dữ liệu nhận. Còn việc hiển thị cái gì khi đã nhận dữ liệu thì ở bài sau chúng ta sẽ xây dựng tiếp.

4.1. Xây Dựng Các Giá Trị Hằng Số

Bạn đã biết việc sử dụng Extra hay Bundle là việc lưu trữ các dữ liệu dạng key/value rồi chuyển đi và nhận chúng ở nơi khác đúng không nào. Vậy để đảm bảo các key luôn luôn được dùng đúng, chúng ta nên định nghĩa nó là một giá trị tĩnh (static) và hằng (final). Giá trị này nên định nghĩa bên lớp nhận dữ liệu thì tốt hơn về mặt quản lý code (theo ý mình thôi nhé, bạn có thể định nghĩa một lớp chuyên chứa các giá trị key này). Do đó mình thêm các thuộc tính được tô sáng sau vào ContactActivity.

4.2. Gửi Dữ Liệu Từ MainActivity

Dĩ nhiên bên MainActivity, chúng ta chỉnh sửa một tí nơi kích hoạt ContactActivity, sao cho Intent có thể chứa Bundle mà chúng ta muốn như sau.

4.3. Nhận Dữ Liệu Ở ContactActivity

Như mình có nói, ContactActivity chỉ nhận dữ liệu rồi dùng Toast để show ra làm bằng chứng là nó đã nhận đúng dữ liệu. Còn việc hiển thị cái gì thì bài học sau chúng ta sẽ nói tiếp nhé. Như vậy code của ContactActivity như sau.

Kết quả là, tùy vào cách người dùng chọn vào menu item mà ContactActivity sẽ hiển thị Toast như sau.

Hình ảnh TourNote sau khi thực hành
Hình ảnh TourNote sau khi thực hành

5. Tổng kết


Bạn có thể download source code mẫu của bài này ở đây.

Chúng ta vừa biết thêm kiến thức thú vị nữa về Activity trong Android. Dĩ nhiên sẽ còn nhiều kiến thức khác mà bạn cũng sẽ thấy thích. Hãy tiếp tục theo dõi các bài học của mình nhé.

Bài viết khác

Hồ Diên Lợi
Đến với CNTT là tình cờ, tuy nhiên khi đã tham gia rồi thì mới biết đây chính là đam mê, hy vọng dịch bệnh Covid-19 sẽ qua, để chia sẽ đam mê công nghệ đến nhiều người hơn!

DANH SÁCH BÀI HỌC