PHP Ionic Angularjs Phonegap AJAX Javascript CSS MySQL jQuery Forum

การสื่อสารระหว่าง fragment กับ activity ตอนที่ 3

24 April 2015 By


เพื่อที่จะใช้งาน fragment UI อีก เราควรที่จะสร้างให้แต่ละ fragment มี container ของตัวเอง
มีองค์ประกอบ module ใน layout และชุดคำสั่งการทำงานของตัวเอง   สิ่งหนึ่งที่เราต้องกำหนด
ให้กับ fragment ให้สามารถนำมาใช้ใหม่ คือ เราเชื่อม fragment กับ activity และสัมพันธ์กับ
เหตุผลของโปรแกรม ประกอบขึ้นมาเป็น UI ทั้งหมด
 
บ่อยครั้งที่เราต้องการที่จะสื่อสารระหว่าง fragment เช่น การเปลี่ยนแปลงเนื้อหาตามการ
กระทำของผู้ใช้    ทุกการเชื่อมต่อสื่อสารระหว่าง fragment จะทำผ่าน activity ที่เกี่ยวข้อง
fragment แต่ละอันจะไม่ติดต่อสื่อสารระหว่างกันโดยตรง
 
 
การกำหนด interface
 
เพื่ออนุญาตให้ fragmnt ติดต่อขึ้นยัง activity    เราสามารถกำหนด interface ใน fragment class 
และใช้มันใน activity    การดักจับ interface ของ fragment จะอยู่ในขั้นตอนการเรียกใช้งาน onAttach()
method และสามารถเรียกใช้ method ของ interface เพื่อสื่อสารกับ activity
 
เรามาทดสอบ เพื่อศึกษา การสื่อสารระหว่าง fragment กับ activity
โดยจะขออ้างอิงจากเนื้อหาตอนที่แล้ว 
 
เพิ่มความยืดหยุ่นการใช้งาน UI เรียกใช้ fragment จากใน activity ตอนที่ 2 
http://www.ninenik.com/content.php?arti_id=629 via @ninenik


 
โดยรูปแบบการทำงานคือ เมื่อผู้ใช้ กดปุ่ม Button ที่อยู่ใน fragment ก็จะให้เรียกใช้งาน
method ที่อยู่ใน activity หลัก เพื่อทำงานเปลี่ยนข้อความใน TextView ที่อยู่ใน fragment อีกที
 
1. ที่ไฟล์ fragment_my.xml code เดิมจากตอนที่แล้ว
 
<TextView  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:text="Dynamic Fragment"  
    xmlns:android="http://schemas.android.com/apk/res/android" />  
 
    เปลี่ยนใหม่ โดย จะมี layout view , TextView และก็ Button ตามนี้
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/placeText1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Dynamic Fragment" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="SET TEXT"
        />

</LinearLayout>
 
 


 
 
2. มาที่ fragment class เราจะกำหนด interface เข้าไป 
    code เดิม
 
package com.example.ninenik.study003;

import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
 * A simple {@link Fragment} subclass.
 */
public class myFragment extends Fragment {


    public myFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_my, container, false);
    }


}




 
    ปรับใหม่ โดยเพิ่ม แต่ละส่วนดังนี้

 
 
    // กำหนด mCallback เป็น instance ของ onChangeTextListener interface
    onChangeTextListener mCallback;
 
 
    // กำหนด interface ชื่อ onChangeTextListener
    // Activity ต้องทำการ implement interface นี้
    public interface onChangeTextListener {
        // กำหนด method ของ interface ใช้ชื่อเดียวกับที่จะกำหนดใน activity
        // โดย method นี้จะรับค่า parameter ที่เป็นข้อความ
        public void changeText(String myText);
    }
 
 
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // ตรวจสอบให้มั่นใจว่า activity ว่า activity ได้ทำการ implement แล้วหรือไม่
        // ถ้าได้ทำการ implement แล้วจะส่ง interface กลับมา
        try {
            mCallback = (onChangeTextListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement onChangeTextListener");
        }
    }
 
 
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // ขยายแสดง layout ของ fragment จาก code เดิมเราจะ return ค่าเลย แต่ครั้งนี้
        // เราจะรับค่าไว้ใน instance ชื่อ v ก่อน แล้ว ค่อย return ค่าที่หลัง
        // โดย instance v จะใช้ในการระบุ อ้างอิงค่า view อื่นๆ ใน layout ด้วย findViewById()
        View v = inflater.inflate(R.layout.fragment_my, container, false);
        // กำหนด instance ให้กับปุ่ม
        Button myButton1 = (Button) v.findViewById(R.id.button1);
        // กำหนดให้ปุ่มรอรับการทำงานจากการ click
        myButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { // เมื่อ view ถูก click
                // ใช้ instance ของ interface เรียกใช้งาน changeText() method
                // ใน activity ที่ได้ทำการ implement แล้ว โดยจะส่งข้อความว่า "hello world"
                mCallback.changeText("Hello World");
            }
        });
        return v;
    }
 
 
    จะได้ myFragment class ทั้งหมดดังนี้
 
