浅谈BaseActivity写法,促使我们更高效开发

简介: 浅谈Bas浅谈BaseActivity写法,促使我们更高效开发

抓住人生中的一分一秒,胜过虚度中的一月一年!

前言

在Android开发中,activity再常用不过了,为了高效开发,我们会将一些常用的功能和页面统一实现的效果放在基类,这样就不用写每个页面时再重新实现这些功能,下面是我总结了些内容与大家共享一下,有不足的地方希望大家提出我将进行再次完善。

实现目标

1、屏幕横竖屏切换,AndroidManifest中将不用再写android:screenOrientation="portrait"

2、ButterKnife绑定页面

3、沉浸式实现

4、携带数据的页面跳转

5、应用被强杀检测

6、标题栏统一实现

7、仿IOS侧滑finish页面实现

8、Loading页面统一实现(可替换成骨架图)

9、点击Edittext弹出软键盘,点击空白区域让软键盘消失

10、结合MVP模式下的BaseActivity


1、屏幕横竖屏切换,AndroidManifest中将不用再写android:screenOrientation="portrait"

我们经常开发的app,一般情况下都是手机上的应用,我想大家已经设置了强制竖屏,因为横屏没有特殊要求没有必要去设置,设置了反而会出现更多问题,其次说一下8.0更新问题,页面同时设置了android:screenOrientation="portrait"和透明属性,8.0运行会出现Only fullscreen opaque activities can request orientation异常,大概意思为“只有不透明的全屏activity可以自主设置界面方向”,我们或许会引用一些第三方SDK到项目中,也许第三方会用到透明属性,我们可能在AndroidManifest中会申明android:screenOrientation="portrait"后导致莫名其妙的奔溃(小概率事件,但不排除),所以建议在BaseActivity设置比较优(当你做侧滑返回以后就不会觉得我说这么啰嗦了)

/**
     * 设置屏幕横竖屏切换
     *
     * @param screenRoate true  竖屏     false  横屏
     */
    private void setScreenRoate(Boolean screenRoate) {
        if (screenRoate) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//设置竖屏模式
        } else {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }
    }
 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setScreenRoate(true);
    }
2、ButterKnife绑定页面

ButterKnife这个快速申明控件省了我们多少findViewById的时间,推荐使用,详细写一写可能有人没用过此控件

1、依赖

compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

2、onCreate绑定页面  onDestroy取消绑定

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ButterKnife.bind(this);
    }
  @Override
    protected void onDestroy() {
        super.onDestroy();
        ButterKnife.bind(this).unbind();
    }
3、沉浸式实现

为了让用户感受更好的体验效果,所以我们会选择设置沉浸式,每个页面大多数都会设置一种效果,所以直接在BaseActivity设置即可

/**
     * 沉浸式实现
     */
    protected void setStatusBar() {
        StatusBarUtil.setColor(this, getResources().getColor(R.color.colorWhite), 0);
//        StatusBarUtil.setTranslucentForImageViewInFragment(this, 0, null);
    }
   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStatusBar();
    }

问:如果有页面不想设置此效果

答:在对应Activity重写setStatusBar(),做自定义操作

4、携带数据的页面跳转

跳转页面 startActivity(new Intent(this, MainActivity.class));不改装这已经是最简洁了,你要记住,程序员是比较懒的,能少写就少写

/**
     * [页面跳转]
     *
     * @param clz
     */
    public void startActivity(Class<?> clz) {
        startActivity(clz, null);
    }
    /**
     * [携带数据的页面跳转]
     *
     * @param clz
     * @param bundle
     */
    public void startActivity(Class<?> clz, Bundle bundle) {
        Intent intent = new Intent();
        intent.setClass(this, clz);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }
    /**
     * [含有Bundle通过Class打开编辑界面]
     *
     * @param cls
     * @param bundle
     * @param requestCode
     */
    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
        Intent intent = new Intent();
        intent.setClass(this, cls);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }

