07 February 2013

การส่งข้อมูลระหว่าง Activity ผ่าน Intent

Updated on

        กลับมาสู่เรื่องพื้นฐานอีกเรื่องหนึ่ง คือเรื่องการ Intent ระหว่าง Activity ก็จะรู้กันอยู่แล้วว่า Intent คือการข้ามไปอีก Activity หนึ่ง หรือข้ามไปอีกหน้า

        ทีนี้เจ้าของบล็อกจะมาพูดถึงเรื่องการส่งข้อมูลข้ามไปยังอีก Activity บ้าง โดยการส่งข้อมูลไปยังอีกหน้าหรืออีก Activity (ขอเรียกว่า "อีกหน้า" ละกัน) ก็จะส่งผ่านการ Intent นั่นเอง โดยที่ Intent จะสามารถส่งตัวแปรได้ในระดับนึง

Activity ที่จะส่งข้อมูล
Button buttonIntent = (Button)findViewById(R.id.buttonIntent);
buttonIntent.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        Intent intent = new Intent(Main.this, Data.class);
        startActivity(intent);
    }
});

        สำหรับคำสั่งข้างต้นนี้ก็คงจะคุ้นเคยกันอยู่แล้ว กับการ Intent ง่ายๆ จากคำสั่งข้างต้น ถ้าดูคร่าวๆก็จะพอรู้ได้ว่า เมื่อกดปุ่ม buttonIntent ก็จะทำการ Intent จากเดิมที่เป็นหน้า Main ข้ามไปยังหน้า Data

        สมมติว่าเจ้าของบล็อกมีตัวแปรอยู่ในหน้า Main แล้วทีนี้ต้องการส่งตัวแปรไปด้วยเมื่อกดปุ่ม buttonIntent โดยตัวแปรนั้นเป็นตัวแปร Integer ที่ตั้งชื่อไว้ว่า x


        เจ้าของบล็อกก็จะเพิ่มคำสั่งของ Intent เข้าไปตามนี้

Intent intent = new Intent(Main.this, Data.class);
intent.putExtra("MyValue", x);
startActivity(intent);

        หมายเหตุ - ตัวแปร x เป็นตัวแปรที่ประกาศไว้แล้วนะ ไม่ใช่ว่าอยู่ๆเรียกมาส่งค่าเลย

        จากคำสั่งตัวอย่างจะเห็นว่าเจ้าของบล็อกใช้คำสั่ง putExtra เพิ่มเข้ามา แต่ทีนี้ให้ดูส่วนประกอบของคำสั่งนี้ก่อน จะเห็นว่ามีตัวแปรสองตัว คือ


        1. Keyword สำหรับระบุให้รู้ว่า Keyword นี้เก็บตัวแปรนี้ไว้อยู่ ดังนั้นฝั่ง Data เวลาจะรับค่าก็ต้องระบุว่า Keyword คือ MyValue จึงจะรับค่าตัวแปร x ที่ส่งจาก Main ได้ (Keyword ตั้งชื่ออะไรก็ได้ ขอให้กำหนดตรงกันทั้งสองฝั่งก็พอ)

        2.ตัวแปรที่ต้องการจะส่ง โดยตัวอย่างนี้จะส่งตัวแปร x

        ทีนี้พอ Intent ไปหน้า Data ก็จะมีค่าที่กำหนดไว้ถูกส่งไปด้วย โดยฝั่ง Data ก็จะต้องใช้คำสั่งรับค่าด้วย ไม่ใช่ว่าใช้ได้เลย และสำหรับค่าที่จะส่งไม่ได้ตายตัวว่าต้องเป็นตัวแปรเท่านั้น จะส่งเป็นตัวแปรหรือจะส่งเป็นค่าตรงๆก็ได้เช่นกัน เช่น

intent.putExtra("MyValue", x);

intent.putExtra("MyValue", 50);