package com.example.ninenik.study003;

import android.app.Activity;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;


/**
 * A simple {@link Fragment} subclass.
 */
public class myFragment extends Fragment {

    // กำหนด mCallback เป็น instance ของ onChangeTextListener interface
    onChangeTextListener mCallback;

    // กำหนด interface ชื่อ onChangeTextListener
    // Activity ต้องทำการ implement interface นี้
    public interface onChangeTextListener {
        // กำหนด method ของ interface ใช้ชื่อเดียวกับที่จะกำหนดใน activity
        // โดย method นี้จะรับค่า parameter ที่เป็นข้อความ
        public void changeText(String myText);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // ตรวจสอบให้มั่นใจว่า activity ว่า activity ได้ทำการ implement แล้วหรือไม่
        // ถ้าได้ทำการ implement แล้วจะส่ง interface กลับมา
        try {
            mCallback = (onChangeTextListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement onChangeTextListener");
        }
    }


    public myFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // ขยายแสดง layout ของ fragment จาก code เดิมเราจะ return ค่าเลย แต่ครั้งนี้
        // เราจะรับค่าไว้ใน instance ชื่อ v ก่อน แล้ว ค่อย return ค่าที่หลัง
        // โดย instance v จะใช้ในการระบุ อ้างอิงค่า view อื่นๆ ใน layout ด้วย findViewById()
        View v = inflater.inflate(R.layout.fragment_my, container, false);
        // กำหนด instance ให้กับปุ่ม
        Button myButton1 = (Button) v.findViewById(R.id.button1);
        // กำหนดให้ปุ่มรอรับการทำงานจากการ click
        myButton1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { // เมื่อ view ถูก click
                // ใช้ instance ของ interface เรียกใช้งาน changeText() method
                // ใน activity ที่ได้ทำการ implement แล้ว โดยจะส่งข้อความว่า "hello world"
                mCallback.changeText("Hello World");
            }
        });
        return v;
    }

}
 
 
3. ทำการ implement interface ที่ MainActivity โดย code Mainctivity เดิมจะเป็นดังนี้
 
package com.example.ninenik.study003;

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

//ActionBarActivity
public class MainActivity extends FragmentActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ตรวจสอบว่า activity มีการเรียกใช้งาน layout ที่มีการกำหนด
        // FrameLayout เป็น fragment container จาก id ชื่อ fragment_container
        if (findViewById(R.id.fragment_container) != null) { // ถ้ามีการกำหนด

            // กรณีถ้า, ถ้ามีการกู้คืนค่าจาก state ก่อนหน้า,
            // แล้วเราไม่ต้องทำอะไร และให้ return ค่า
            if (savedInstanceState != null) {
                return;
            }

            // สร้าง fragment เพื่อใส่เข้าไปใน activity layout
            // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว
            // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA
            myFragment FragmentA = new myFragment();

            // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent
            // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments
            FragmentA.setArguments(getIntent().getExtras());

            // แทนที่ fragment ไปใน 'fragment_container' FrameLayout
            getFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, FragmentA)
                    .commit();
        }

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
 
    ให้ปรับเพิ่มแต่ละส่วนตามนี้
 
// ทำการ implement โดยต่อด้วย implements myFragment.onChangeTextListener
// รูปแบบ implements [ชื่อ fragment].[ชื่อ instance interface]
// จะได้เป็น implements myFragment.onChangeTextListener
public class MainActivity extends FragmentActivity
        implements myFragment.onChangeTextListener{
..............
......
 
 
    // method ที่เรียกใช้งานจาก fragment
    public void changeText(String myText){

        // เก็บ fragment instance ในชื่อ FragmentB ถ้ามีการเรียกใช้งาน fragment แล้ว
        myFragment FragmentB = (myFragment)
                getFragmentManager().findFragmentById(R.id.fragment_container);

        // ตรวจสอบว่ามี fragment ชื่อ instance ว่า FragmentB หรือไม่
        if (FragmentB != null) { // มีการกำหนด fragment แล้ว

            // กำหนดการทำงานของ method ตามต้องการ ในที่นี้เราจะกำหนดข้อความใน TextView ใน fragment
            // โดยที่เมื่อได้รับค่าที่ส่งเข้ามาแล้วใน method เมื่อกดที่ปุ่ม Button แล้วก็ให้แสดงค่าใน TextView
            // สร้าง instance ของ TextView สังเกตเราจะใช้ FragmentB.getView() ก่อนจะเรียก findViewById()
            // ทั้งนี้เพราะเป็นการไปใช้งานกับ fragment 
            TextView myTextView = (TextView) FragmentB.getView().findViewById(R.id.placeText1);
            myTextView.setTextSize(40);
            myTextView.setText(myText);

        } else {
            // สร้าง fragment เพื่อใส่เข้าไปใน activity layout
            // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว
            // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA
            myFragment FragmentA = new myFragment();

            // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent
            // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments
            FragmentA.setArguments(getIntent().getExtras());

            // แทนที่ fragment ไปใน 'fragment_container' FrameLayout
            getFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, FragmentA)
                    .addToBackStack(null)
                    .commit();
        }

    }
 
    จะได้ code ของ MainActivity ทั้งหมดดังนี้
 
