手游海外SDK实战——Android客户端之UI流程控制篇

一、前言

随着国内手游版号申请难度的增加,以及防沉迷等一系列政策的影响,很多国内开发者纷纷开始寻求海外发行之路。那么手游出海首要的是需要一套适合海外发行和运营的手游SDK联运系统。

本系列我们就来开发一套这样的SDK,我们暂且称这套SDK为UGSDK。

整个UGSDK项目,暂时可以分为三大部分——Android客户端SDK部分、iOS客户端SDK部分以及服务端部分(目前不考虑H5游戏部分)。

本篇主要介绍UGSDK项目中Android客户端部分中的UI和流程控制设计。

二、UI设计

1、设计原则

1、每个界面采用单独一个fragment,fragment能重复利用尽可能重复利用。
2、单个fragment中,只能放一个UI界面,不可以将多个UI界面放到一个fragment中。
3、fragment中禁止处理流程跳转,也就是不会直接在一个fragment中push进另一个fragment。
4、流程的控制(fragment的跳转),统一在fragment归属的activity中处理。
5、fragment和activity之间的流程交互,采用回调的方式处理。

2、设计样例:

我们来看下游客升级提示界面的fragment, 演示如何设计单个UI界面的fragment以及处理流程中需要被所属Activity托管的部分:

public class VisitorFragment extends BaseFragment {

    private IVisitorFlowCallback flowCallback;

    public void setFlowCallback(IVisitorFlowCallback callback) {
        this.flowCallback = callback;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(ResourceUtils.getResourceID(activity, "R.layout.ug_layout_visitor"), container, false);

        TextView btnSwitch = (TextView) ResourceUtils.getViewByParent(view, "R.id.ug_visitor_switch");
        btnSwitch.setClickable(true);

        TextView btnContinue = (TextView) ResourceUtils.getViewByParent(view, "R.id.ug_visitor_continue");
        btnSwitch.setClickable(true);

        Button btnUpgrade = (Button) ResourceUtils.getViewByParent(view, "R.id.ug_btn_upgrade");

        btnUpgrade.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                if (flowCallback != null) {
                    flowCallback.onVisitorUpgradeAccount();
                }

            }
        });

        btnSwitch.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                if (flowCallback != null) {
                    flowCallback.onVisitorSwitchAccount();
                }
            }
        });

        btnContinue.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                if (flowCallback != null) {
                    flowCallback.onVisitorContinued();
                }

            }
        });

        return view;
    }

    public interface IVisitorFlowCallback {

        void onVisitorUpgradeAccount();

        void onVisitorSwitchAccount();

        void onVisitorContinued();

    }

}

三、UI流程控制

UI流程的控制,我们采用每个业务流程对应一个单独的activity。 这样我们可以轻松控制流程中不同fragment的跳转以及流程的生命周期,同时也可以最大化fragment的复用。

我们以游客升级这个的流程为例。 该流程总共有三个UI界面,游客升级提示界面-》点击升级,弹出账户升级界面-》点击升级,弹出输入邮箱验证码界面-》点击确定,发送协议给服务端完成账号升级。

在UGSDK中, 我们定义一个VisitorUpgradeActivity来处理这个流程, 我们先来看下代码:

public class VisitorUpgradeActivity extends BaseFragmentActivity implements
        VisitorFragment.IVisitorFlowCallback,
        RegisterFragment.IRegisterFlowCallback,
        EmailCodeFragment.IEmailCodeFlowCallback {

    // 游客账号提示界面
    private VisitorFragment visitorFragment;

    // 账号升级界面(重用注册界面)
    private RegisterFragment upgradeFragment;

    // 输入邮箱验证码界面
    private EmailCodeFragment emailCodeFragment;

    private String email;
    private String password;
    private String code;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        visitorFragment = findOrCreateFragment(VisitorFragment.class);
        upgradeFragment = findOrCreateFragment(RegisterFragment.class);
        upgradeFragment.setTitle(ResourceUtils.getString(this, "R.string.ug_visitor_upgrade_title"));
        upgradeFragment.setButtonText(ResourceUtils.getString(this, "R.string.ug_visitor_upgrade_btn"));
        upgradeFragment.setBackText(ResourceUtils.getString(this, "R.string.ug_visitor_upgrade_cancel"));
        emailCodeFragment = findOrCreateFragment(EmailCodeFragment.class);

        // 首次启动,防止重复fragment堆叠
        if (savedInstanceState == null) {
            push(visitorFragment);
        }

    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        if(fragment instanceof VisitorFragment) {
            ((VisitorFragment)fragment).setFlowCallback(this);
        } else if(fragment instanceof RegisterFragment) {
            ((RegisterFragment)fragment).setFlowCallback(this);
        } else if (fragment instanceof EmailCodeFragment) {
            ((EmailCodeFragment)fragment).setFlowCallback(this);
        }
    }

    /**
     * 游客账号提示界面,点击升级账号,跳转到账号升级界面
     */
    @Override
    public void onVisitorUpgradeAccount() {

        push(upgradeFragment);

    }

    /**
     * 游客账号提示界面,点击切换账号,跳转到登录Activity
     */
    @Override
    public void onVisitorSwitchAccount() {
        // 这里不直接切到登录界面Activity, 直接触发logout,让游戏返回到游戏登录界面,然后再主动登录。
        this.finish();
        SDKManager.getInstance().onLogout();
    }

    /**
     * 游客账号界面,点击继续,直接关闭该Activity
     */
    @Override
    public void onVisitorContinued() {
        this.finish();
    }

    /**
     * 从账号注册界面返回
     */
    @Override
    public void onGotoEmailLogin() {
        fragmentManager.popBackStack();
    }

    /**
     * 跳转到邮箱验证码输入界面
     */
    @Override
    public void onGotoEmailVerify(String email, String password) {

        this.email = email;
        this.password = password;

        push(emailCodeFragment);

    }

    /**
     * 从邮箱验证码返回
     */
    @Override
    public void onEmailCodeBack() {
        fragmentManager.popBackStack();
    }

    /**
     * 点击邮箱验证码验证, 账号升级成功。继续游戏
     */
    @Override
    public void onEmailCodeVerify(String code) {
        this.code = code;
        doUpgrade();
    }

    // 发送注册协议
    private void doUpgrade() {

        UGUser user = SDKManager.getInstance().getLoginedUser();
        if(user == null) {
            ResourceUtils.showTip(this, "R.string.ug_upgrade_failed_no_login");
            return;
        }

        showLoading();
        UserApi.upgrade(user, email, password, code, new IApiListener() {

            @Override
            public void onSuccess(final UGUser data) {
                VisitorUpgradeActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        hideLoading();
                        VisitorUpgradeActivity.this.finish();
                        EmailAccountStore.getInstance().saveEmailAccount(new UGEmailAccount(email, password));
                        SDKManager.getInstance().onUpgradeSuccess(Constants.LoginType.Email, data);
                    }
                });
            }

            @Override
            public void onFailed(final int code, final String msg) {
                Log.e(Constants.TAG, "doUpgrade failed. code:" + code + ";msg:" + msg);
                VisitorUpgradeActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        hideLoading();
                        if (code == ApiRequest.R_CODE_FAIL) {
                            ResourceUtils.showTip(VisitorUpgradeActivity.this, msg);
                        } else {
                            ResourceUtils.showTip(VisitorUpgradeActivity.this, "R.string.ug_upgrade_failed");
                        }
                    }
                });

            }
        });

    }

}

通过上面的代码,我们可以看到, 该流程Activity中, 维护了流程中三个步骤对应的三个fragment:VisitorFragment, RegisterFragment和EmailCodeFragment,并实现了三个Fragment中流程交互对应的Callback。

在onCreate中, 预先初始化了三个fragment,并将第一个步骤游客升级提示fragment给展示了出来。在onAttachFragment中,我们将三个fragment的流程回调监听类都设置为当前activity自身。

下面其他的方法都是对应各个fragment中操作之后对应的流程控制方法了, 在不同的方法中,我们处理流程的跳转或者结束。

最终在最后一步操作,输入邮箱验证码之后,我们像服务端发送请求,完成整个业务流程。

好了,本篇我们介绍了在UGSDK中简化UI和业务流程的控制。

你可能感兴趣的:(手游海外SDK实战——Android客户端之UI流程控制篇)