跳转页面startActivity(MainActivity.class);嗯。。。少写了几个字母

5、应用被强杀检测

手机开了N多个应用,可能导致内存不足,所以GC就出来工作了,也许你的App就是被杀的对象(保活处理移步其他文章),我们需要检测到APP是否被杀

思路:

(1)APP被杀,可以跳转到闪屏页,再跳转到MainActivity,但可能MainActivity还存在,我想让MainActivity彻底消失,所以我的思路是跳转到MainActivity,将MainActivity  finish再跳转到闪屏页,再往其他页面跳转

(2)那怎么样检测APP是否被杀呢,我进入到APP后将一个参数设置个值,如果APP被杀,也就是说我们当时设置的值已经不存在了,当我们检测到这个值和我们当时设置的值不匹配说明APP被杀了

1、新建个常量类AppStatusConstant

/**
 * File descripition:   APP状态跟踪器常量码
 *
 * @author lp
 * @date 2018/9/29
 */
public class AppStatusConstant {
    public static final int STATUS_FORCE_KILLED=-1; //应用放在后台被强杀了
    public static final int STATUS_NORMAL=2;  //APP正常态
    //intent到MainActivity 区分跳转目的
    public static final String KEY_HOME_ACTION="key_home_action";//返回到主页面
    public static final int ACTION_BACK_TO_HOME=6; //默认值
    public static final int ACTION_RESTART_APP=9;//被强杀
}

2、新建个单例模式,用来保存值

/**
 * File descripition:
 *
 * @author lp
 * @date 2018/9/29
 */
public class AppStatusManager {
    public int appStatus= AppStatusConstant.STATUS_FORCE_KILLED;        //APP状态 初始值为没启动 不在前台状态
    public static AppStatusManager appStatusManager;
    private AppStatusManager() {
    }
    public static AppStatusManager getInstance() {
        if (appStatusManager == null) {
            appStatusManager = new AppStatusManager();
        }
        return appStatusManager;
    }
    public int getAppStatus() {
        return appStatus;
    }
    public void setAppStatus(int appStatus) {
        this.appStatus = appStatus;
    }
}

3、进入到闪屏页我便给appStatus赋值

/**
 * File descripition:   闪屏页
 *
 * @author lp
 * @date 2018/10/16
 */
public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        AppStatusManager.getInstance().setAppStatus(AppStatusConstant.STATUS_NORMAL); //进入应用初始化设置成未登录状态
        super.onCreate(savedInstanceState);
    }
}

4、在BaseActivity的onCreate中去检测这个值是否是我们设置过的值

private void initAppStatus() {
        switch (AppStatusManager.getInstance().getAppStatus()) {
            /**
             * 应用被强杀
             */
            case AppStatusConstant.STATUS_FORCE_KILLED:
                //跳到主页,主页lauchmode SINGLETASK
                protectApp();
                break;
        }
    }
 protected void protectApp() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_RESTART_APP);
        startActivity(intent);
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initAppStatus();
    }

5、MainActivity中接收传过来的信息,然后调整到闪屏页

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        int action = intent.getIntExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_BACK_TO_HOME);
        switch (action) {
            case AppStatusConstant.ACTION_RESTART_APP:
                protectApp();
                break;
        }
    }
 @Override
    protected void protectApp() {
        Toast.makeText(getApplicationContext(), "应用被回收重新启动", Toast.LENGTH_LONG).show();
        startActivity(new Intent(this, SplashActivity.class));
        finish();
    }
6、标题栏统一实现

每个页面大多数都会有个标题栏,实现方式我们都会,下面我介绍另一种方式,我把标题栏写到BaseActivity布局中,这样在对应的Activity就不用一遍一遍的写了,但是弊端是多了一层嵌套

思路:我们在BaseActivity申明一个布局,其子Activity的xml塞入到父布局的一个控件中,这样就每个子Activity都会有统一的控件了(标题栏)

