今天看到了一篇文章,講了DialogFragment的封裝方式(Android:我為何要封裝DialogFragment?),想到當初也為頁面銷毀后DialogFragment的回調方式頭疼了好久,看到了po主的思路,與當初自己想的不太一樣,就整理一下.
如何在開發中遇到頁面銷毀的情況
在android開發中,頁面銷毀是個必須要考慮的一個問題.由于現在android手機性能越來越強,及自己在開發中其實是很難碰到頁面銷毀的情況,可以在手機設置-開發者選項中-不保留活動選項選中.這樣在app使用中,按下home鍵后,再回到app中,頁面就會重新onCreate.(由于我在開發中使用genimotion模擬器,某些情況下按下home鍵,再立即回到app中是不會銷毀的,可以在按下home鍵后,再開個別的app后,再回到自己的app中)
思想
一般設計的方式,是將回調的listener傳遞到DialogFragment的實例中,頁面銷毀后實例中保存的listener對象就會丟失.由于listener通常指向的是宿主本身,所以也無法通過onSaveInstance()方法保存,那么主動去獲取呢?
實現思路
在DialogFragment的實例中現將接該dialog中需要的接口定義好
宿主(activity或fragment)實現該接口
DialogFragment的實例中通過getActivity獲取activity對象,或者通過getTargetFragment獲取fragment對象,由于宿主本身實現了需要的回調接口,可以通過強轉直接調用接口中定義的方法
創建BaseDialogFragment
public class BaseDialogFragment extends DialogFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...根據自己的需求
}
/**
* 為獲取接口類型定義的一個輔助方法 簡化每次都要強轉的麻煩
* @param listenerInterface
* @param
* @return
*/
protected T getDialogListener(Class listenerInterface) {
//用targetFragment是否為空來標識是fragment還是activity開啟的這個DialogFragment
final Fragment targetFragment = getTargetFragment();
if (targetFragment != null && listenerInterface.isAssignableFrom(targetFragment.getClass())) {
return (T) targetFragment;
}
if (getActivity() != null && listenerInterface.isAssignableFrom(getActivity().getClass())) {
return ((T) getActivity());
}
return null;
}
}
一個簡單的DialogFragment實現
public class ConfirmDialogFragment extends BaseDialogFragment {
/**
* 定義該dialog需要的回調方法
*/
public interface IConfirmDialogListener{
void onConfirmDialogPositiveListener();
void onConfirmDialogCancelListener();
}
private IConfirmDialogListener getConfirmDialogListener(){
return getDialogListener(IConfirmDialogListener.class);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
//程序簡單起見 直接使用該方法創建一個dialog
AlertDialog.Builder b = new AlertDialog.Builder(getActivity())
.setTitle("title")
.setMessage("msg")
.setPositiveButton("確認", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
getConfirmDialogListener().onConfirmDialogPositiveListener();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
getConfirmDialogListener().onConfirmDialogCancelListener();
}
});
return b.create();
}
}
在activity中使用dialog
public class MainActivity extends AppCompatActivity implements ConfirmDialogFragment.IConfirmDialogListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConfirmDialogFragment dialogFragment = new ConfirmDialogFragment();
dialogFragment.show(getSupportFragmentManager(),"tag");
}
@Override
public void onConfirmDialogPositiveListener() {
//確認事件
}
@Override
public void onConfirmDialogCancelListener() {
//取消事件
}
}```
#### 在fragment中使用
public class FeatureFragment extends Fragment implements ConfirmDialogFragment.IConfirmDialogListener{
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
showDialog();
//演示用 這里就不去創建布局了
return super.onCreateView(inflater, container, savedInstanceState);
}
private void showDialog() {
ConfirmDialogFragment dialogFragment = new ConfirmDialogFragment();
//設置target用于在dialogFragment中區分context是activity還是fragment 第二個參數為 requestCode 方便書寫這里為0
dialogFragment.setTargetFragment(this,0);
dialogFragment.show(getChildFragmentManager(),"tag");
}
@Override
public void onConfirmDialogPositiveListener() {
//確認事件
}
@Override
public void onConfirmDialogCancelListener() {
//取消事件
}
}
#### 缺點
- 宿主需要先實現接口,不能通過匿名內部類的方式傳遞
- 如果一個activity需要彈出多個對話框,宿主本身會override很多方法
#### 未實現功能
- 一個activity多次彈出dialog,每次按鈕有不同的功能,需要加入回調參數來區分 (待更新)
待更新