show code block

2016年6月16日 星期四

Fragment的使用(二) ─ 在activity內切換Fragment


Fragment的使用()
activity內切換Fragment


前言:

(更新聲明2017/03/08)
做個小聲明:在這邊建議太過複雜的畫面不要使用Fragment。
這聲明是流著淚打出來的,Fragment是個超級大坑,以後妳絕對會遇到各式各樣不可預期的爛帳。我敢說Fragment的絕對是Android最爛的設計知之一。

1、如果你拿Fragment作為你的分頁使用,最常見的問題就是OOM,分頁之間的切換導致Fragment不斷疊加。
參照:http://stackoverflow.com/questions/28483600/android-fragments-on-backstack-taking-up-too-much-memory

2、再來就是複雜、難以控制的的生命週期
參照:https://asce1885.gitbooks.io/android-rd-senior-advanced/content/wo_wei_shi_yao_zhu_zhang_fan_dui_shi_yong_android_fragment.html

不是我在這黑Fragment,上面聯結有一小段說道:
When Fragments were introduced, they sounded like the best idea of all times. Being able to display more than one activity at the same time, kinda. That was the selling point.
當Fragment剛被發明,當你的App想要展示多個Activity時,Fragment被認為是最好的使用方式。
So the whole world slowly started using Fragments. It was the new kid on the block. Everybody was using Fragments. If you were not using Fragments, chances were that "you were doing it wrong".
Fragment當時是一個新的功能,全世界開始慢慢使用它的當下,你只要沒有使用Fragment,就會有人認為你的作法不夠潮。
A few years and apps later, the trend is (thankfully) reverting back to more activity, less fragment. This is enforced by the new APIs (The ability to transition between activities without the user really noticing, as seen in the Transition APIs and such).
幾年過後,因為API的改動,人們開始傾向於改回使用Activity多於Fragment。
So, in summary: I hate fragments. I believe it's one of the worst Android implementations of all time, that only gained popularity because of the lack of Transition Framework (as it exists today) between activities. The lifecycle of a Fragment is, if anything, a ball of random callbacks that are never guaranteed to be called when you expect them.

總結:Fragment是Android 有史以來最爛的成就,Fragment會變得如此火熱的原因是因為他在切換畫面時的流暢度是Activity無法比擬的。

所以我的結論是:
複雜的頁面不要使用Fragment
主要的用途在ViewPager之間的轉換就好了。






為什麼要在Activity加入Fragment呢?
為了要做到兩件事。
一、主要目的是要讓App得執行畫面,可以隨著裝置的螢幕大小自動調整。

二、可以在一個Activity內作內容的切換。(本日實作)




 今日要實作的影片實例: Activity加入Fragment的實作。


今日的重點程式碼:
//宣告
private FragmentManager manager;
private FragmentTransaction transaction;
//透過下方程式碼,取得Activity中執行的個體。
manager = getSupportFragmentManager();
        transaction = manager.beginTransaction();
//呼叫commit讓變更生效。
        transaction.commit();



STEP 1創建兩個fragment



















在創建的過程中,紅框處請勿勾選,用不到。
















STEP 2─ Layout的布局


MainActivity佈局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context="com.example.nikeru8.a11245.MainActivity">
//切換第一個Fragment的按鈕
    <Button
        android:id="@+id/Button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Fragment1" />
//切換第二個Fragment的按鈕
    <Button
        android:id="@+id/Button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="Fragment2" />
//準備顯示FragmentLayout視窗
    <LinearLayout
        android:id="@+id/center"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"></LinearLayout>
</LinearLayout>







fragment_fragment 1 佈局
<FrameLayout 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="com.example.nikeru8.a11245.Fragment1">
 
    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="FRAGMENT1"
        android:textSize="50dp"/>

</FrameLayout>













fragment_fragment2 佈局
<FrameLayout 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="com.example.nikeru8.a11245.Fragment2">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Fragment2"
        android:textSize="50dp"/>



</FrameLayout>








STEP 3Java程式碼

MainActivity.java
package com.example.nikeru8.a11245;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity  {

    private FragmentManager manager;
    private FragmentTransaction transaction;

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

//透過下方程式碼,取得Activity中執行的個體。
        manager = getSupportFragmentManager();
       

    }
      //換頁的按鈕設定
    public void onClick(View view) {
//透過下方程式碼,取得Activity中執行的個體。
        transaction = manager.beginTransaction();
        switch (view.getId()) {
            case R.id.Button1:
                Fragment1 fragment1 = new Fragment1();
                transaction.replace(R.id.center, fragment1, "fragment1");

                break;
            case R.id.Button2:
                Fragment2 fragment2 = new Fragment2();
                transaction.replace(R.id.center, fragment2, "fragment2");
                break;

        }
//呼叫commit讓變更生效。
        transaction.commit();
    }
}


簡單三步驟!完成囉!








此時會發現一個問題,如果操作者按了返回建,會直接跳出app






這時候我們要做的是希望按了返回,能返回上一個fragment



transaction.addToBackStack("fragment2");
這就是我們的魔法。

……程式碼省略……….
//換頁的按鈕設定
public void onClick(View view) {
        transaction = manager.beginTransaction();
        switch (view.getId()) {
            case R.id.Button1:
                Fragment1 fragment1 = new Fragment1();
                transaction.replace(R.id.center, fragment1, "fragment1");
                transaction.addToBackStack("fragment1");

                break;
            case R.id.Button2:
                Fragment2 fragment2 = new Fragment2();
                transaction.replace(R.id.center, fragment2, "fragment2");
                transaction.addToBackStack("fragment2");
                break;

        }
        transaction.commit();

    }
……程式碼省略……….

此時就能用返回建切換上一個Fragment了!



後續維護:
這篇沒有提供github,照著上面的做法應該做得出來,如果有任何問題再聯絡我!





Fragment全集
 

沒有留言:

張貼留言

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...