?一、activity與Fragment的通信有哪些?
????????使用接口進行通信的邏輯與代碼示例
????????使用接口通信的核心是解耦,通過定義一個接口作為通信契約,讓 Fragment 不依賴于具體的 Activity 類型。
1. 定義通信接口(在 Fragment 內)
首先,在 Fragment 內部定義一個公共接口。這個接口就像一份協議,規定了 Fragment 想要傳遞給 Activity 的信息類型和方法。
// MyFragment.java
public class MyFragment extends Fragment {// 定義通信接口public interface OnMessageSendListener {void onMessageSent(String message);}private OnMessageSendListener listener;// ... 其他 Fragment 生命周期方法@Overridepublic void onAttach(@NonNull Context context) {super.onAttach(context);// 檢查宿主 Activity 是否實現了接口if (context instanceof OnMessageSendListener) {listener = (OnMessageSendListener) context;} else {// 如果沒有實現,拋出異常,提醒開發者throw new RuntimeException(context.toString() + " must implement OnMessageSendListener");}}// Fragment 內部觸發事件的方法private void triggerCommunication() {if (listener != null) {// 調用接口方法,傳遞數據listener.onMessageSent("Hello from Fragment!");}}
}
2. Activity 實現接口并處理數據
然后,你的 Activity 必須實現這個接口。這就像在說:“好的,我愿意遵守這份契約,并且知道如何處理來自 Fragment 的數據。”
// MyActivity.java
public class MyActivity extends AppCompatActivity implements MyFragment.OnMessageSendListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 假設這里將 MyFragment 添加到了 ActivitygetSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new MyFragment()).commit();}// 實現接口中定義的方法@Overridepublic void onMessageSent(String message) {// 在 Activity 中處理從 Fragment 接收到的數據Toast.makeText(this, "收到來自 Fragment 的消息: " + message, Toast.LENGTH_SHORT).show();}
}
邏輯總結: 這個過程非常清晰:Fragment 不關心它的宿主是誰,它只知道需要一個實現了 OnMessageSendListener
接口的對象。只要 Activity 遵守了這個約定,通信就能安全地進行。這種方式徹底解耦了 Fragment 和 Activity,提高了 Fragment 的可復用性。
????????使用 ViewModel 進行通信的邏輯與代碼示例
使用 ViewModel 進行通信的核心是數據驅動。Activity 和 Fragment 不再直接交互,而是通過一個共享的 ViewModel 實例作為數據中心,來同步數據。
1. 創建共享的 ViewModel
首先,創建一個繼承自 ViewModel
的類,并用 MutableLiveData
來封裝你需要共享的數據。
// SharedViewModel.java
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;public class SharedViewModel extends ViewModel {// MutableLiveData 用于在 ViewModel 內部修改數據private final MutableLiveData<String> selectedItem = new MutableLiveData<>();// 提供一個公開方法,供外部調用以更新數據public void selectItem(String item) {selectedItem.setValue(item);}// 提供一個不可變的 LiveData 實例供外部觀察public LiveData<String> getSelectedItem() {return selectedItem;}
}
2. Fragment A(數據發送方)
在發送數據的 Fragment 中,通過其宿主 Activity 的范圍(by activityViewModels()
或 ViewModelProvider
)獲取 ViewModel 的實例,然后調用其方法來更新數據。
// FragmentA.java
public class FragmentA extends Fragment {// 獲取共享的 ViewModel 實例private SharedViewModel sharedViewModel;@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 使用 ViewModelProvider 獲取同一個實例sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_a, container, false);Button button = view.findViewById(R.id.send_button);button.setOnClickListener(v -> {// 當按鈕被點擊時,更新 ViewModel 中的數據sharedViewModel.selectItem("Data from Fragment A");});return view;}
}
3. Fragment B(數據接收方)
在接收數據的 Fragment 中,也通過同樣的方式獲取 ViewModel 的實例,然后觀察(observe
)LiveData
的變化。
// FragmentB.java
public class FragmentB extends Fragment {private SharedViewModel sharedViewModel;private TextView textView;@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_b, container, false);textView = view.findViewById(R.id.received_data_text_view);// 觀察 ViewModel 中的數據變化sharedViewModel.getSelectedItem().observe(getViewLifecycleOwner(), item -> {// 當數據發生變化時,更新 UItextView.setText(item);});return view;}
}
????????邏輯總結: 這個過程的核心是數據流。Fragment A 只負責更新 ViewModel 中的數據,Fragment B 和 Activity 只負責觀察這些數據。它們之間沒有直接引用。這種方式不僅徹底解耦了組件,還利用了 LiveData 的生命周期感知特性,自動處理了數據在屏幕旋轉等配置變化時的持久化,有效防止了內存泄漏。它代表了現代 Android 開發中組件通信的最新趨勢和最佳實踐。
二、String類與List,Set,Map類
對 String
、StringBuilder
和 StringBuffer
三者作用、意義和區別。
????????String
是最基礎的字符串類,但它最大的特點是不可變性。這意味著一旦創建,它的值就無法改變。任何對 String
的修改操作,比如拼接,都會在內存中創建一個全新的 String
對象,而舊的對象則會被回收。因此,String
適用于那些不需要頻繁修改的場景,它的不可變性也保證了線程安全,使其成為一個可靠的數據類型。然而,如果需要進行大量的字符串操作,尤其是在循環中,頻繁創建新對象的開銷會嚴重影響程序性能。
????????為了解決 String
的性能問題,Java 引入了 StringBuilder
和 StringBuffer
。這兩者都屬于可變的字符串,它們在內部維護一個動態的字符數組,可以直接在原有對象上進行修改,而無需創建新的對象。這使得它們在進行字符串拼接、插入等操作時,效率遠高于 String
。其中,StringBuilder
的性能最高,因為它沒有線程同步(synchronized
)的開銷,這使得它在單線程環境下成為處理字符串修改的首選工具。
????????StringBuffer
和 StringBuilder
的功能幾乎完全相同,但關鍵區別在于線程安全性。StringBuffer
的所有方法都是線程同步的,這意味著在多線程環境中,它可以確保同一時間只有一個線程能訪問它,從而避免了數據不一致的問題。然而,這種同步機制會帶來額外的性能開銷,所以在單線程環境下,使用 StringBuffer
是不必要的,會比 StringBuilder
慢。因此,在選擇時,應根據項目的具體需求來決定:單線程用 StringBuilder
,多線程用 StringBuffer
,而 String
則用于處理不需要修改的簡單字符串。
List、Set 和 Map 是 Java 集合框架中最基礎也是最重要的三種接口,它們都用于存儲對象,但各自有獨特的存儲方式、行為和適用場景。理解它們的區別,是高效編程的關鍵。
List(列表)
????????List 是一種有序、可重復的集合。你可以把它想象成一個數組,每個元素都有一個對應的索引,因此你可以通過索引來精確地訪問、添加或刪除元素。由于它允許重復元素,你可以多次添加同一個對象。在實際應用中,當你需要一個元素的順序很重要,或者需要存儲重復數據時,List
是你的首選。常見的實現類有 ArrayList
和 LinkedList
,前者基于數組,隨機訪問速度快;后者基于鏈表,插入和刪除操作更高效。
Set(集合
????????Set 是一種無序、不可重復的集合。它的行為更像一個數學意義上的集合,所有元素都是唯一的。當你試圖向一個 Set
中添加一個已經存在的元素時,添加操作會失敗。正因為這種獨一無二的特性,Set
非常適合用來去重。例如,如果你需要統計一篇文章中不重復的單詞數量,Set
就能輕松勝任。常見的實現類有 HashSet
和 TreeSet
,HashSet
提供了最快的查找速度,而 TreeSet
則會保持元素的排序。
Map(映射)
????????Map 是一種鍵值對的集合。它存儲的不是單個元素,而是由“鍵(Key)”和“值(Value)”組成的配對。每個鍵都是唯一的,并且與一個值相關聯。你可以通過鍵來快速查找、更新或刪除對應的值,就像查字典一樣。Map
非常適合用于存儲需要通過某種唯一標識來檢索的數據,比如一個用戶的 ID 對應其個人信息,或者一個學生的學號對應其成績。常見的實現類有 HashMap
和 TreeMap
,HashMap
提供了無序的快速存取,而 TreeMap
則會按鍵的自然順序進行排序。