การใช้ Intent เพื่อเปิดหน้า Activity และส่งข้อมูลระหว่าง Activity
บทความนี้ขอนำเสนอบทความพื้นฐานสำหรับมือใหม่เลยครับ เกี่ยบกับเรื่อง Intent และการเปิด Activity หนึ่งไปยังอีก Activity หนึ่ง รวมถึงการส่งข้อมูลระหว่าง Activity ด้วยครับ
จริงๆ ตั้งใจว่าจะไม่เขียนพวกพื้นฐานเท่าไหร่ เพราะหาอ่านได้ตามเว็บอื่นๆ หรือตามหนังสือก็มีอยู่เยอะแยะมากมาย แต่มาคิดอีกที เราอาจจะคิดว่ามันเยอะแยะ แต่บางคนละไม่คิดแบบเรา เค้าอาจจะหาไม่เจอ หรือยังไม่เข้าใจ ก็ต้องพยายามอ่านหลายๆเว็บ ผมก็เลยตัดสินใจ จะทำบทความครอบคลุมพื้นฐานด้วยละกัน อย่างน้อยก็เผื่อมีบางคนมาอ่าน แล้วได้ประโยชน์ ไม่บ้างก็น้อยแหละ :D
มาเข้าเรื่อง Intent และ Activity กันเลยดีกว่า
TLDR
- สร้าง Activity ขึ้นใหม่ สมมติชื่อ
AboutActivity
- เพิ่ม activity name ใน
AndroidManifest.xml
ให้รู้จักAboutActivity
- ใช้
startActivity(intent);
เพื่อเปิดหน้าใหม่ - ใช้
finish()
เพื่อกลับมา Activity เดิม
การเปิด Activity ไปอีก Activity หนึ่ง
สำหรับบางคน ที่เริ่มเขียนใหม่ อาจจะใช้แค่ Activity เดียวในแอพ แต่ว่าอยากจะให้กดปุ่ม แล้วเปิดอีก Activity หนึ่ง หรือเปลี่ยน Activity จะทำยังไง?
เริ่มต้นสร้างโปรเจ็คใหม่เลยครับ สมมติว่าทุกคน สามารถสร้างโปรเจ็คใหม่เป็นนะครับ ใครไม่เป็นอ่านบทความนี้ สร้างโปรเจ็คด้วย Android Studio
ที่นี้เราจะใช้ ไฟล์ 2 ไฟล์คือ
- MainActivity.java
- AboutActivity.java
และเลเอาท์ 2 ไฟล์ คือ
- activity_main.xml
- activity_about.xml
เลเอาท์สร้างไว้ที่ /res/layout/
ส่วน Activity สร้างไว้ที่เดียวกับคลาส MainActivity
เลย
Layout
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button_about"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="About"
android:paddingTop="24dp"
android:paddingBottom="24dp"
android:paddingLeft="48dp"
android:paddingRight="48dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
<ImageView
android:layout_width="128dp"
android:layout_height="128dp"
android:id="@+id/imageView"
android:src="@drawable/ic_launcher"
android:layout_above="@+id/button_back"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
activity_about.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="AboutActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="36sp"
android:layout_marginTop="32dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>
<Button
android:id="@+id/button_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Back"
android:paddingTop="24dp"
android:paddingBottom="24dp"
android:paddingLeft="48dp"
android:paddingRight="48dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
ทีนี้เป้าหมายเรา คือ กดปุ่ม Button จาก MainActivity
แล้วให้ทำการเปิด AboutActivity
ขึ้นมา จากนั้นหน้า AboutActivity
เมื่อกด Back ก็จะกลับมาหน้า MainActivity
อีกครั้ง
ง่ายมากครับ แค่เพิ่มโค๊ด สองบรรทัดนี้ลงไป ใน onClickListener
คือเมื่อทำการกดปุ่มก็จะเปิด AboutActivity
ขึ้นมา นั่นเอง
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
โค๊ดมันมีแค่นี้แหละ คือ เราจะสร้างออปเจ็ค intent ขึ้นมา โดยรับ parameter 2 ตัว ตัวแรกคือ Context ภายใน Activityแรก และ parameter ตัวที่สองคือ Activity ที่เราต้องการเปิด
โค๊ดเต็มๆของ MainActivity
คือ
package com.devahoy.sample.intent;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonAbout = (Button) findViewById(R.id.button_about);
buttonAbout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, AboutActivity.class);
startActivity(intent);
}
});
}
}
ส่วนฝั่ง AboutActivity
เมื่อกดปุ่ม back ก็จะกลับมา Activity จะใช้ finish()
ครับ หมายถึงการปิด Activity ครับ แต่ถ้าเราไปใช้แบบ ด้านบน คือเปลี่ยนเป็นแบบนี้
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
มันก็จะเปิดหน้า MainActivity ได้ครับ แต่ว่ามันจะมีหน้าซ้อนกัน 2 หน้าครับ (โดยปกติใน Android Activity มันจะถูกเปิดซ้อนกันไปเรื่อยๆครับ) ไม่เชื่อคุณลองรันโปรแกรม แล้วสั่งเปิดหน้าสอง แล้วกด back หลายๆครั้งดูครับ Activity มันจะซ้อนกันตามจำนวนที่คุณกดเลย
คลาส AboutActivity.java
package com.devahoy.sample.intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Button;
public class AboutActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
Button buttonBack = (Button) findViewById(R.id.button_back);
buttonBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}
แต่ถ้าหากอยากจะใช้แบบ ส่ง Intent ก็ทำได้ครับ โดย MainActivity
ต้อง เรียก finish()
ด้วยครับ เช่น
MainActivity.java
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
finish();
AboutActivity.java
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
แบบนี้ก็จะไม่เกิด Activity ซ้ำกันแล้ว แต่ว่าในกรณีที่เรามี 2 Activity แค่กดปิด แล้วกลับไปหน้าหลัก ดีกว่า ที่จะต้องมาสร้างหน้าหลักใหม่ อีก จริงมั้ยครับ :D
สุดท้ายที่ไฟล์ AndroidManifest.xml
เราต้องไปเพิ่มในส่วนของ Android Name ให้มันรู้จัก Activity ที่เราเพิ่มมา
<activity android:name=".AboutActivity">
</activity>
ปัญหาการใช้ this
จะเห็นว่า บางทีพวกนี้จะเป็นปัญหาสำหรับมือใหม่เลย คือใส่ this แต่ไม่รู้ว่ามันอยู่ใน block, scope ไหน ก็ยังไปใส่ this เช่น
btnSubmit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(this, AboutActivity.class);
startActivity(intent);
}
});
ด้านบน เรียกเปิด Activity ใหม่ จากภายใน Anonymous Inner Class ของ OnClickListener ซึ่ง this มันก็จะไปมองเป็น OnClickListener ไม่ได้มองเป็น MainActivity วิธีแก้ก็ต้องเปลี่ยนเป็นแบบนี้
btnSubmit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, AboutActivity.class);
//หรือแบบนี้
//Intent intent = new Intent(getApplicationContext(), AboutActivity.class);
startActivity(intent);
}
});
หรือทางแก้อีกแบบ ก็ประกาศตัวแปรหนึ่งเป็น global ไปเลย เช่น
public class YourClass extends Activity {
private Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
mContext = getApplicationContext();
}
}
ทีนี้ทุกอย่างที่ต้องการ ApplicationContext ก็แค่ส่ง mContext
ไปเท่านั้น
อีกปัญหานึงที่เจอบ่อยๆ คือ จะเปิด Activity ใหม่ จากหน้า Fragment แต่ดันไปใช้ this หรือ MyFragment.this มันก็จะไปได้อย่างไร? เนื่องจาก context มันอยู่ใน Activity ฉะนั้นก็ต้องเรียกแบบนี้
Intent intent = new Intent(getActivity(), AboutActivity.class);
startActivity(intent);
การส่งข้อมูลข้าม Activity
วิธีการส่งข้อมูลข้าม Activity กรณีเรามีข้อมูลอยู่ MainActivity
แต่อยากให้มันไปโชว์ที่หน้า DetailActivity
เราจะทำอย่างไร?
วิธีการ ก็คือใช้ Intent เหมือนเดิมครับ โดยทาง Intent จะมีเมธอด putExtra(key, value)
มาให้เราสำหรับส่งค่าไปครับ parameter แรกจะเป็นชื่อเรียก ส่วน parameter สอง จะเป็นชนิดของตัวแปร จะเป็น int, String, boolean, float ก็ได้ครับ ดังเช่นตัวอย่าง
ในคลาส MainActivity
เรา ทำการเปิด AboutActivity
โดยส่งค่า ไปด้วย
Intent intent = new Intent(this, AboutActivity.class);
intent.putExtra("name", "devahoy");
intent.putExtra("isSmart", true);
intent.putExtra("star", 5);
startActivity(intent);
จากนั้นที่ AboutActivity
ก็รับค่าที่ส่งมา แบบนี้ เปิด onCreate()
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
String name = bundle.getString("name");
int star = bundle.getInt("star");
boolean isSmart = bundle.getBoolean("smart");
String result = String.format("Name is %s, star : %s, smart : %s",
name, star, isSmart);
Toast.makeText(this, "Name : " + result, Toast.LENGTH_SHORT).show();
}
เราจะทำการเช็คก่อน ว่ามีการส่งค่ามาจริงไหม ถ้ามีจริง ก็ใช้ Bundle.getXXX
เช่นจะรับค่า String ก็ใช้ getString(key)
ข้างในก็เป็น key ตัวเดียวกับที่่ไว้ก่อนส่งมาจาก MainActivity
สุดท้าย ก็โชว์ Toast แสดงผลลัพธ์ที่ส่งมา มีแค่นี้แหละครับ ลองนำไปประยุกต์ใช้กันดูครับ
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit