教你對Android項目的需求進行封裝抽象(下)

我們來實現Android端的彈框顯示邏輯,由於需要顯示的分享彈框業務種類有八種,所以必要的封裝和抽象是必要的

1.封裝前後臺切換監聽

點擊參考這篇前後臺切換管理類

在應用的主頁的onCreate()中調用:

       //根據前後臺切換監聽檢測是否有分享彈窗
        AppBackgroundManager.getInstance().initWatcher().setAppStateListener(new AppBackgroundManager.IAppStateChangeListener() {
            @Override
            public void onAppStateChanged(boolean isAppForceground) {

                if (isAppForceground) {
                   ShareCommandMgr.getInstance().startCheckShareCommand();
                }
            }
        });

考慮到項目中主頁之前還有啓動頁,在前後臺切換管理類的基礎上,我加了一個方法,以便在第一次打開應用時,主頁第一次走onCreate()時也能回調onAppStateChanged

    /**
     * 開始監聽時調用,只允許調用一次
     */
    private boolean isInited = false;

    public AppBackgroundManager initWatcher() {
        if (!isInited) {
            isAppForeground = false;

            isInited = true;
        }
        return this;
    }


(因爲註冊的前後臺監聽是在主頁,閃屏頁啓動之後,如果沒有這個方法,第一次啓動APP進入閃屏頁,mListener == null,後續都在前臺,主頁就不會再走回調,而我希望第一次進入主頁也會有回調。請細品代碼哦)

    //App前後臺切換
    private void onAppForegroundStateChange(boolean isAppForeground) {
        if (mListener == null) {
            return;
        }
        mListener.onAppStateChanged(isAppForeground);
    }

別忘了在應用的Application的onCreate中增加方法:

    /**
     * 註冊監聽應用全局activity生命週期的監聽,判斷應用前臺後臺切換
     */
    private void registerActivityLifeCycle() {
        getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

            }

            @Override
            public void onActivityStarted(Activity activity) {
                AppBackgroundManager.getInstance().onActivityStarted(activity.getLocalClassName());
            }

            @Override
            public void onActivityResumed(Activity activity) {

            }

            @Override
            public void onActivityPaused(Activity activity) {

            }

            @Override
            public void onActivityStopped(Activity activity) {
                AppBackgroundManager.getInstance().onActivityStopped();
            }

            @Override
            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

            }

            @Override
            public void onActivityDestroyed(Activity activity) {

            }
        });
    }

2.獲取口令,獲取分享數據

剛剛在前後臺回調中做了如下調用,看看內部是如何封裝的

ShareCommandMgr.getInstance().startCheckShareCommand();
/**
 * 分享彈窗管理類
 */
public class ShareCommandMgr {

    public static ShareCommandMgr uHelper;

    public static ShareCommandMgr getInstance() {
        if (uHelper == null) {
            synchronized (ShareCommandMgr.class) {
                if (uHelper == null) {
                    uHelper = new ShareCommandMgr();
                }
            }
        }
        return uHelper;
    }


    /**
     * 粘貼板是否含自己的口令
     * <p>
     * #LZ100_200000#
     * #LZabcdefg890123456#
     * 客戶端判斷 #LZ開頭 和#結尾中間的內容code,
     * 若code的長度>16 或等於0則不處理;
     *
     * @return
     */
    public boolean isLzShareCommand() {

        if (StringUtils.isEmpty(ClipboardUtils.getText())) {
            return false;
        }
        String command = ClipboardUtils.getText().toString();

        if (StringUtils.isTrimEmpty(command)) {
            return false;
        }

        if (command.length() <= 4) {
            return false;
        }

        if (command.startsWith("#LZ") && command.endsWith("#")) {
            return true;
        }
        return false;
    }

    /**
     * 開始解析並顯示口令
     */
    public void startCheckShareCommand() {

        //如果不是自己的口令直接退出
        if (!isLzShareCommand()) {
            return;
        }

        //獲取粘貼板文本口令
        String commandFull = ClipboardUtils.getText().toString();

        //根據口令調接口
        getShareDataByCommand(commandFull);

    }

    public void getShareDataByCommand(String shareCode) {
        RetrofitFactory.composeAndAutoDispose(RetrofitFactory.getAPI().share_detail(shareCode), (AppCompatActivity) ActivityUtils.getTopActivity())
                .subscribe(new SmartObserver<ShareCommandData>(ActivityUtils.getTopActivity()) {
                    @Override
                    public void onSuccess(BaseBean<ShareCommandData> bean) {
                        if (bean.getData() == null) {
                            return;
                        }
                        //根據類型顯示不同的口令彈窗
                        if (bean.getData().equipment != null) {
                            //顯示設備彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
                                    .setData(bean.getData(), bean.getData().equipment)
                                    .show();
                        } else if (bean.getData().equipmentdemand != null) {
                            //顯示求租彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_RENT_OUT)
                                    .setData(bean.getData(), bean.getData().equipmentdemand)
                                    .show();
                        } else if (bean.getData().goods != null) {
                            //顯示商品彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_PRODUCT)
                                    .setData(bean.getData(), bean.getData().goods)
                                    .show();
                        } else if (bean.getData().demand != null) {
                            //顯示採購單彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_PURCHASE)
                                    .setData(bean.getData(), bean.getData().demand)
                                    .show();
                        } else if (bean.getData().recruit != null) {
                            //顯示招聘彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_RECRUIT)
                                    .setData(bean.getData(), bean.getData().recruit)
                                    .show();
                        } else if (bean.getData().resume != null) {
                            //顯示人才簡歷彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_TALENT)
                                    .setData(bean.getData(), bean.getData().resume)
                                    .show();
                        } else if (bean.getData().userinfo != null) {
                            //顯示個人主頁彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_PERSONAL)
                                    .setData(bean.getData(), bean.getData().userinfo)
                                    .show();

                        }else{
                            Log.i("LZ", "不支持的彈窗類型");
                        }

                        //清除粘貼板口令信息,防止重複進入應用重複顯示彈窗
                        ClipboardUtils.copyText("");

                    }

                    @Override
                    public void onFailure(int code, String errorMsg) {
                        super.onFailure(code, errorMsg);
                    }
                });


    }

3.抽象彈窗顯示

ShareCommandMgr 中顯示彈窗的代碼如下:

      //顯示設備彈窗
                            ShareCommandFactory.getInstance()
                                    .newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
                                    .setData(bean.getData(), bean.getData().equipment)
                                    .show();

我們來看看內部實現,這裏用了工廠模式,以較爲優雅的方式創建不同風格的彈框,畢竟彈框種類不少:

/**
 * 分享彈窗工廠
 */
public class ShareCommandFactory {

    public static final int TYPE_MACHINE = 0;//機械設備
    public static final int TYPE_PURCHASE = 1;//採購單
    public static final int TYPE_RENT_OUT = 2;//求租
    public static final int TYPE_RECRUIT = 3;//招聘
    public static final int TYPE_TALENT = 4;//人才
    public static final int TYPE_PERSONAL = 5;//主頁
    public static final int TYPE_PRODUCT = 6;//商品

    public static ShareCommandFactory uHelper;

    public static ShareCommandFactory getInstance() {
        if (uHelper == null) {
            synchronized (ShareCommandFactory.class) {
                if (uHelper == null) {
                    uHelper = new ShareCommandFactory();
                }
            }
        }
        return uHelper;
    }


    private IShareCommand iShareCommand = null;

    /**
     * 創建分享彈窗場景實例
     *
     * @param type
     * @return
     */
    public ShareCommandFactory newShareCommandViewScene(int type) {
        switch (type) {
            case TYPE_MACHINE:
                iShareCommand = new MachineSence();
                break;

            case TYPE_PURCHASE:
                iShareCommand = new PurchaseSence();
                break;

            case TYPE_RENT_OUT:
                iShareCommand = new RentOutSence();
                break;

            case TYPE_RECRUIT:
                iShareCommand = new RecruitSence();
                break;

            case TYPE_TALENT:
                iShareCommand = new TalentSence();
                break;

            case TYPE_PERSONAL:
                iShareCommand = new PersonalSence();
                break;

            case TYPE_PRODUCT:
                iShareCommand = new ProductSence();
                break;

            default:
                iShareCommand = new MachineSence();
                break;

        }
        return this;

    }

    /**
     * 設置彈窗中的數據
     * @param bean
     * @param data
     * @param <T>
     */
    public <T> ShareCommandFactory setData(ShareCommandData bean, T data){
        if (iShareCommand != null) {
            iShareCommand.setData(bean,data);
        }
        return this;
    }

