31 ตุลาคม 2557

[Android Code] Let's Fragment - เริ่มต้นง่ายๆกับ Fragment แบบพื้นฐาน



        หลังจากที่เกริ่นกันไปคร่าวๆแล้วกับ Fragment ในบทความ [Android Code] Fragment Principle - มารู้จักกับ Fragment กันเถอะ~ คราวนี้ก็ลองมาดูวิธีการใช้งานเบื้องต้นกันต่อดีกว่า

        แต่ก่อนจะเริ่มเรียกใช้งาน Fragment ก็ต้องรู้เรื่องพื้นฐานต่างๆสำหรับ Fragment ก่อนนะ

Fragment มี 2 Class ด้วยกัน

        Fragment (android.app.Fragment) นั้นถือกำเนิดขึ้นบน Android 3.0 Honeycomb (ต้นปี 2011) ซึ่งในตอนนั้น Fragment ถูกสร้างขึ้นมาและถูกผลักดันให้ใช้งานเพื่อให้การทำงานของแอปพลิเคชันยืดหยุ่นขึ้น สามารถทำแอปพลิเคชันในรูปแบบต่างๆได้เยอะขึ้น แต่ทว่าปัญหาหลักในตอนนั้นก็คือแอนดรอยด์เวอร์ชันที่ต่ำกว่านั้นใช้งานไม่ได้ ซึ่งเป็นช่วงที่ Android 2.3 ยังเป็นที่แพร่หลาย (ในขณะที่ Android 3.0 - 3.2 ไม่เป็นที่นิยมซักเท่าไร) จึงทำให้ Fragment มีข้อจำกัดที่ทำให้ไม่ค่อยน่าใช้งานซักเท่าไร

        Fragment (android.support.v4.app.Fragment) ได้เกิดขึ้นมาในตอนที่ทีมแอนดรอยด์ได้เปิดตัว Android 4.0 Icecream Sandwich ใน (ปลายปี 2011) ซึ่งมาพร้อมกับ Android Support v4 ซึ่งเป็นไลบรารีสำหรับฟีเจอร์ใหม่ๆให้ทำงานบนเวอร์ชันเก่าๆได้ หนึ่งในนั้นก็คือ Fragment นั่นเอง เพื่อให้ Fragment ใช้งานได้ทั้งบนเวอร์ชันเก่าและใหม่

        สรุปสั้นๆได้ดังนี้

        • android.app.Fragment มาพร้อมกับ Android 3.0 Honeycomb แต่รองรับเฉพาะ API 11 ขึ้นไป จึงไม่นิยมซักเท่าไร
        • android.support.v4.app.Fragment เป็นส่วนหนึ่งของ Android Support v4 Library เพื่อให้สามารถใช้งาน Fragment กับเวอร์ชันต่ำกว่า API 11 ได้ (ขั้นต่ำคือ API 4 หรือ Android 1.6 Donut)

        ทั้ง 2 คลาสนี้มีการทำงานที่คล้ายๆกัน แต่ไม่สามารถใช้แทนกันได้ เพราะเป็นคนละคลาสกันโดยสิ้นเชิง โดยในการใช้งานจริงจะนิยมใช้งาน Fragment ของ Android Support v4 Library กันมากกว่า

สร้าง Fragment 

        การสร้าง Fragment ก็จะคล้ายๆกับ Activity แต่ไม่จำเป็นต้องประกาศใน Android Manifest โดยสามารถสร้างได้ทันทีบน Android Studio

        แต่ที่สำคัญคือจะต้องไม่ลืม Android Support v4 เพราะว่าในบทความ Fragment ทั้งหมดของเจ้าของบล็อกจะอิงจาก Android Support v4 ทั้งหมด ดังนั้นเข้าไปเช็คด้วยว่าใน build.gradle มี Dependency ของ Android Support v4 แล้วหรือยัง

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:support-v4:23.0.0'
}

        เมื่อพร้อมแล้วก็เริ่มต้นสร้าง Fragment ต่อได้เลย โดยสามารถคลิกขวาที่ Project Package แล้วเลือก New > Fragment > Fragment (Blank) เลยก้ได้นะ



        ในขั้นตอนการกำหนด Fragment เจ้าของบล็อกอยากจะให้เอาช่อง Include fragment factory methods? กับ Include interface callback? ออกก่อน เพราะเป็นส่วนที่ Android Studio จะใส่ชุดคำสั่งเตรียมมาให้ในตอนสร้าง แต่เจ้าของบล็อกอยากจะให้ผู้ที่หลงเข้ามาอ่านเข้าใจพื้นฐานก่อน เดี๋ยวอธิบายที่มาของคำสั่งเหล่านั้นทีหลัง (เวลาทำงานจริงเดี๋ยวก็ได้ใช้)



        เมื่อสร้างขึ้นมาแล้วจะเห็นว่ามีโค๊ดเตรียมไว้แล้วประมาณนี้


        แต่ปัญหาที่จะเกิดขึ้นตามมาก็คือ Fragment ที่สร้างขึ้นมาด้วยวิธีนี้ จะเป็น android.app.Fragment โดยอัตโนมัติ ดังนั้นผู้ที่หลงเข้ามาอ่านต้องไปแก้ไขให้เป็น android.support.v4.app.Fragment ให้เรียบร้อยซะ

import android.os.Bundle;
import android.support.v4.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);
    }
}

        ส่วน Fragment Layout ก็จะสร้างขึ้นมาให้อัตโนมัติเช่นกัน และมี  TextView แปะอยู่ตรงกลางมีข้อความว่า Hello blank fragment ตอนนี้ก็ยังไม่ต้องไปยุ่งอะไรกับมันละกัน


        เท่านี้ก็เป็นอันเสร็จสิ้นการสร้าง Fragment (แค่เบื้องต้น จริงๆมีโค๊ดมากว่านี้)

มีวิธีเรียกใช้งาน Fragment อยู่ 2 วิธี

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

วิธีแรก : ประกาศ <fragment> ใน Layout XML

        วิธีนี้จะเป็นการสร้าง Fragment ไว้ใน Layout XML เตรียมไว้ตั้งแต่แรก โดยสร้าง <fragment> ไว้แล้วกำหนด Fragment ที่ต้องการไว้เรียบร้อยแล้ว

<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"
    tools:context=".MainActivity">
    
    <fragment
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:name="com.akexorcist.fragment.MyFragment"
        android:id="@+id/fragment_my"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        tools:layout="@layout/fragment_my" />
    
</RelativeLayout>

       โดยจะอิง Fragment ด้วยชื่อ + Package ของ Fragment ที่ต้องการ โดยยังคงมีการกำหนด ID ให้กับ <fragment> อยู่ เพราะจะเรียกใช้งานโดยอ้างอิงผ่าน ID

        และเมื่อเรียกใช้งานบน Activity หรือ Fragment ก็จะเรียกใช้งานแบบนี้

public class MainActivity extends AppCompatActivity {

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

        Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_my);
        MyFragment myFragment = (MyFragment) fragment;
    }
}

        ซึ่ง Fragment ที่ประกาศไว้ใน XML เวลาดึงมาใช้งานก็จะต้อง Cast ให้เป็น Fragment ที่สร้างไว้ทุกครั้ง แล้วจึงนำไปใช้งานตามต้องการ

        โดยวิธีนี้จะเป็นการประกาศ Fragment เตรียมไว้ใน Layout แล้วใช้คำสั่ง findFragmentById เพื่อดึง Fragment มาใช้งานนั่นเอง

        ไม่ยากเนอะ?

        เพิ่มเติม - สำหรับการเพิ่ม <fragment> ลงใน Layout XML ไม่จำเป็นต้องพิมพ์โค๊ดเองก็ได้นะ เพราะในหน้า Design มีให้เลือกอยู่แล้ว



        เพียงแค่กดเลือก ก็จะมีหน้าต่างถามให้เลยว่าจะให้เป็น Fragment ตัวไหน (นั่นคือที่มาว่าทำไมต้องไปสร้าง Fragment ขึ้นมาก่อน) แล้วเอาไปแปะลงบน Layout ในตำแหน่งที่ต้องการได้เลย



        แต่บางครั้ง (น่าจะทุกครั้งมากกว่า) ที่หน้า Design จะมีแจ้งเตือนแบบนี้


        ไม่ต้องตกใจไป ที่แจ้งเตือนแบบนี้ก็เพราะว่าผู้ที่หลงเข้ามาอ่านได้เพิ่ม <fragment> ลงไปใน Layout แล้ว แต่ว่าตัวโปรแกรมไม่รู้ว่าจะต้องเอา Layout ตัวไหนของ Fragment มา Preview ให้ดู สามารถแก้ไขได้ด้วยการกดเลือก Use @layout/<fragment name> เพื่อให้ Preview Layout ของ Fragment ตัวนั้นๆ ก็หมดปัญหาแล้ว

        ซึ่งจริงๆมันก็คือการใส่ tools:layout ใน <fragment> นั่นเอง


วิธีที่สอง : สร้าง Layout เตรียมไว้แล้วแปะ Fragment เข้าไปทีหลัง

        ถ้าจะให้อธิบายแบบสั้นๆก็คือสร้าง ViewGroup ไว้ซักตัว แล้วก็เอา Fragment มาแปะลงในนั้นเลย ซึ่ง ViewGroup ที่ว่านี้ เจ้าของบล็อกชอบใช้เป็น FrameLayout (ใช้ตัวไหนก็ได้)

<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"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/layout_fragment_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</RelativeLayout>

        และในการเอา Fragment มาแปะบน ViewGroup ก็จะใช้ FragmentManager เข้ามาช่วย (สามารถอ่านเพิ่มเติมได้ที่ [Android Code] Let's Fragment - รู้จักกับ FragmentTransaction สำหรับการแสดง Fragment [ตอนที่ 1]) โดยจะสร้าง Fragment ที่ต้องการขึ้นมา แล้วใช้ FragmentManager แปะ Fragment ดังกล่าวลงใน ViewGroup

public class MainActivity extends AppCompatActivity {

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

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction transaction = manager.beginTransaction();
        transaction.replace(R.id.layout_fragment_container, myFragment);
        transaction.commit();
    }
}

        เพิ่มเติม - ViewGroup ที่ว่านี้ รวมไปถึง <fragment> ด้วยนะเออ เพราะงั้นจะใช้ <fragment> เปล่าๆแปะไว้ใน Layout แล้วใช้ FragmentManager ให้แปะ Fragment ลงบนนั้นก็ได้เช่นกัน

วิธีไหนดีกว่ากัน?

        ไม่มีวิธีไหนที่ดีที่สุดครับ เพราะขึ้นอยู่กับว่าผู้ที่หลงเข้ามาอ่านต้องการใช้งาน Fragment แบบไหนซะมากกว่า

        ซึ่งวิธีแรกนั้นจะเหมาะกับ Fragment ที่ตายตัว ไม่มีการเปลี่ยนแปลง อย่างเช่น MapFragment ของ Google Maps API ที่แปะลงบน Layout เตรียมไว้ตั้งแต่แรก

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

        ซึ่งทั้งสองวิธีนี้สามารถใช้ร่วมกันได้ อย่างเช่น ต้องการแปะ Fragment ไว้ตั้งแต่ตอนแรก แต่สั่งให้เปลี่ยนเป็น Fragment ตัวอื่นได้ เป็นต้น

ข้อสังเกตเกี่ยวกับคำสั่ง getFragmentManager หรือ getSupportFragmentManager

        จะเห็นว่าการเรียกใช้งาน FragmentManager จะไม่ได้เป็นการสร้าง Instance ขึ้นมาใหม่ แต่ว่าจะเป็นการเรียกใช้งาน FragmentManager ที่มีอยู่แล้วใน Activity (หรือ Fragment) แต่ทว่าคำสั่งจะมีด้วยกันอยู่สองแบบนั่นก็คือ getFragmentManager และ getSupportFragmentManager


        ทั้งสองตัวนี้ได้ FragmentManager เหมือนกันทั้งคู่ แต่ทว่าจะเป็น FragmentManager จากคนละคลาสกัน

        คำสั่ง getFragmentManager จะได้เป็น android.app.FragmentManager ซึ่งเอาไว้ใช้งานสำหรับ android.app.Fragment (มีเฉพาะ API 11 ขึ้นไป)

        คำสั่ง getSupportFragmentManager จะได้เป็น android.support.v4.app.FragmentManager ซึ่งเอาไว้ใช้งานสำหรับ android.support.v4.app.Fragment (ใช้ Androi Support v4 Library)

        ซึ่งคำสั่ง getFragmentManager จะมีให้เรียกใช้งานจาก Activity ทุกๆตัวอยู่แล้ว (บน API 11 ขึ้นไป) แต่สำหรับ getSupportFragmentManager จะมีเฉพาะ FragmentActivity (หรือ Activity ตัวอื่นๆที่สืบทอดคลาสนี้) ซึ่งเป็นคลาสที่เพิ่มเข้ามาทีหลังใน Android Support v4 Library นั่นเอง

        ดังนั้นถ้าใช้แค่ Activity ธรรมดาๆก็จะไม่มีคำสั่ง getSupportFragmentManager ให้ใช้งานนั่นเอง แต่สำหรับ AppCompatActivity เป็นคลาสที่สืบทอดมาจาก FragmentActivity อยู่แล้ว จึงสามารถเรียกใช้งานได้ทั้ง getFragmentManager และ getSupportFragmentManager (เรียกใช้ให้ถูกต้องด้วยนะ)

