因爲這裏涉及到接口回調的問題,因此先來看一看什麼是接口回調:
這就比如老闆和員工的微妙關係,老闆須要員工去工做,員工掙錢了之後還要告訴老闆本身掙了多少錢,而後由老闆來處理這些錢。
首先建立一個接口:android
package com.fitsoft; public interface CallBack { void collectMoney(String name, int money); }
因爲員工掙完錢了之後,錢由老闆來處理,所以接口也是由老闆來實現
建立老闆類:app
package com.fitsoft; /** * @author Joker * @since 2019/9/20 0020 18:49 */ public class Boss implements CallBack { void makeMoney(){ String name = "小三"; System.out.println(name+"快去工做!"); Staff staff = new Staff(name, this); staff.doWork(); } public void collectMoney(String name, int money) { System.out.println(name+"幫我掙了"+money+"元"); } }
這裏有兩個方法,一個是叫員工去賺錢,在makeMoney()方法中建立一個員工,讓員工去doWork(),另外一個是員工賺完錢之後回調給老闆,由老闆來打印輸出(花錢)。
看一看員工類:ide
package com.fitsoft; /** * @author Joker * @since 2019/9/20 0020 18:35 */ class Staff { private String myName; private CallBack callBack; Staff(String name, CallBack callBack){ this.myName = name; this.callBack = callBack; } void doWork(){ System.out.println(myName + " make money ing..."); callBack.collectMoney(myName, 500); } }
在構造函數中初始化名字和接口,在doWork()方法中(由老闆來調用的方法),輸出我正在賺錢,賺完錢以後,執行老闆的collectMoney()方法,告訴老闆:這錢是我給你的,你能夠收了,而後老闆就執行了:函數
public void collectMoney(String name, int money) { System.out.println(name+"幫我掙了"+money+"元"); }
總的流程大體是這樣,接下來建立測試類:佈局
package com.fitsoft; /** * @author Joker * @since 2019/9/20 0020 18:47 */ public class Test { @org.junit.Test public void test(){ new Boss().makeMoney(); } }
直接調用老闆類中的賺錢方法(賺錢是不可能賺錢的,這輩子都不可能去賺錢的,只有讓員工去賺錢這樣子才能維持生活...)。
看一看輸出:測試
小三快去工做! 小三 make money ing... 小三幫我掙了500元
以上大體是接口回調的內容,接下來纔是主題:Fragment
首先建立佈局activity_main.xml:this
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.fitsoft.MainActivity"> <Button android:id="@+id/fragment_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="24dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" android:text="add" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" /> <Button android:id="@+id/fragment_remove" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="32dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:text="remove" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/fragment_add" /> <Button android:id="@+id/fragment_modify" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="32dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:text="modify" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/fragment_remove" /> <LinearLayout android:id="@+id/main_fragment" android:layout_width="match_parent" android:layout_height="200dp" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" android:orientation="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.666" /> <TextView android:id="@+id/tv_in_activity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/main_fragment" /> </android.support.constraint.ConstraintLayout>
界面大體是這樣子的:code
而後建立Fragment中的佈局fragment_main.xml:xml
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="#4CAF50" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_in_fragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" android:text="這是Fragment界面" android:textColor="#fff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.415" /> <Button android:id="@+id/btn_in_fragment" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" android:layout_marginBottom="8dp" android:text="modify" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_in_fragment" app:layout_constraintVertical_bias="0.064" /> </android.support.constraint.ConstraintLayout>
界面是這樣的:blog
首先咱們建立Activity的管理類MainActivity:
package com.fitsoft; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends FragmentActivity { Button add; Button remove; Button modify; TextView textView; MainFragment mainFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv_in_activity); mainFragment = new MainFragment(); mainFragment.setOnBtnClickListener(new MainFragment.OnBtnClickListener() { @Override public void onBtnClick() { textView.setText("===這裏的值已經被修改了==="); } }); add = findViewById(R.id.fragment_add); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.main_fragment, mainFragment); ft.commit(); } }); remove = findViewById(R.id.fragment_remove); remove.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.remove(mainFragment); ft.commit(); } }); modify = findViewById(R.id.fragment_modify); modify.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mainFragment.modify(); } }); } }
而後建立Fragment的管理類MainFragment:
package com.fitsoft; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; //兼容性好 import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; /** * @author Joker * @since 2019/9/19 0019 20:48 */ public class MainFragment extends Fragment { Button button; View view; TextView textView; private OnBtnClickListener onBtnClickListener; public void setOnBtnClickListener(OnBtnClickListener onBtnClickListener){ this.onBtnClickListener = onBtnClickListener; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { view = inflater.inflate(R.layout.fragment_main, container, false); textView = view.findViewById(R.id.tv_in_fragment); button = view.findViewById(R.id.btn_in_fragment); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(onBtnClickListener != null) onBtnClickListener.onBtnClick(); } }); return view; } public void modify(){ textView.setText("===修改以後的值==="); } public interface OnBtnClickListener { void onBtnClick(); } }
爲了兼容性更好這裏我用v4包下的Fragment,啓動app以後出現以下界面:
這些就是運行以後咱們Activity上面的佈局,當咱們點擊ADD按鈕以後,觸發事件:
add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.main_fragment, mainFragment); ft.commit(); } });
在這裏將咱們的Fragment添加在LinearLayout佈局中,就是這個:
點擊以後看到Fragment已經生成了:
而後咱們點擊Activity中的MODIFY按鈕,在Activity中修改Fragment中的文本值:
modify = findViewById(R.id.fragment_modify); modify.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mainFragment.modify(); } });
在MainFragment中是這麼寫的:
public void modify(){ textView.setText("===修改以後的值==="); }
將Fragment中的TextView的值進行了修改,修改以後:
上面咱們在Activity中修改Fragment,那麼如何在Fragment中調用Activity中的方法呢,固然方法有不少,這裏咱們使用回調函數的方式進行通訊:
在MainFragment中定義接口:
public interface OnBtnClickListener { void onBtnClick(); }
而後在MainFragment中定義方法,將接口提供給調用者:
public void setOnBtnClickListener(OnBtnClickListener onBtnClickListener){ this.onBtnClickListener = onBtnClickListener; }
這裏MainActivity中使用匿名內部類的方式實現了接口的方法:
mainFragment = new MainFragment(); mainFragment.setOnBtnClickListener(new MainFragment.OnBtnClickListener() { @Override public void onBtnClick() { textView.setText("===這裏的值已經被修改了==="); } });
爲何要set呢?這是爲了讓兩個類中的接口保持一致,原來的MainFragment中的onBtnClickListener是null,而在MainActiviy中卻已經寫好了方法,就等着你去調用
而後Fragment按鈕的點擊事件中就調用了接口中的onBtnClick()方法,這跟普通的調用方法還有點不同,它更像是調用實體類中的方法,只不過沒有實例化:
button = view.findViewById(R.id.btn_in_fragment); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(onBtnClickListener != null) onBtnClickListener.onBtnClick(); } });
這裏還須要注意,據我分析(若是沒有錯的話):
onBtnClickListener.onBtnClick();
這行代碼算不上調用,更像是執行,由於此時的onBtnClickListener已經不爲null了,它只是執行了裏面的onBtnClick()方法,
@Override public void onBtnClick() { textView.setText("===這裏的值已經被修改了==="); }
而真正要被執行的方法應該是已經早早的在set方法中被傳遞了過來。
而後看看回調以後的效果:
最後還有一個移除Fragment的按鈕:
remove = findViewById(R.id.fragment_remove); remove.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.remove(mainFragment); ft.commit(); } });
整個過程大體是這樣:
而後會有小夥伴發問了,這裏和開頭舉的例子的回調方法不同啊。。。
好,那我改爲一致的...
MainActivity:
package com.fitsoft; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends FragmentActivity implements OnBtnClickListener{ Button add; Button remove; Button modify; TextView textView; MainFragment mainFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = findViewById(R.id.tv_in_activity); mainFragment = new MainFragment(); mainFragment.setOnBtnClickListener(this); add = findViewById(R.id.fragment_add); add.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.add(R.id.main_fragment, mainFragment); ft.commit(); } }); remove = findViewById(R.id.fragment_remove); remove.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FragmentManager fm = getSupportFragmentManager(); //得到fragment的事務 FragmentTransaction ft = fm.beginTransaction(); ft.remove(mainFragment); ft.commit(); } }); modify = findViewById(R.id.fragment_modify); modify.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mainFragment.modify(); } }); } @Override public void onBtnClick() { textView.setText("===這裏的值已經被修改了==="); } }
其實理解應該不難,畢竟點擊事件的觸發不也是這樣的嘛...
modify.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mainFragment.modify(); } });
也可使類實現View.OnClickListener接口....