1、首先新建个关于title的xml,app_title.xml(供参考)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rlt_base"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@color/colorWhite">
    <LinearLayout
        android:id="@+id/back"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:paddingLeft="@dimen/padding_12"
        android:paddingRight="@dimen/padding_12">
        <TextView
            android:id="@+id/back_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="@dimen/margin_8"
            android:drawableLeft="@mipmap/zuojiantou"
            android:drawablePadding="@dimen/padding_8"
            android:gravity="center"
            android:textColor="@color/colorBlack"
            android:visibility="visible" />
    </LinearLayout>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_marginLeft="80dp"
        android:layout_marginRight="80dp">
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_centerInParent="true"
            android:ellipsize="end"
            android:gravity="center"
            android:lines="1"
            android:textColor="@color/colorBlack"
            android:textSize="@dimen/text_18" />
    </RelativeLayout>
    <TextView
        android:id="@+id/tv_right"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:drawablePadding="@dimen/padding_6"
        android:ellipsize="end"
        android:gravity="center"
        android:lines="1"
        android:paddingLeft="14dp"
        android:paddingRight="14dp"
        android:textColor="@color/colorBlack"
        android:textSize="@dimen/text_16"
        android:visibility="visible" />
    <View
        style="@style/View_o_5"
        android:layout_alignParentBottom="true" />
</RelativeLayout>

2、创建父布局的xml,activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <include layout="@layout/app_title" />
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3、都创建好了就该给BaseActivity设置布局了

public abstract class BaseActivityNall extends AppCompatActivity {
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;
    protected View rootView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);
    }
    private void addContent() {
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);
        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());//java8写法,特此备注一下
        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
        }
    }
    /**
     * 获取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * title赋值
     *
     * @return
     */
    protected abstract String getContentTitle();
}
7、仿IOS侧滑finish页面实现

实现侧滑会有很多弊端,在此就不细讲实现方式了,给大家演示一种,但是想完美实现还需进一步完善,第三方库实现,方法在BaseActivity写

implementation 'com.r0adkll:slidableactivity:2.0.6'
/**
     * 初始化滑动返回
     */
    protected void initSlidable() {
        int isSlidable = SettingUtil.getInstance().getSlidable();
        if (isSlidable != Constants.SLIDABLE_DISABLE) {
            SlidrConfig config = new SlidrConfig.Builder()
                    .edge(isSlidable == Constants.SLIDABLE_EDGE)
                    .build();
            slidrInterface = Slidr.attach(this, config);
        }
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initSlidable();
    }
// Base application theme. 
    <style name="MyAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
       // <item name="android:windowAnimationStyle">@style/activityAnimation</item>
        <item name="android:windowIsTranslucent">true</item>
        <!--<item name="android:windowDisablePreview">true</item>-->
        <item name="android:windowBackground">@android:color/transparent</item>
    </style>
有很多类似的开源框架 暂举四个
  1. SwipeBackLayout
  2. Slidr
  3. Snake
  4. and_swipeback
8、Loading页面统一实现(可替换成骨架图)

看了一个大神写的一个框架,超级来感觉呀 spruce-android,在BaseActivity封装简单的给大家演示下,具体封装大家去实现

/**
 * File descripition: activity基类
 * <p>
 *
 * @author lp
 * @date 2018/5/16
 */
public abstract class BaseActivityNall extends AppCompatActivity implements BaseView {
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;
    public int mIndex = BaseContent.baseIndex;
    protected View rootView;
    protected LoadService mBaseLoadService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);
        this.initData();
        this.getData();
    }
    private void addContent() {
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);
        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());//java8写法,特此备注一下
        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
            mBaseLoadService = LoadSir.getDefault().register(content, new Callback.OnReloadListener() {
                @Override
                public void onReload(View v) {
                    onNetReload(v);
                }
            });
        }
    }
    protected void onNetReload(View v) {
        mBaseLoadService.showCallback(LoadingCallback.class);
        mIndex = BaseContent.baseIndex;
        getData();
    }
    /**
     * 获取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * title赋值
     *
     * @return
     */
    protected abstract String getContentTitle();
    /**
     * 数据初始化操作
     */
    protected abstract void initData();
    /**
     * 请求数据
     */
    protected abstract void getData();
}
9、点击Edittext弹出软键盘,点击空白区域让软键盘消失