มาดูที่ Fragment Class กันต่อ

        ถึงแม้ว่า Fragment จะมีความคล้ายกับ Activity อยู่บ้าง แต่ก็มีหลายๆอย่างที่แตกต่างกัน (และควรรู้ไว้) โดยเฉพาะ Life Cycle ซึ่งสามารถอ่านเพิ่มเติมได้จาก [Android Code] Let's Fragment - วงจรชีวิตของ Fragment (Fragment Lifecycle) และควรเข้าใจการทำงาน Fragment เพื่อให้สามารถใช้งานได้ถูกต้อง เพื่อให้ Fragment มีการทำงานที่ดีและยืดหยุ่นกับการนำไปใช้งานในรูปแบบต่างๆ

การสร้าง Fragment ไม่ควรใช้ Constructor โดยตรง

        ในการสร้าง Fragment จากตัวอย่างในตอนแรกๆจะเห็นว่าเจ้าของบล็อกประกาศ​ Empty Constructor ไว้

public class MyFragment extends Fragment {
    
    public MyFragment() { }

    ...

}

        เวลาสร้าง Fragment นั้นๆขึ้นมาก็จะใช้คำสั่งแบบนี้

MyFragment myFragment = new MyFragment();

        แต่ถ้าเจ้าของบล็อกอยากให้ Activity ส่ง String ซักตัวให้ Fragment ไปด้วยล่ะ? จะทำยังไง?

        ก็แค่ Overload Constructor ขึ้นมาอีกตัวโดยมีพารามิเตอร์เป็น String ใช่มั้ยล่ะ?

public class MyFragment extends Fragment {

    private String message;

    public MyFragment(String message) {
        this.message = message;
    }

    ...

}

        แล้วคำสั่งก็จะเป็นแบบนี้แทน

MyFragment myFragment = new MyFragment("Hello Android");

        นี่แหละครับตัวอย่างการสร้าง Fragment ที่ผิด

        อ้าว!? ผิดตรงไหน?

        ที่มันผิดก็เพราะว่า Fragment ไม่ได้ถูกออกแบบมาให้สร้างแบบนั้นนั่นเอง เนื่องจาก Fragment มี Life Cycle ในตัวเอง คล้ายๆกับ Activity ที่สามารถถูกเคลียร์ทิ้งหรือสร้างใหม่ได้เองตลอดเวลา

        ซึ่งเวลาที่ Fragment ถูกเคลียร์ทิ้งชั่วคราว (อาจจะเพราะ Memory ไม่พอใช้งาน) แล้วถูกสร้างขึ้นมาใหม่อีกครั้ง (Recreate) สิ่งที่เกิดขึ้นคือระบบจะสร้าง Fragment จาก Empty Constructor เท่านั้น ซึ่งก็คือ

MyFragment myFragment = new MyFragment();

        ดังนั้นการ Overload Constructor จากตัวอย่างข้างบนที่ส่ง String เข้ามาใน Fragment ได้จึงไม่ใช่วิธีที่ถูกต้อง เพราะเมื่อใดที่ Fragment มันเกิด Recreate จะทำให้ String ที่ประกาศไว้ใน Global กลายเป็น Null ทันที เพราะมันไม่ได้เรียก Constructor ตัวที่ Overload ไว้

วิธีการสร้าง Fragment ที่ถูกต้อง

        จากปัญหาดังกล่าวจึงทำให้ต้องใช้ Factory Method เข้ามาช่วยในการสร้าง Fragment ขึ้นมา โดยนิยมกำหนดชื่อ Method ว่า newInstance

public class MyFragment extends Fragment {

    public static MyFragment newInstance() {
        return new MyFragment();
    }

    public MyFragment() { }

    ...

}

        เวลาจะสร้าง Fragment ขึ้นมาก็จะต้องใช้คำสั่งแบบนี้

MyFragment myFragment = MyFragment.newInstance();

        แล้วถ้าต้องการส่ง String เข้าไปก็จะใช้ Bundle เข้ามาช่วยแทน