    /**
     * 顯示彈窗
     *
     */
    public void show() {
        if (iShareCommand != null) {
            iShareCommand.showShareSceneView();
        }

    }
}

對於彈窗的顯示,我做了小小的抽象,寫了個基類:

/**
 * 分享彈窗抽象類
 * @param <T>
 */
public abstract class IShareCommand<T> {

    /**
     * 數據
     */
    protected T mData;
    protected ShareCommandData mDataParent;
    /**
     * view
     */
    protected View mView;

    /**
     * 彈窗資源layout
     * @return
     */
    public abstract int getLayoutResId();

    /**
     * 綁定數據到界面
     */
    public abstract void bindDataToView();

    /**
     * 界面上點擊查看詳情按鈕
     */
    public abstract void navigationTo();


    /**
     * 設置數據
     * @param mDataParent
     * @param data
     * @return
     */
    public IShareCommand setData(ShareCommandData mDataParent,T data) {
        this.mDataParent = mDataParent;
        mData = data;
        return this;
    }


    /**
     * 顯示彈窗
     * @return
     */
    public IShareCommand showShareSceneView(){
        CustomDialog.show(ActivityUtils.getTopActivity(), getLayoutResId(), new CustomDialog.BindView() {
            @Override
            public void onBind(final CustomDialog dialog, View v) {

                mView = v;

                //彈窗界面相似邏輯基類統一處理start
                v.findViewById(R.id.ll_cancel).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        dialog.doDismiss();
                    }
                });
                v.findViewById(R.id.tv_navigation).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //跳轉
                        navigationTo();
                        dialog.doDismiss();
                    }
                });


                GlideImageView avatar = mView.findViewById(R.id.iv_avatar);
                TextView username = mView.findViewById(R.id.tv_user_name);
                LinearLayout ll_share_user_top = mView.findViewById(R.id.ll_share_user_top);
                if (mDataParent.frominfo == null) {
                    ll_share_user_top.setVisibility(View.GONE);
                } else {
                    avatar.setImageUrl(mDataParent.frominfo.fromavatar);
                    username.setText(mDataParent.frominfo.nickname);
                }

                //彈窗界面相似邏輯基類統一處理end
                
                //綁定數據到界面
                bindDataToView();
            }
        });
        return this;
    }

}

然後每個業務場景的彈窗只需要繼承這個抽象類,實現不同的彈窗風格,設置不同類型的數據,跳轉到自己的詳情頁即可:
比如,其中一個彈窗示例:

/**
 * 機械設備分享彈窗
 */
public class MachineSence extends IShareCommand<ShareCommandData.Equipment> {
    /**
     * 彈窗界面
     * @return
     */
    @Override
    public int getLayoutResId() {
        return R.layout.share_command_machine_dialog;
    }

    /**
     * 綁定數據到界面
     */
    @Override
    public void bindDataToView() {
        GlideImageView ivTop = mView.findViewById(R.id.iv_top);
        if (!BosUtil.isRealUrl(mData.pic)) {
            ivTop.setImageUrl(BosUtil.getRealUrlByShort(mData.pic));
        } else {
            ivTop.setImageUrl(mData.pic);
        }

        TextView title = mView.findViewById(R.id.tv_title);
        title.setText(mData.title);

        TextView tv_name_price = mView.findViewById(R.id.tv_name_price);
        if (StringUtils.isEmpty(mData.rentpricelist) || mData.rentpricelist.equals("面議")) {
            tv_name_price.setText("面議");
        } else {
            tv_name_price.setText(mData.rentpricelist);
        }
    }

    /**
     * 跳轉
     */
    @Override
    public void navigationTo() {
        ARouter.getInstance().build(RoutingTable.DeviceDetail)
                .withString("id", mData.id)
                .navigation();
    }

}

最後重新看下分享彈窗管理類調用代碼顯示彈窗邏輯:

    //顯示設備彈窗
      ShareCommandFactory.getInstance()
             .newShareCommandViewScene(ShareCommandFactory.TYPE_MACHINE)
             .setData(bean.getData(), bean.getData().equipment)
             .show();

是不是很優雅的實現了彈窗的顯示,這就是Java封裝與抽象的魅力,這也和平時封裝BaseActivity或者BaseFragment相似,只是這裏多了個工廠模式,很簡單,請客觀細品。

歡迎關注公衆號,給你更多技術乾貨:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章