在我们使用Edittext时,软键盘弹出了,写完字之后,想让它消失,不去处理想让软键盘消失需要点击软键盘中的消失按钮,显然不是很方便的方法,我们想点击非Edittext任何地方都让软键盘(也可以点击Edittext让软键盘消失),请往下看,有俩种实现方法

(1)、第一种实现方法,扩展性差

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideKeyboard(v, ev)) {
                hideKeyboard(v.getWindowToken());
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    /**
     * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击EditText的事件,忽略它。
                return false;
            } else {
                return true;
            }
        }
        // 如果焦点不是EditText则忽略,这个发生在视图刚绘制完,第一个焦点不在EditText上,和用户用轨迹球选择其他的焦点
        return false;
    }
    /**
     * 获取InputMethodManager,隐藏软键盘
     *
     * @param token
     */
    private void hideKeyboard(IBinder token) {
        if (token != null) {
            InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

(2)、第二种实现方法(推荐使用)

/**
     * 以下是关于软键盘的处理
     */
    /**
     * 清除editText的焦点
     *
     * @param v   焦点所在View
     * @param ids 输入框
     */
    public void clearViewFocus(View v, int... ids) {
        if (null != v && null != ids && ids.length > 0) {
            for (int id : ids) {
                if (v.getId() == id) {
                    v.clearFocus();
                    break;
                }
            }
        }
    }
    /**
     * 隐藏键盘
     *
     * @param v   焦点所在View
     * @param ids 输入框
     * @return true代表焦点在edit上
     */
    public boolean isFocusEditText(View v, int... ids) {
        if (v instanceof EditText) {
            EditText et = (EditText) v;
            for (int id : ids) {
                if (et.getId() == id) {
                    return true;
                }
            }
        }
        return false;
    }
    //是否触摸在指定view上面,对某个控件过滤
    public boolean isTouchView(View[] views, MotionEvent ev) {
        if (views == null || views.length == 0) {
            return false;
        }
        int[] location = new int[2];
        for (View view : views) {
            view.getLocationOnScreen(location);
            int x = location[0];
            int y = location[1];
            if (ev.getX() > x && ev.getX() < (x + view.getWidth())
                    && ev.getY() > y && ev.getY() < (y + view.getHeight())) {
                return true;
            }
        }
        return false;
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (isTouchView(filterViewByIds(), ev)) {
                return super.dispatchTouchEvent(ev);
            }
            if (hideSoftByEditViewIds() == null || hideSoftByEditViewIds().length == 0) {
                return super.dispatchTouchEvent(ev);
            }
            View v = getCurrentFocus();
            if (isFocusEditText(v, hideSoftByEditViewIds())) {
                KeyBoardUtils.hideInputForce(this);
                clearViewFocus(v, hideSoftByEditViewIds());
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    /**
     * 传入EditText的Id
     * 没有传入的EditText不做处理
     *
     * @return id 数组
     */
    public int[] hideSoftByEditViewIds() {
        return null;
    }
    /**
     * 传入要过滤的View
     * 过滤之后点击将不会有隐藏软键盘的操作
     *
     * @return id 数组
     */
    public View[] filterViewByIds() {
        return null;
    }

使用方法:在对应的Activity重写hideSoftByEditViewIds()和filterViewByIds(),传入需要弹出的软键盘的ID

/*实现案例===============================================================================================*/
    @Override
    public int[] hideSoftByEditViewIds() {
        int[] ids = {R.id.et_company_name, R.id.et_address};
        return ids;
    }
    @Override
    public View[] filterViewByIds() {
        View[] views = {mEtCompanyName, mEtAddress};
        return views;
    }
10、结合MVP模式下的BaseActivity,传送地址
/**
 * File descripition: activity基类
 * <p>
 *
 * @author lp
 * @date 2018/5/16
 */
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements BaseView {
    protected final String TAG = this.getClass().getSimpleName();
    public View mViewStatusBar;
    public TextView mBackName;
    public LinearLayout mBack;
    public TextView mTvTitle;
    public TextView mTvRight;
    public RelativeLayout mRltBase;
    public Activity mContext;
    protected P mPresenter;
    private LoadingDialog mLodingDialog;
    protected abstract P createPresenter();
    //错误提示框  警告框  成功提示框
    private PromptDialog promptDialog;
    public int mIndex = BaseContent.baseIndex;
    protected View rootView;
    protected LoadService mBaseLoadService;
    /**
     * 是否显示初始Loading
     */
    private Boolean isShow = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//设置竖屏模式
        mContext = this;
        rootView = View.inflate(this, R.layout.activity_title, null);
        setContentView(getLayoutId());
        addContent();
        setContentView(rootView);
        mPresenter = createPresenter();
        AppManager.getAppManager().addActivity(this);
        setStatusBar();
        initAppStatus();
        ButterKnife.bind(this);
        this.initData();
    }
    private void initAppStatus() {
        switch (AppStatusManager.getInstance().getAppStatus()) {
            /**
             * 应用被强杀
             */
            case AppStatusConstant.STATUS_FORCE_KILLED:
                //跳到主页,主页lauchmode SINGLETASK
                protectApp();
                break;
        }
    }
    private void addContent() {
        mViewStatusBar = (View) rootView.findViewById(R.id.view_status_bar);
        mBackName = (TextView) rootView.findViewById(R.id.back_name);
        mBack = (LinearLayout) rootView.findViewById(R.id.back);
        mTvTitle = (TextView) rootView.findViewById(R.id.tv_title);
        mTvRight = (TextView) rootView.findViewById(R.id.tv_right);
        mRltBase = (RelativeLayout) rootView.findViewById(R.id.rlt_base);
        FrameLayout flContent = (FrameLayout) rootView.findViewById(R.id.fl_content);
        mTvTitle.setText(getContentTitle() == null ? "" : getContentTitle());
        mBack.setOnClickListener(v -> finish());
        View content = View.inflate(this, getLayoutId(), null);
        if (content != null) {
            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
                    FrameLayout.LayoutParams.MATCH_PARENT);
            flContent.addView(content, params);
            ButterKnife.bind(this, rootView);
            mBaseLoadService = LoadSir.getDefault().register(content, new Callback.OnReloadListener() {
                @Override
                public void onReload(View v) {
                    showLoadingLayout();
                    mIndex = BaseContent.baseIndex;
                    getData();
                }
            });
            if (isShow) {
                showLoadingLayout();
            } else {
                PostUtil.postSuccessDelayed(mBaseLoadService, 0);
            }
        }
    }
    protected void protectApp() {
        Intent intent = new Intent(this, MainActivity.class);
        intent.putExtra(AppStatusConstant.KEY_HOME_ACTION, AppStatusConstant.ACTION_RESTART_APP);
        startActivity(intent);
    }
    private void showLoadingLayout() {
        mBaseLoadService.showCallback(LoadingCallback.class);
    }
    public void showLoadingLayout(boolean isShow) {
        this.isShow = isShow;
    }
    /**
     * 获取布局ID
     *
     * @return
     */
    protected abstract int getLayoutId();
    /**
     * title赋值
     *
     * @return
     */
    protected abstract String getContentTitle();
    /**
     * 数据初始化操作
     */
    protected abstract void initData();
    /**
     * 请求数据
     */
    protected abstract void getData();
    /**
     * 沉浸式实现
     */
    protected void setStatusBar() {
        StatusBarUtil.setColor(this, getResources().getColor(R.color.colorWhite), 0);
//        StatusBarUtil.setTranslucentForImageViewInFragment(this, 0, null);
    }
    public void showToast(String str) {
        showToast(str, Toast.LENGTH_SHORT);
    }
    public void showLongToast(String str) {
        showToast(str, Toast.LENGTH_LONG);
    }
    /**
     * 封装toast方法
     *
     * @param str
     * @param dur
     */
    void showToast(String str, int dur) {
        ToastUtils.showToastS(this, str, dur);
    }
    @Override
    public void showError(String msg) {
        showToast(msg);
    }
    @Override
    public void onErrorCode(BaseModel model) {
        if (model.getErrcode() == BaseObserver.NETWORK_ERROR) {//网络连接失败  无网
            PostUtil.postCallbackDelayed(mBaseLoadService, NetWorkErrorCallback.class);
        } else if (model.getErrcode() == BaseObserver.CONNECT_ERROR ||//连接错误
                model.getErrcode() == BaseObserver.CONNECT_TIMEOUT ||//连接超时
                model.getErrcode() == BaseObserver.BAD_NETWORK ||//网络超时
                model.getErrcode() == BaseObserver.CONNECT_NULL//数据为空,显示异常
                ) {
            PostUtil.postCallbackDelayed(mBaseLoadService, ErrorCallback.class);
        } else if (model.getErrcode() == BaseObserver.CONNECT_NOT_LOGIN) {//没有登录,去登录
            startLogin();
        }
    }
    private void startLogin() {
        AppUMS.mIsLogin = false;
        AppUMS.setToken("");
        startActivity(LoginActivity.class);
    }
    @Override
    public void showLoading() {
        showLoadingDialog();
    }
    @Override
    public void hideLoading() {
        closeLoadingDialog();
    }
    public void closeLoadingDialog() {
        if (mLodingDialog != null && mLodingDialog.isShowing()) {
            mLodingDialog.dismiss();
        }
    }
    /**
     * 加载...
     */
    public void showLoadingDialog() {
        if (mLodingDialog == null) {
            mLodingDialog = new LoadingDialog(this).setMessage(getString(R.string.app_loding));
        }
        mLodingDialog.show();
    }
    /**
     * 警告框
     */
    public void showInfoDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showInfo(msg);
    }
    /**
     * 错误提示框
     */
    public void showErrorDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showError(msg);
    }
    /**
     * 成功提示框
     */
    public void showSuccessDialog(String msg) {
        if (promptDialog == null) {
            promptDialog = new PromptDialog(this);
        }
        promptDialog.showSuccess(msg);
    }
    @Override
    protected void onResume() {
        super.onResume();
        MobclickAgent.onResume(this);
    }
    @Override
    protected void onPause() {
        super.onPause();
        MobclickAgent.onPause(this);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ButterKnife.bind(this).unbind();
        AppManager.getAppManager().finishActivity(this);
        if (mPresenter != null) {
            mPresenter.detachView();
        }
    }
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            finishActivity();
            return false;
        }
        return super.dispatchKeyEvent(event);
    }
    public void finishActivity() {
        finish();
    }
    /**
     * [页面跳转]
     *
     * @param clz
     */
    public void startActivity(Class<?> clz) {
        startActivity(clz, null);
    }
    /**
     * [携带数据的页面跳转]
     *
     * @param clz
     * @param bundle
     */
    public void startActivity(Class<?> clz, Bundle bundle) {
        Intent intent = new Intent();
        intent.setClass(this, clz);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }
    /**
     * [含有Bundle通过Class打开编辑界面]
     *
     * @param cls
     * @param bundle
     * @param requestCode
     */
    public void startActivityForResult(Class<?> cls, Bundle bundle, int requestCode) {
        Intent intent = new Intent();
        intent.setClass(this, cls);
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }
    /**
     * 以下是关于软键盘的处理
     */
    /**
     * 清除editText的焦点
     *
     * @param v   焦点所在View
     * @param ids 输入框
     */
    public void clearViewFocus(View v, int... ids) {
        if (null != v && null != ids && ids.length > 0) {
            for (int id : ids) {
                if (v.getId() == id) {
                    v.clearFocus();
                    break;
                }
            }
        }
    }
    /**
     * 隐藏键盘
     *
     * @param v   焦点所在View
     * @param ids 输入框
     * @return true代表焦点在edit上
     */
    public boolean isFocusEditText(View v, int... ids) {
        if (v instanceof EditText) {
            EditText et = (EditText) v;
            for (int id : ids) {
                if (et.getId() == id) {
                    return true;
                }
            }
        }
        return false;
    }
    //是否触摸在指定view上面,对某个控件过滤
    public boolean isTouchView(View[] views, MotionEvent ev) {
        if (views == null || views.length == 0) {
            return false;
        }
        int[] location = new int[2];
        for (View view : views) {
            view.getLocationOnScreen(location);
            int x = location[0];
            int y = location[1];
            if (ev.getX() > x && ev.getX() < (x + view.getWidth())
                    && ev.getY() > y && ev.getY() < (y + view.getHeight())) {
                return true;
            }
        }
        return false;
    }
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (isTouchView(filterViewByIds(), ev)) {
                return super.dispatchTouchEvent(ev);
            }
            if (hideSoftByEditViewIds() == null || hideSoftByEditViewIds().length == 0) {
                return super.dispatchTouchEvent(ev);
            }
            View v = getCurrentFocus();
            if (isFocusEditText(v, hideSoftByEditViewIds())) {
                KeyBoardUtils.hideInputForce(this);
                clearViewFocus(v, hideSoftByEditViewIds());
            }
        }
        return super.dispatchTouchEvent(ev);
    }
    /**
     * 传入EditText的Id
     * 没有传入的EditText不做处理
     *
     * @return id 数组
     */
    public int[] hideSoftByEditViewIds() {
        return null;
    }
    /**
     * 传入要过滤的View
     * 过滤之后点击将不会有隐藏软键盘的操作
     *
     * @return id 数组
     */
    public View[] filterViewByIds() {
        return null;
    }
    /*实现案例===============================================================================================*/
    /*
    @Override
    public int[] hideSoftByEditViewIds() {
        int[] ids = {R.id.et_company_name, R.id.et_address};
        return ids;
    }
    @Override
    public View[] filterViewByIds() {
        View[] views = {mEtCompanyName, mEtAddress};
        return views;
    }
    */
}

