Intent
Intent là cơ chế cho phép các Activity có thể giao tiếp với nhau. Có hai dạng intent là intent tường minh (explicit intent) và intent ngầm định (implicit intent). Trong bài này chúng ta sẽ khám phá kiểu Intent tường minh.
Intent tường minh (explicit intent)
Giao tiếp giữa các Activity
Intent là cơ chế cho phép giao tiếp giữa các Activity và giả sử ActivityA muốn giao tiếp với ActivityB. Intent tường minh yêu cầu chúng ta phải xác định rõ Activity (ActivityB) mà Activity hiện tại (ActivityA) muốn giao tiếp. Cách sử dụng intent tường minh rất phổ biến khi chúng ta cần thực hiện giao tiếp giữa các Activity trong cùng một ứng dụng. Đoạn mã sau minh họa cách giao tiếp với ActivityB thông qua intent:
//tạo thể hiện lớp Intent Intent i = new Intent(this, ActivityB.class); //bắt đầu giao tiếp với Activity B startActivity(i);
Đầu tiên chúng ta phải tạo một thể hiện (i) của lớp Intent với hai tham số là context của Activity hiện tại muốn giao tiếp với ActivityB (mặc định là this). Kế tiếp chúng ta sẽ thực thi giao tiếp với phương thức startActivity với đối số là thể hiện của Intent vừa tạo (i).
Trong quá trình giao tiếp, ActivityA có thể gửi dữ liệu đến ActivityB thông qua phương thức putExtra() của lớp Intent như đoạn mã sau:
//tạo thể hiện lớp Intent Intent i = new Intent(this, ActivityB.class); //gửi đến Activity dữ liệu là chuỗi myString i.putExtra("myString", "This is a message for ActivityB"); //gửi đến Activity dữ liệu là số nguyên 100 i.putExtra("myInt", 100); //bắt đầu giao tiếp với Activity B startActivity(i);
Dữ liệu được nhận bởi ActivityB thông qua phương thức getIntent().getExtras() và được gán đến đối tượng Bundle như đoạn mã sau:
Bundle datafromActivityA = getIntent().getExtras(); if (datafromActivityA!= null) { String myString = datafromActivityA.getString("myString"); int myInt = datafromActivityA.getInt("myInt"); }
Khi thực hiện giao tiếp giữa ActivityA và ActivityB, các Activity sẽ được cấu hình như sau trong tập tin manifest của ứng dụng:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=<a href="http://schemas.android.com/apk/res/android"> http://schemas.android.com/apk/res/android</a> package="com.ebookfrenzy.intent1.intent1" > <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name="com.ebookfrenzy.intent1.intent1.ActivityA" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="ActivityB" android:label="ActivityB" > </activity> </application> </manifest>
Trả về dữ liệu đến một Activity
Như trên đã đề cập, ActivityA có thể giao tiếp và gửi dữ liệu đến ActivityB thông qua Intent và ActivityB có thể nhận dữ liệu từ ActivityA thông qua một đối tượng trung gian gọi là Bundle. Tuy nhiên, một câu hỏi được đặt ra là ActivityB có thể gửi dữ liệu trở lại ActivityA hay không? Câu trả lời là có thể nếu chúng ta xem ActivityB là một Activity con (sub-Activity) của ActivityA. Điều này có thể đạt được bằng cách gọi phương thức startActivtiyForResult() thay vì gọi phương thức startActivity():
startActivityForResult(i, REQUEST_CODE);
Tham số REQUEST_CODE là giá trị được dùng để xác định dữ liệu trả về ActivityA.
ActivityB (lúc này được xem là Activity con của ActivityA) muốn trả về dữ liệu đến ActivityA phải thực hiện phương thức finish(). Mục đích của việc gọi finish() nhằm tạo một đối tượng Intent mới chứa dữ liệu trả về và gọi phương thức setResult() với các tham số là RESULT_OK nếu trả về thành công hay RESULT_CANCEL nếu trả về thất bại và đối tượng Intent vừa tạo:
public void finish() { Intent data = new Intent(); data.putExtra("returnString1", "Message to parent activity"); setResult(RESULT_OK, data); super.finish(); }
Để nhận dữ liệu, Activity cha (ActivityA) phải thực hiện phương thức onActivityResult() như đoạn mã sau:
protected void onActivityResult(int requestCode, int resultCode, Intent data) { String returnString; if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) { if (data.hasExtra("returnString1")) { returnString = data.getExtras().getString("returnString1"); } } }
Ứng dụng minh họa với Intent tường minh và quá trình giao tiếp giữa các activities
Tạo ActivityA
Tạo một ứng dụng mới tên ExplicitIntent, nhập ngocminhtran.com trong Company Domain, chọn Phone and Tablet và API 14, chọn Empty Activity và nhập tên ActivityA trong Activity Name và activity_a trong Layout Name.
Mở tập tin activity_a.xml trong chế độ Design, xóa TextView “Hello World!” mặc định, thêm một TextView, một EditText (Plain Text), và một Button với giá trị thuộc tính ID và Text lần lượt là:
View | ID | Text |
TextView | textView1 | TextView |
EditText | editText1 | |
Button | button1 | Ask Question |
Định vị các views trên giao diện như sau:
Tạo ActivityB
Tìm đến gói com.ngocminhtran.explicitintent trong thư mục app > java và nhấn chuột phải vào gói này chọn New > Activity > Empty Activity:
Trong cửa sổ Configure Activity nhập ActivityB trong Activity Name và activity_b cho Layout Name
Mở tập tin activity_b.xml trong chế độ Design và thêm một TextView, một EditText (Plain Text) và một Button đến giao diện với các thuộc tính ID và Text như sau:
View | ID | Text |
TextView | textView1 | TextView |
EditText | editText1 | |
Button | button1 | Answer Question |
Định vị các views như sau:
Lúc này chúng ta đã có ActivityA và ActivityB và hai Activity này sẽ giao tiếp với nhau thông qua đối tượng Intent. Khi hai Activity được tạo, Android Studio sẽ tự động tạo tập tin AndroidManifest.xml trong thư mục app > manifests với nội dung như sau:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ngocminhtran.explicitintent"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".ActivityA"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ActivityB"></activity> </application> </manifest>
Gửi dữ liệu từ ActivityA đến ActivityB
Mở tập tin ActivityA.java và thêm phương thức onClick() có nội dung như sau:
public void onClick(View view) { Intent i = new Intent(this, ActivityB.class); final EditText editText1 = (EditText) findViewById(R.id.editText1); String myString = editText1.getText().toString(); i.putExtra("qString", myString); startActivity(i); }
Chú ý import:
import android.content.Intent; import android.view.View; import android.widget.EditText;
Mở tập tin activity_a.xml trong chế độ Text và tìm đến phần tử <Button> và thêm thuộc tính onClick như sau:
<Button android:id="@+id/button1" android:text="Ask Question" android:onClick="onClick" ... />
ActivityB nhận và xử lý dữ liệu từ ActivityA
Mở tập tin ActivityB.java và thêm đoạn mã sau vào phương thức onCreate():
public class ActivityB extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_b); Bundle extras = getIntent().getExtras(); if (extras == null) { return; } String qString = extras.getString("qString"); final TextView textView = (TextView) findViewById(R.id.textView1); textView.setText(qString); } }
Thực thi ứng dụng và nhập một câu hỏi bất kỳ vào EditText trong ActivityA:
Nhấn nút ASK QUESTION, ứng dụng sẽ chuyển sang ActivityB và câu hỏi chúng ta vừa nhập trong TextView
Chuyển ActivityB thành activity con của ActivityA
Bây giờ nếu chúng ta nhập câu trả lời vào EditText của ActivityB và nhấn nút ANSWER QUESTION, chúng ta muốn ứng dụng sẽ chuyển trở lại ActivityA cùng với câu trả lời từ ActivityB trong TextView. Muốn thực hiện điều này đầu tiên chúng ta phải biến ActivityB trở thành Activity con của ActivityA bằng cách gọi phương thức startActivityForResult() thay vì gọi startActivity() trong lớp ActivityA:
public class ActivityA extends AppCompatActivity { private static final int REQUEST_CODE = 3; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); } public void onClick(View view) { ... //startActivity(i); startActivityForResult(i, REQUEST_CODE); } }
Với giá trị REQUEST_CODE là một giá trị ngẫu nhiên bất kỳ (trong ví dụ này là 3). Kế tiếp chúng ta sẽ thực thi phương thức onActivityResult() trong lớp ActivityA để nhận giá trị trả về từ activity con (ActivityB):
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if ((requestCode == REQUEST_CODE) && (resultCode == RESULT_OK)) { TextView textView1 = (TextView) findViewById(R.id.textView1); String returnString = data.getExtras().getString("returnData"); textView1.setText(returnString); } }
Chuyển dữ liệu từ ActivityB trờ lại ActivityA
Sau khi ActivityB trở thành activity con của ActivityA, lớp ActivityB phải thực hiện phương thức finish() để tạo một Intent mới và gọi phương thức setResult() để chuyển dữ liệu trở lại ActivityA
@Override public void finish() { Intent data = new Intent(); EditText editText1 = (EditText) findViewById(R.id.editText1); String returnString = editText1.getText().toString(); data.putExtra("returnData", returnString); setResult(RESULT_OK, data); super.finish(); }
Tạo phương thức onClick() thực thi finish()
public void onClick(View view) { finish(); }
Gọi phương thức onClick bằng cách mở tập tin activity_b.xml trong chế độ Text và thêm thuộc tính onClick của phần tử <button>:
<Button android:id="@+id/button1" android:text="Answer Question" android:onClick="onClick" .../>
Thực thi lại ứng dụng và nhập câu hỏi
Nhấn ASK QUESTION:
Nhập câu trả lời (3) và nhấn ANSWER QUESTION, kết quả:
Lời kết
Trong bài này chúng ta đã tìm hiểu kiểu Intent tường minh và đã thực hiện tạo một ứng dụng minh họa dùng Intent này. Source code đầy đủ các tập tin của ứng dụng ExplicitIntent có thể xem tại GitHub. Trong bài kế tiếp chúng ta sẽ tìm hiệu một kiểu Intent khác, Intent ngầm định (Implicit Intent).
Ý kiến bài viết