intent.putExtra("MyValue", array.size());

        ทีนี้มาดูกันต่อกับหน้า Main ที่จะส่งข้อมูลก่อน ยังไม่ไปฝั่ง Data ที่รับค่า เพราะอยากจะอธิบายเป็นฝั่งๆไปให้เข้าใจก่อน จะได้ไม่สับสน

        สำหรับค่าหรือตัวแปรที่ส่งผ่าน Intent ได้ จะมีทั้งหมดดังนี้

        • boolean
        • boolean[]
        • byte
        • byte[]
        • char
        • char[]
        • CharSequence
        • CharSequence[]
        • double
        • double[]
        • float
        • float[]
        • int
        • int[]
        • long
        • long[]
        • short
        • short[]
        • String
        • String[]
        • ArrayList<CharSequence>
        • ArrayList<String>
        • ArrayList<Integer>
        • Parcelable 
        • Serializable 

        ก็จะเห็นว่าค่าที่ส่งได้ทั้งหมดจะเป็นตัวแปรพื้นฐานทั้งหมดเลย ตั้งแต่ Boolean ยัน String แล้วแต่ผู้ใช้ว่าจะส่งค่าแบบไหนไปอีกหน้า ซึ่งรูปแบบการส่งก็เหมือนกันหมดคือมี Keyword และค่าที่จะส่ง

        1. ส่งตัวแปร x ที่เป็น Array Integer โดยกำหนด Keyword ว่า MyX

        2. ส่งค่า 299792.458 ที่เป็น Double โดยกำหนด Keyword ว่า LightSpeed

        3. ส่งตัวแปร str ที่เป็น String โดยกำหนด Keyword ว่า Message

        4. ส่งตัวแปร state ที่เป็น Boolean โดยกำหนด Keyword ว่า DEVICE_STATE


        สำหรับ Keyword สำคัญอย่างไร ก็มาดูต่อในหน้าที่จะรับข้อมูล


Activity ที่จะรับข้อมูล

        มาดูกันต่อที่หน้า Data ที่จะให้รับข้อมูลกันต่อเลย ซึ่งการรับข้อมูลจาก Activity ก่อนหน้า ก็ไม่ยากอะไร แค่สร้างตัวแปรมารับ และกำหนด Keyword ให้ตรง เท่านี้ก็รับค่าที่ส่งมาได้แล้ว โดยใช้คำสั่งตามนี้เลย

Bundle bundle = getIntent().getExtras();
String text = bundle.getString("Message");

String text = getIntent().getExtras().getString("Message");

        จะเห็นว่าไม่มีอะไรมากเลย สร้างตัวแปร ระบุ Keyword แค่นั้นเอง โดยจะเห็นว่าตัวแปรที่รับ ไม่จำเป็นต้องตั้งชื่อตัวแปรให้ตรงกับใน Main ในฝั่ง Main ใช้เป็นตัวแปรชื่อ str แต่ในฝั่ง Data เอาตัวแปรชื่อ text มารับ เพราะการส่งข้อมูลผ่าน Intent ไม่ได้อิงที่ชื่อตัวแปร แต่อิงที่ชื่อ Keyword ดังนั้นจะประกาศตัวแปรชื่ออะไรก็ได้ ขอแค่ระบุ Keyword ให้ถูกก็พอ และสำหรับคำสั่งรับค่าจะต้องใช้ให้ตรงกับประเภทของค่านั้นๆด้วย

        • getBoolean สำหรับ boolean
        • getBooleanArray สำหรับ boolean[]
        • getByte สำหรับ byte
        • getByteArray สำหรับ byte[]
        • getChar สำหรับ char
        • getCharArray สำหรับ char[]
        • getCharSequence สำหรับ CharSequence
        • getCharSequence สำหรับ CharSequence[]
        • getCharSequenceArrayList สำหรับ ArrayList<CharSequence>
        • getDouble สำหรับ double
        • getDoubleArray สำหรับ double[]
        • getFloat สำหรับ float
        • getFloatArray สำหรับ float[]
        • getInt สำหรับ int
        • getIntArray สำหรับ int[]
        • getIntegerArrayList สำหรับ ArrayList<Integer>
        • getLong สำหรับ long
        • getLongArray สำหรับ long[]
        • getShort สำหรับ short
        • getShortArray สำหรับ short[]
        • getString สำหรับ String
        • getStringArray สำหรับ String[]
        • getStringArrayList สำหรับ ArrayList<String>

        และสำหรับการรับค่าจาก Intent เป็นไปได้ควรใช้คำสั่งใน onCreate เลย เพื่อเป็นการเตือนตัวเองไม่ให้ลืมว่ามีค่าเหล่านี้ถูกส่งมาผ่าน Intent และไม่ให้คำสั่งเกิดการเรียกใช้กระจัดกระจายไปทั่ว จนโปรแกรมรก

        หมายเหตุ - สำหรับบางคำสั่งจะสามารถกำหนด Default Value ได้ เวลาที่โปรแกรมไม่สามารถดึงค่าจาก Keyword นั้นๆได้ (เป็น null) จะอิงค่าจาก Default Value แทน

boolean state = getIntent().getExtras().getBoolean("STATUS", true);

        ถ้าไม่มีค่าใน Keyword ที่ชื่อ STATUS ก็จะให้กำหนดค่าเป็น true แทน


        สำหรับคำสั่งที่สามารถกำหนด Default Value ได้ก็จะมีดังนี้

        • getBoolean
        • getByte
        • getChar
        • getDouble
        • getFloat
        • getInt
        • getLong
        • getShort

        ทีนี้ค่าที่ส่งมาทั้งหมดจาก Main ก็จะสามารถรับค่าได้ดังนี้