package com.example.ninenik.study003;

import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

//ActionBarActivity
public class MainActivity extends FragmentActivity
        implements myFragment.onChangeTextListener{

    // method ที่เรียกใช้งานจาก fragment
    public void changeText(String myText){

        // เก็บ fragment instance ในชื่อ FragmentB ถ้ามีการเรียกใช้งาน fragment แล้ว
        myFragment FragmentB = (myFragment)
                getFragmentManager().findFragmentById(R.id.fragment_container);

        // ตรวจสอบว่ามี fragment ชื่อ instance ว่า FragmentB หรือไม่
        if (FragmentB != null) { // มีการกำหนด fragment แล้ว

            // กำหนดการทำงานของ method ตามต้องการ ในที่นี้เราจะกำหนดข้อความใน TextView ใน fragment
            // โดยที่เมื่อได้รับค่าที่ส่งเข้ามาแล้วใน method เมื่อกดที่ปุ่ม Button แล้วก็ให้แสดงค่าใน TextView
            // สร้าง instance ของ TextView สังเกตเราจะใช้ FragmentB.getView() ก่อนจะเรียก findViewById()
            // ทั้งนี้เพราะเป็นการไปใช้งานกับ fragment
            TextView myTextView = (TextView) FragmentB.getView().findViewById(R.id.placeText1);
            myTextView.setTextSize(40);
            myTextView.setText(myText);

        } else {
            // สร้าง fragment เพื่อใส่เข้าไปใน activity layout
            // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว
            // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA
            myFragment FragmentA = new myFragment();

            // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent
            // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments
            FragmentA.setArguments(getIntent().getExtras());

            // แทนที่ fragment ไปใน 'fragment_container' FrameLayout
            getFragmentManager().beginTransaction()
                    .replace(R.id.fragment_container, FragmentA)
                    .addToBackStack(null)
                    .commit();
        }

    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ตรวจสอบว่า activity มีการเรียกใช้งาน layout ที่มีการกำหนด
        // FrameLayout เป็น fragment container จาก id ชื่อ fragment_container
        if (findViewById(R.id.fragment_container) != null) { // ถ้ามีการกำหนด

            // กรณีถ้า, ถ้ามีการกู้คืนค่าจาก state ก่อนหน้า,
            // แล้วเราไม่ต้องทำอะไร และให้ return ค่า
            if (savedInstanceState != null) {
                return;
            }

            // สร้าง fragment เพื่อใส่เข้าไปใน activity layout
            // myFragment คือชื่อ fragment activity ที่เราสร้างในตอนที่แล้ว
            // เราตั้งชื่อ instance ของ fragment ใหม่ชื่อ FragmentA
            myFragment FragmentA = new myFragment();

            // ในกรณีที่ activity นี้ มีการการรับค่าจาก intent
            // ให้ส่งค่าจาก intent ไปยัง fragment ด้วยการกำหนด arguments
            FragmentA.setArguments(getIntent().getExtras());

            // แทนที่ fragment ไปใน 'fragment_container' FrameLayout
            getFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, FragmentA)
                    .commit();
        }

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
 
    เป็นอันเสร็จการเชื่อมต่อสื่อสารระกว่าง fragment กับ activity
 
 
4. ทดสอบ run app จะได้ผลลัพธ์ ดังนี้

      

 



เนื้อหาที่เกี่ยวข้อง



Tags:: android android studio fragment

เนื้อหาพิเศษ เฉพาะสำหรับสมาชิก

กรุณาล็อกอิน และลงชื่อติดตาม


สมัครสมาชิกได้ที่        ล็อกอินได้ที่   





URL สำหรับอ้างอิง