最后,祝大家开发顺利!

相关文章
|
2月前
|
Web App开发 缓存 固态存储
简洁实用的5款工具,为工作注入新的活力
在日常工作中,简单而巧妙的工具是我们事业路上的良友。这五款工具简洁而实用,可能会为你的工作注入新的活力。
55 0
|
20天前
|
JavaScript 前端开发 安全
Cypress因其强大的端到端测试能力备受青睐,尤其与TypeScript结合,提升了测试的规范性和准确性。
【6月更文挑战第12天】前端开发日益复杂,测试成为保障代码质量和稳定性的关键。Cypress因其强大的端到端测试能力备受青睐,尤其与TypeScript结合,提升了测试的规范性和准确性。TypeScript使Cypress测试代码更易读、维护,通过类型定义、自定义命令和断言增强测试可靠性。Cypress能模拟真实用户操作,支持时间旅行和高效调试,全面测试前端应用功能。因此,TypeScript+Cypress是前端端到端测试的理想选择。
55 2
|
2月前
|
JavaScript 前端开发 开发者
跟踪最新的JavaScript游戏开发技术趋势需要多方面的努力和参与
【5月更文挑战第14天】跟踪JavaScript游戏开发趋势:访问专业网站和博客(如Medium, GameDev.net),参加JSConf和GDC会议,订阅技术期刊,关注开源项目(如Phaser, Three.js),利用社交媒体(Twitter, Reddit)和在线论坛(Stack Overflow),学习新技术(如WebGL, WebAssembly)。通过这些方式保持对行业动态的敏锐度。
24 4
|
8月前
|
安全 测试技术 持续交付
软件开发、测试常用知识点总结与拓展
脚本(Script): 定义:脚本是一系列计算机指令的文本文件,通常用于自动化任务或执行特定的操作。它可以包括编程语言的代码或一系列命令。 用途:脚本用于自动化重复性任务、批处理作业、配置系统设置等。例如,Shell脚本、Python脚本和JavaScript脚本用于执行各种任务。 图解:通常,脚本的图示是一张文本文件图标,包括文件名和脚本内容的代码段。 队列(Queue): 定义:队列是一种数据结构,遵循FIFO(先进先出)原则,其中最早加入队列的元素最早被移除。队列通常用于管理和协调多个任务或进程之间的顺序执行。 用途:队列在计算机科学中用于任务调度、消息传递、数据缓冲等。例如,操作系统使
215 1
|
12月前
|
算法
简单几行代码背后的重大意义
简单几行代码背后的重大意义
|
设计模式 程序员 开发者
程序员在开发中必经之路:重构代码
众所周知,程序员在开发过程中接手前人代码,或者接手公司外购项目的代码等情况的时候,都有想要重构代码的冲动,与其这样说,不如说程序员只要是接手不是自己亲自写的代码都想重构!俗话说得好:一百个程序员脑中有一百个编程思维,不同程序员就算是开发相同功能的程序,一定会有不同的实现方式,而且代码格式和实现方式也肯定是不一样的,这样就给程序的代码重构留下了伏笔。
149 1
|
敏捷开发 JavaScript 前端开发
接私活福音,validation组件敏捷开发,效率提升5倍!
接私活福音,validation组件敏捷开发,效率提升5倍!
608 0
接私活福音,validation组件敏捷开发,效率提升5倍!
|
存储 设计模式 程序员
多数程序员难以简单的方式开发应用?
  心理学中有一篇相当古老、但又非常重要的论文,题为《魔法数字七(上下浮动二):人类信息处理能力中的一些限制》。这篇文章衡量了大脑处理信息的极限,并给出了一个具体的数字:人脑可以同时容纳五到九个概念。我们当然能够把这个有趣的结论延伸到诸多领域当中,但对软件开发人员而言,下面两项含义最为重要:
113 0
|
前端开发 JavaScript 程序员
优质的组件库都离不开BEM!
当你在编写css代码的时候,是否遇到这样的困扰: 不知道取什么class名? 修改某个组件的样式,担心影响了其他组件? 编写的组件样式如何复用?为了解决这些问题,聪明的程序猿发明了BEM命名法。
240 0
|
安全 Java 程序员
37 岁学编程,发现第一个 Bug,创造商业编程语言
  人类往往对“改变”过敏,并倾向于说:“我们一直是这样做的。”我试图与这一观点抗争,所以我在墙上挂了一个逆时针旋转的钟表。   ——Grace Hopper   在计算机史上,葛丽丝·霍普(Grace Hopper)是一个传奇般的存在。   她是唯一一位被艾伦·麦席森·图灵(Alan Mathison Turing)、史蒂夫·乔布斯(Steve Jobs)、比尔·盖茨(Bill Gates)一同称为“IT界十大最有远见的人才”的女性,发现了计算机程序中第一个“Bug”,创造了商业编程语言COBOL,直到今天,全球60%的商业数据都要用它处理[1]。
205 0