android封裝框架入門之從自定義對話方塊開始callback幫你忙
android封裝框架入門之從封裝確定、取消對話方塊開始
最近,封裝了一個輕量級的網路非同步網路請求框架MHttpUtils(傳送門),由於非常喜歡RxJava和Retrofit等的鏈式程式設計風格,於是自己搗鼓著按這種風格來封裝,期間的一些封裝思路抽取出來以備記錄查閱。
為什麼要封裝
封裝在減少重複程式碼的同時還能提高開發效率,這便是java中的提高程式碼重用性的思想,好的封裝還能提高app的效能和效率。
封裝應有哪些特點
1、易用性
封裝的框架應該要容易使用,減少程式碼量,降低入門的門檻,提供相應的使用者操作反饋回撥,使用者只用關心經常變動的地方。
2、實用性
封裝的框架應該要具有很好的實用性,否則封裝就沒有了意義
3、儘量保證單例
保持單例主要是為了減少記憶體資源的佔用率,提高app的效率。(這裡說的儘量,因為有些東西使用單例模式反而會有諸多限制)
開始封裝確定、取消對話方塊
下面通過封裝一個確定、取消對話方塊的簡單例子來看看一種封裝的思路。
以前你可能會在每個需要使用對話方塊的地方寫上下面的程式碼:
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(title);
builder.setMessage(message);
builder.setIcon(iconResId);
builder.setNegativeButton("取消" , new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//取消的邏輯處理
}
});
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//確定的邏輯處理
}
});
builder.create().show();
看著不多,如果是同一個類有多處呼叫的話還可以提為全域性變數,但是如果有很多activity都要呼叫的話就覺得好沒意義,必須抽取出來呀。
首先來看如何保證單例(必須單例模式啊):
//確定、取消對話方塊
public class MDialog {
private static MDialog mDialog;
private MDialog() {
}
public static MDialog build() {
if (mDialog == null) {
mDialog = new MDialog();
}
return mDialog;
}
}
再來考慮一下哪些是使用者經常變動的屬性,寫了那麼多builder的你一定知道title、message、icon是由使用者決定的,其實既然抽取出來了,在哪裡顯示的話一定要告訴MDialog,所以還要加上一個上下文物件context。
為MDialog加上title、message、icon、context四個屬性,如何賦值呢?又如何像rxjava、retrofit等的一條鏈的就寫完整個呼叫過程呢?
我猜你肯定想到鏈式程式設計了,鏈式程式設計的核心思想就是方法的返回值為物件自己,這樣每呼叫一個方法返回的還是物件本身,那麼有多少這樣的方法就能調多少了。
完善一下程式碼:
//確定、取消對話方塊
public class MDialog {
...//省略了上面的程式碼
//設定上下文物件
public MDialog with(Context context) {
this.context = context;
return this;
}
//設定標題
public MDialog title(String title) {
this.title = title;
return this;
}
// 設定訊息
public MDialog message(String message) {
this.message = message;
return this;
}
//設定圖示資源id
public MDialog iconResId(int iconResId) {
this.iconResId = iconResId;
return this;
}
}
重點來了,使用者點選確定之後的邏輯處理應該由呼叫者自行處理,這裡就要使用非常有用的回撥思想了,提供一個介面,使用者實現了這個介面,當用戶互動的時候觸發某個事件而回調給使用者實現的這個介面中。
如何定義回撥介面?使用者互動的無非就是點選確認、取消兩個按鈕,所以這樣定義:
interface IOnClickCallback {
void onOk();//點選確定的時候回撥
void onCancel();//點選取消的時候回撥
}
細心的你會發現其實很多時候使用者點選取消是不需要做任何事的,如何讓onCancel方法可以重寫但又不是必須重寫呢?對,抽象類就可以做到,所以我們改造一下上面的程式碼(效果在下面給出):
interface IOnClickCallback {
void onOk();//點選確定的時候回撥
}
//這裡加上static是因為這個介面是寫在MDialog中的,屬於內部類
public static abstract class OnClickCallback implements IOnClickCallback {
public void onCancel() {//點選取消的時候回撥
}
}
最後呼叫一個show方法即顯示對話方塊:
public void show(final OnClickCallback callback) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (!TextUtils.isEmpty(title)) {
builder.setTitle(title);
}
if (!TextUtils.isEmpty(message)) {
builder.setMessage(message);
}
if (iconResId != 0) {
builder.setIcon(iconResId);
}
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onCancel();//點選取消的時候回撥
}
});
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onOk();//點選確認的時候回撥
}
});
builder.create().show();
}
至此,所有的封裝已經完畢,貼一下完整的程式碼:
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
/**
* 自定義確定取消對話方塊
* Created by HDL on 2016/11/22.
*/
//確定、取消對話方塊
public class MDialog {
private static MDialog mDialog;
private String title;//標題
private String message;//提示內容
private int iconResId;//圖示
private Context context;//上下文物件
private MDialog() {
}
public static MDialog build() {
if (mDialog == null) {
mDialog = new MDialog();
}
return mDialog;
}
//設定上下文物件
public MDialog with(Context context) {
this.context = context;
return this;
}
// 設定標題
public MDialog title(String title) {
this.title = title;
return this;
}
//設定訊息
public MDialog message(String message) {
this.message = message;
return this;
}
//設定圖示
public MDialog iconResId(int iconResId) {
this.iconResId = iconResId;
return this;
}
//顯示對話方塊
public void show(final OnClickCallback callback) {
//這裡建議使用V7包中的AlertDialog,導包見標頭檔案
AlertDialog.Builder builder = new AlertDialog.Builder(context);
if (!TextUtils.isEmpty(title)) {
builder.setTitle(title);
}
if (!TextUtils.isEmpty(message)) {
builder.setMessage(message);
}
if (iconResId != 0) {
builder.setIcon(iconResId);
}
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onCancel();
}
});
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
callback.onOk();
}
});
builder.create().show();
}
interface IOnClickCallback {
void onOk();//點選確定的時候回撥
}
public static abstract class OnClickCallback implements IOnClickCallback {
public void onCancel() {//點選取消的時候回撥
}
}
}
使用
下面來看看怎麼使用(是不是沒有重寫):
大多數情況下是這樣使用的:
1、設定標題、內容、處理確定邏輯
MDialog.build()
.with(this)
.title("警告")
.message("您確定要刪除嗎?")
.show(new MDialog.OnClickCallback() {
@Override
public void onOk() {
ToastUtils.showMsg(MDialogDemoActivity.this, "點選確定了");
}
});
是不是沒有重寫onCancel方法?因為很多時候是不需要處理的,如果需要,重寫一下就可以了
2、全部呼叫
MDialog.build()
.with(this)
.title("警告")
.message("您確定要刪除嗎?")
.iconResId(R.mipmap.warning)
.show(new MDialog.OnClickCallback() {
@Override
public void onOk() {
ToastUtils.showMsg(MDialogDemoActivity.this, "點選確定了");
}
@Override
public void onCancel() {
ToastUtils.showMsg(MDialogDemoActivity.this, "點選取消了");
}
});
3、只設置內容
注意:當不設定title的時候,設定了icon,icon也是不顯示出來的
MDialog.build()
.with(this)
.message("您確定要刪除嗎?")
.show(new MDialog.OnClickCallback() {
@Override
public void onOk() {
ToastUtils.showMsg(MDialogDemoActivity.this, "點選確定了");
}
});
驗證單例
要驗證其實很簡單,只需將show方法的返回值型別從void改為物件本身即MDialog,然後在三個Activity中呼叫MDialog,然後答應一下物件就知道是不是同一個物件了。
下圖是單例的驗證:
是同一個吧,驗證搞定。
總結
以上只是我在封裝框架過程中使用到的思想,demo也比較簡單,有人可能會覺得dialog不會封裝這麻煩的,仁者見仁智者見智吧,只是提供一種思路,如果你覺得這篇文章還不錯,頂一下