Bundle bundle = getIntent().getExtras();
String text = bundle.getString("Message");
int[] array_int = bundle.getIntArray("MyX");
boolean state = bundle.getBoolean("DEVICE_STATE");
double value = bundle.getDouble("LightSpeed");

        อย่าลืมว่าตัวแปรที่สร้างมารับค่าไม่จำเป็นต้องตรงกับที่ส่งมาก็ได้

        ดังนั้นจากที่พล่ามข้างต้นก็จะสามารถสรุปการส่งข้อมูลผ่าน Intent เป็นภาพคร่าวๆได้ตามนี้


        จากนั้นก็จะเอาค่าไปทำอะไรต่อในอีกหน้าก็ตามใจชอบเลย

        สำหรับตัวอย่างในบทความนี้ จะมีหน้า Main และ Data โดยที่หน้า Main จะมีปุ่มให้กด เพื่อไปยังหน้า Data และจะส่งค่าตัวแปรจากหน้า Main ไปยังหน้า Data ด้วย เมื่อมายังหน้า Data ก็จะดึงค่าที่รับมาแสดงบน Text View



Main.java
package app.akexorcist.intentwithdata;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Main extends Activity {
    int[] x = { 2, 4, 6 };
    String str = "Sleeping For Less";
    boolean state = false;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button buttonIntent = (Button)findViewById(R.id.buttonIntent);
        buttonIntent.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                Intent intent = new Intent(Main.this, Data.class);
                intent.putExtra("MyX", x);
                intent.putExtra("LightSpeed", 299792.458);
                intent.putExtra("Message", str);
                intent.putExtra("DEVICE_STATE", state);
                startActivity(intent);
            }
        });
    }
}

        คำสั่งใน Main ก็มีแค่ Button ที่กดแล้วจะ Intent ไปหน้า Data ซึ่งมีการส่งค่าไปหน้า Data ด้วย  โดยส่งไปทั้งหมดสี่ตัว


main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <Button
        android:id="@+id/buttonIntent"
        android:layout_width="150dp"
        android:layout_height="100dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Intent"
        android:textSize="20sp" />

</RelativeLayout>


Data.java
package app.akexorcist.intentwithdata;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class Data extends Activity{

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.data);

        Bundle bundle = getIntent().getExtras();
        String text = bundle.getString("Message");
        int[] array_int = bundle.getIntArray("MyX");
        boolean state = bundle.getBoolean("DEVICE_STATE");
        double value = bundle.getDouble("LightSpeed");
        
        TextView textData = (TextView)findViewById(R.id.textData);
        textData.setText("text = " + text + "\n" + "array_int = " 
                    + String.valueOf(array_int[0]) + ", "
                    + String.valueOf(array_int[1]) + ", "
                    + String.valueOf(array_int[2]) + "\n" 
                    + "state = " + String.valueOf(state) + "\n"
                    + "value = " + String.valueOf(value));
    }
}

        สำหรับคำสั่งใน Data ก็จะประกาศตัวแปรขึ้นมารับค่าที่ส่งมาจาก Main แล้วก็นำไปแสดงใน Text View ที่เตรียมไว้ เท่านี้ก็เสร็จเรียบร้อย


data.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world"
        android:textSize="20sp" />

</RelativeLayout>


AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="app.akexorcist.intentwithdata"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="8" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".Main"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".Data" />
    </application>

</manifest>

        บทความนี้ก็ถือว่าเป็นอีกพื้นฐานหนึ่งที่ผู้ที่หลงเข้ามาอ่านควรจะรู้วิธีการใช้งานเป็นอย่างน้อย ดังนั้นอยากให้ทำความเข้าใจตรงจุดนี้เข้าไว้ เพราะในเวลาที่เขียนแอปพลิเคชันที่มีขนาดใหญ่ขึ้นก็จะไม่พ้นเรื่องนี้เป็นแน่แท้ อีกทั้งยังประยุกต์ใช้กับในเรื่องของ Shared Preference ได้อีกด้วยเพราะว่ามีหลักการกำหนดค่าคล้ายๆกัน

        สำหรับผู้ที่หลงเข้ามาอ่านผู้ใดที่ต้องการไฟล์ตัวอย่างบทความนี้ สามารถดาวน์โหลดได้จาก Intent With Data [Google Drive] หรือ Intent With Data [Direct Link]


        ลองหัดใช้ดูนะ เพราะใช้กันบ่อย