public class MyFragment extends Fragment {
    public static final String KEY_MESSAGE = "message";

    public static MyFragment newInstance(String message) {
        MyFragment fragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString(KEY_MESSAGE, message);
        fragment.setArguments(bundle);
        return fragment;
    }

    public MyFragment() { }

    ...
    
}

        โดยจะเก็บ String ที่ส่งเข้ามาไว้ใน Bundle แล้วเก็บไว้ใน Fragment อีกทีหนึ่ง (คล้ายๆกับการส่งข้อมูลผ่าน Intent นั่นแหละ) ซึ่งข้อมูลที่จะส่งเข้ามาใน Fragment ได้ก็จะต้องเป็นข้อมูลที่เก็บลงใน Bundle ได้นั่นเอง

        และเวลาดึงข้อมูลมาใช้งานก็จะใช้คำสั่งที่ onCreate แล้วเก็บไว้เป็น Global Variable

public class MyFragment extends Fragment {
    public static final String KEY_MESSAGE = "message";

    private String message;

    ...

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle bundle = getArguments();
        if(bundle != null) {
            message = bundle.getString(KEY_MESSAGE);
        }
    }

    ...

}

       สรุปโค๊ดให้ดูอีกรอบ

public class MyFragment extends Fragment {
    public static final String KEY_MESSAGE = "message";

    private String message;

    public static MyFragment newInstance(String message) {
        MyFragment fragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString(KEY_MESSAGE, message);
        fragment.setArguments(bundle);
        return fragment;
    }

    public MyFragment() { }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle bundle = getArguments();
        if(bundle != null) {
            message = bundle.getString(KEY_MESSAGE);
        }
    }

    ...
    
}

        เวลาสร้าง Fragment ขึ้นมาก็จะใช้คำสั่งแบบนี้

MyFragment myFragment = MyFragment.newInstance("Hello Android");

        จากนั้นก็เอา Fragment ไปใช้งานต่อได้เลย

        ซึ่งในขั้นตอนการสร้าง Fragment Class ถ้าติ๊กเลือกที่ Include fragment factory methods? ด้วย โปรแกรมก็จะทำการสร้างโค๊ดแบบตัวอย่างขึ้นมาให้นั่นแหละ แต่เนื่องจากมันมี Comment และอื่นๆแถมเข้ามาเยอะมาก อาจจะทำให้ดูแล้วเข้าใจได้ยาก (ถ้าไม่เคยเข้าใจมันมาก่อน)


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

กำหนด Layout ให้กับ Fragment Class ได้อย่างไร?

        ปกติแล้วผู้ที่หลงเข้ามาอ่านจะชินกับการกำหนด Layout ให้กับ Activity Class ด้วยคำสั่ง setContentView แต่สำหรับ Fragment จะไม่มีคำสั่ง setContentView ให้ใช้งานนะ

        แต่จะกำหนดด้วยวิธีนี้

public class MyFragment extends Fragment {
    
    ...

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

        ซึ่ง Fragment จะมี Method ที่ชื่อว่า onCreateView อยู่ มีไว้สำหรับกำหนด Layout ให้กับ Fragment โดยเฉพาะ ใช้วิธี Inflate Layout แบบนี้นี่แหละ แล้ว Return กลับไป (จริงๆเบื้องหลังของ setContentView ก็คือการ Inflate Layout นะ)

        เวลาจะกำหนด View ต่างๆใน Layout ให้ไปกำหนดไว้ใน onViewCreated แบบนี้

public class MyFragment extends Fragment {
    
    private TextView tvUsername;
    
    ...

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        
        tvUsername = (TextView) view.findViewById(R.id.tv_username);
        
        ...

    }
}

        ขอตัดจบเพียงเท่านี้ก่อนนะครับ ขอแบ่งส่วนที่เหลือไปต่อกันในบทความถัดไปแทนนะครับ



บทความที่เกี่ยวข้อง

        • Fragment Principle - มารู้จักกับ Fragment กันเถอะ~
        • Let's Fragment - เริ่มต้นง่ายๆกับ Fragment แบบพื้นฐาน
        • Let's Fragment - รู้จักกับ FragmentTransaction สำหรับการแสดง Fragment [ตอนที่ 2]
        • Let's Fragment - มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 1]
        • Let's Fragment - มาทำ View Pager กันเถิดพี่น้อง~ [ตอนที่ 2]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium