上一篇

简易集成的MVP模块化App框架(1/3)

前言

一直想整理一个自己app框架,现在刚好不是很忙就整理一下,尚不成熟还有待改进

大纲

1.整体结构:MVP模式+模块化

2.网络框架:Retrofit+Rxjava

3.屏幕适配方案:头条的AndroidAutoSize

4.分享框架:Mob的ShareSDK

5.其他:base、常用工具类以及简易的自定义控件等

6.常见问题

7.使用说明

项目链接

https://github.com/UncleQing/QingFrame

5.其他

Access能不能全屏看图 access窗体弹出全屏_android

utils

glide,对glide进行一次二次封装以及配置

Access能不能全屏看图 access窗体弹出全屏_ide_02

GlideApp对glide一些api进行二次封装,便于调用
public class GlideApp {
    private GlideApp() {
    }

    @Nullable
    public static File getPhotoCacheDir(Context context) {
        return Glide.getPhotoCacheDir(context);
    }

    @Nullable
    public static File getPhotoCacheDir(Context context, String cacheName) {
        return Glide.getPhotoCacheDir(context, cacheName);
    }

    public static Glide get(Context context) {
        return Glide.get(context);
    }

    @VisibleForTesting
    @SuppressLint({"VisibleForTests"})
    public static void init(Glide glide) {
        Glide.init(glide);
    }

    @VisibleForTesting
    @SuppressLint({"VisibleForTests"})
    public static void tearDown() {
        Glide.tearDown();
    }

    public static GlideRequests with(Context context) {
        return (GlideRequests)Glide.with(context);
    }

    public static GlideRequests with(Activity activity) {
        return (GlideRequests)Glide.with(activity);
    }

    public static GlideRequests with(FragmentActivity activity) {
        return (GlideRequests)Glide.with(activity);
    }

    public static GlideRequests with(Fragment fragment) {
        return (GlideRequests)Glide.with(fragment);
    }

    public static GlideRequests with(android.support.v4.app.Fragment fragment) {
        return (GlideRequests)Glide.with(fragment);
    }

    public static GlideRequests with(View view) {
        return (GlideRequests)Glide.with(view);
    }
}

 其他都是一些glide配置,就不贴了

permission,因为6.0之后为了安全需要动态请求一些权限,因此对于权限请求封装了下

Access能不能全屏看图 access窗体弹出全屏_app框架_03

IPermissionRequestProxy请求权限的接口
public interface IPermissionRequestProxy {
    boolean checkSelfPermission(String[] permissions);
    void permissionsCheck(String[] permissions, int requestCode, int error_msg);
    void setResultListener(IRequestResult listener);
}
IRequestResult请求结果的接口
public interface IRequestResult {
    void onRequestResultSuccess();
    void onRequestResultFailed();
}
PermissionWrapper权限申请管理类
/**
 * android 6.0 以后的权限申请,使用一个fragment代理的方式请求权限
 */
public class PermissionWrapper {

    public static final String PACKAGE = "package:";
    private static final String FRAGMENT_PERMISSION = "fragment_permission_request";

    private IPermissionRequestProxy iPermissionRequestProxy;
    private IRequestResult iRequestResult;
    private String[] permissions;
    private int requestCode;
    private int error_msg = R.string.permission_tip;

    private PermissionWrapper(Activity mActivity) {
        iPermissionRequestProxy = getPermissionsFragment((AppCompatActivity) mActivity);
    }

    private PermissionFragmentRequestProxy getPermissionsFragment(AppCompatActivity activity) {
        PermissionFragmentRequestProxy permissionFragmentRequestProxy = findPermissionsFragment(activity);

        if (null == permissionFragmentRequestProxy) {
            permissionFragmentRequestProxy = new PermissionFragmentRequestProxy();
            FragmentManager fragmentManager = activity.getSupportFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(permissionFragmentRequestProxy, FRAGMENT_PERMISSION)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return permissionFragmentRequestProxy;
    }

    private PermissionFragmentRequestProxy findPermissionsFragment(AppCompatActivity activity) {
        return (PermissionFragmentRequestProxy) activity.getSupportFragmentManager().findFragmentByTag(FRAGMENT_PERMISSION);
    }


    /**
     * 检查权限是否已申请
     *
     * @return true 有权限,false 无权限
     */
    private boolean checkSelfPermission() {
        return iPermissionRequestProxy.checkSelfPermission(permissions);
    }

    /**
     * 获取权限dialog
     *
     * @return
     */
    private void permissionsCheck() {
        // 注意这里要使用shouldShowRequestPermissionRationale而不要使用requestPermission方法
        // 因为requestPermissions方法会显示不在询问按钮
        iPermissionRequestProxy.permissionsCheck(permissions, requestCode, error_msg);
    }


    /**
     * 请求权限
     */
    public void requestPermission() {
        if (checkSelfPermission()) {
            iRequestResult.onRequestResultSuccess();
        } else {
            iPermissionRequestProxy.setResultListener(iRequestResult);
            permissionsCheck();
        }
    }


    public void clear() {
        permissions = null;
        requestCode = -1;
    }


    public static class Builder {

        PermissionWrapper permissionWrapper;

        public Builder with(Activity mActivity) {
            permissionWrapper = new PermissionWrapper(mActivity);
            return this;
        }

        public Builder with(Fragment fragment) {
            permissionWrapper = new PermissionWrapper(fragment.getActivity());
            return this;
        }

        public Builder requePermissionString(String... permissions) {
            permissionWrapper.permissions = permissions;
            return this;
        }

        public Builder requestCode(int requestCode) {
            if (requestCode <= 0) {
                throw new RuntimeException("The request code cannot be less than or equal to 0");
            }
            permissionWrapper.requestCode = requestCode;
            return this;
        }

        public Builder setErrorMsg(int errorMsg) {
            permissionWrapper.error_msg = errorMsg;
            return this;
        }

        public Builder onResultListener(IRequestResult iRequestResult) {
            permissionWrapper.iRequestResult = iRequestResult;
            return this;
        }


        public PermissionWrapper create() {
            return permissionWrapper;
        }
    }
}
PermissionRequestCode权限请求码管理
/**
 * 权限请求码,避免不同的地方重复
 */
public class PermissionRequestCode {

    //联系人
    public static final int WRITE_CONTACTS = 10000;
    public static final int GET_ACCOUNTS = 10001;
    public static final int READ_CONTACTS = 10002;

    //拨号、读取手机状态等
    public static final int READ_CALL_LOG = 10003;
    public static final int READ_PHONE_STATE = 10004;
    public static final int CALL_PHONE = 10005;
    public static final int USE_SIP = 10006;
    public static final int PROCESS_OUTGOING_CALLS = 10007;
    public static final int ADD_VOICEMAIL = 10008;

    //相机
    public static final int CAMERA = 10009;

    //日历
    public static final int READ_CALENDAR = 10010;
    public static final int WRITE_CALENDAR = 10011;

    //传感器
    public static final int BODY_SENSORS = 10012;


    //定位
    public static final int ACCESS_FINE_LOCATION = 10013;
    public static final int ACCESS_COARSE_LOCATION = 10014;

    //sd卡存储
    public static final int READ_EXTERNAL_STORAGE = 10015;
    public static final int WRITE_EXTERNAL_STORAGE = 10016;

    //麦克风
    public static final int RECORD_AUDIO = 10017;

    //短信
    public static final int READ_SMS = 10018;
    public static final int RECEIVE_WAP_PUSH = 10019;
    public static final int RECEIVE_MMS = 10020;
    public static final int RECEIVE_SMS = 10021;
    public static final int SEND_SMS = 10022;

}
ActivityStackUtils,做为activity管理栈
/**
 * activity stack管理类
 */
public class ActivityStackUtils {
    private static Stack<Activity> sActivityStack = new Stack<Activity>();

    /**
     * 入栈
     * oncreate之后调用
     *
     * @param activity
     */
    public static void addActivity(Activity activity) {
        sActivityStack.add(activity);
    }

    /**
     * 出栈
     * onDestroy之后调用
     *
     * @param activity
     */
    public static void removeActivity(Activity activity) {
        if (activity != null) {
            sActivityStack.remove(activity);
        }

    }

    /**
     * 返回栈顶activity
     *
     * @return
     */
    public static Activity getTopActivity() {
        return sActivityStack.isEmpty() ? null : sActivityStack.lastElement();
    }

    /**
     * 结束当前activity
     * 代替context.finish
     */
    public static void finishActivity() {
        Activity activity = sActivityStack.lastElement();
        finishActivity(activity);
    }

    /**
     * 结束指定activity
     *
     * @param activity
     */
    public static void finishActivity(Activity activity) {
        if (activity != null) {
            sActivityStack.remove(activity);
            finishAnimtor(activity);
            activity = null;
        }
    }

    /**
     * 结束动画,5.0以后区分
     *
     * @param activity
     */
    private static void finishAnimtor(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            activity.finishAfterTransition();
        } else {
            activity.finish();
        }
    }

    /**
     * 结束所有activity
     * exit时调用
     */
    public static void removeAllActivity() {
        if (sActivityStack != null && sActivityStack.size() > 0) {
            Iterator var0 = sActivityStack.iterator();
            while (var0.hasNext()) {
                Activity activity = (Activity) var0.next();
                if (null != activity) {
                    finishAnimtor(activity);
                }
            }
        }

    }

    /**
     * 结束除目标以外的所有activity
     * 一般用于返回到登录页面
     * @param clazz
     */
    public void removeAllActivityWithoutThis(Class<?> clazz) {
        Stack<Activity> tmp = new Stack<>();

        while (!sActivityStack.empty()) {
            Activity current = sActivityStack.pop();//获取到并移除栈顶的对象。
            if (current != null
                    && !current.getClass().getSimpleName()
                    .equals(clazz.getSimpleName())) {
                finishAnimtor(current);
            } else if (null != current &&
                    (current.getClass().getSimpleName().equals(clazz.getSimpleName()))) {
                tmp.push(current);
            }
        }

        if (null != tmp && tmp.size() > 0) {
            sActivityStack.addAll(tmp);
        }
    }
}
AppUtils,使用反射获取app对象
public class AppUtils {

    /**
     * 反射获取app对象
     */
    public static Application getApp() {
        Application application = null;

        try {
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Field appField = activityThreadClass.getDeclaredField("mInitialApplication");
            Method method = activityThreadClass.getMethod("currentActivityThread");
            Object localObject = method.invoke(null, (Object[]) null);
            appField.setAccessible(true);
            application = (Application) appField.get(localObject);
        } catch (ClassNotFoundException var5) {
            var5.printStackTrace();
        } catch (NoSuchFieldException var6) {
            var6.printStackTrace();
        } catch (IllegalAccessException var7) {
            var7.printStackTrace();
        } catch (IllegalArgumentException var8) {
            var8.printStackTrace();
        } catch (NoSuchMethodException var9) {
            var9.printStackTrace();
        } catch (InvocationTargetException var10) {
            var10.printStackTrace();
        }

        return application;
    }
}
CacheCleanUtils,有时候会有清理缓存的需求
/**
 * 缓存获取清理管理类
 */
public class CacheCleanUtils {
    /**
     * 获取缓存大小
     *
     * @param context
     * @return
     * @throws Exception
     */
    public static String getTotalCacheSize(Context context) throws Exception {
        long cacheSize = getFolderSize(context.getCacheDir());
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cacheSize += getFolderSize(context.getExternalCacheDir());
        }
        return getFormatSize(cacheSize);
    }

    /**
     * 清除缓存
     *
     * @param context
     */
    public static void clearAllCache(Context context) {
        deleteDir(context.getCacheDir());
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            deleteDir(context.getExternalCacheDir());
        }
    }

    private static boolean deleteDir(File dir) {
        if (dir != null && dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        return dir.delete();
    }

    // 获取文件大小
    //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
    //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
    public static long getFolderSize(File file) {
        long size = 0;
        try {
            File[] fileList = file.listFiles();
            for (int i = 0; i < fileList.length; i++) {
                // 如果下面还有文件
                if (fileList[i].isDirectory()) {
                    size = size + getFolderSize(fileList[i]);
                } else {
                    size = size + fileList[i].length();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return size;
    }

    /**
     * 格式化单位
     *
     * @param size
     * @return
     */
    public static String getFormatSize(double size) {
        double kiloByte = size / 1024;
        if (kiloByte < 1) {
            return "0K";
        }

        double megaByte = kiloByte / 1024;
        if (megaByte < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "K";
        }

        double gigaByte = megaByte / 1024;
        if (gigaByte < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "M";
        }

        double teraBytes = gigaByte / 1024;
        if (teraBytes < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "GB";
        }
        BigDecimal result4 = new BigDecimal(teraBytes);
        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
                + "TB";
    }
}

其他一些util就不一一列举了,详细请见项目内

自定义控件

Access能不能全屏看图 access窗体弹出全屏_ide_04

picker,一个图片选择器,就是弹出拍照或图库选择的popwindow,结合PhotoUtils对图片进行一些处理

ClipImageView,用于裁剪页面的自定义控件

ClipView,用于裁剪页面的自定义边框

CutPictureActivity,裁剪页面

TakePhotoPopWindow,选择器的popwindow

public class TakePhotoPopWindow extends PopupWindow implements OnClickListener {
    private View mView;
    public Button btnSaveProject, btnAbandonProject, btnCancelProject;
    Context mcontext;

    private PickPhotoListener mListener;

    public TakePhotoPopWindow(Activity context) {

        super(context);
        mcontext = context;
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mView = inflater.inflate(R.layout.populwindow_takephoto, null);

        btnSaveProject = mView.findViewById(R.id.popupwindow_Button_saveProject);
        btnAbandonProject = mView.findViewById(R.id.popupwindow_Button_abandonProject);
        btnCancelProject = mView.findViewById(R.id.popupwindow_cancelButton);


        // 设置按钮监听
        btnCancelProject.setOnClickListener(this);
        btnSaveProject.setOnClickListener(this);
        btnAbandonProject.setOnClickListener(this);


        //设置PopupWindow的View
        this.setContentView(mView);
        //设置PopupWindow弹出窗体的宽
        this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        //设置PopupWindow弹出窗体的高
        this.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
        //设置PopupWindow弹出窗体可点击
        this.setFocusable(true);
        //设置SelectPicPopupWindow弹出窗体动画效果
        this.setAnimationStyle(R.style.AnimationBottomFade);
        //实例化一个ColorDrawable颜色为半透明
        ColorDrawable dw = new ColorDrawable(0x60000000);
        //设置SelectPicPopupWindow弹出窗体的背景
        this.setBackgroundDrawable(dw);
        //全屏遮罩
        this.setClippingEnabled(false);
        //底部状态栏计算
        if (UIUtils.isNavigationBarShow(context)) {
            int heigth = UIUtils.getNavigationBarHeight(context);
            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) btnCancelProject.getLayoutParams();
            lp.bottomMargin = heigth;
            btnCancelProject.setLayoutParams(lp);
        }

    }

    public void setTitle(String... t1) {
        if (t1.length > 0) {
            btnSaveProject.setText(t1[0]);
        }

        if (t1.length > 1) {
            btnAbandonProject.setText(t1[1]);
        } else {
            btnAbandonProject.setVisibility(View.GONE);
        }
    }

    public void setCancel(String cancel) {
        btnCancelProject.setText(cancel);
    }

    public View getmView() {
        return mView;
    }

    @Override
    public void onClick(View v) {
        if (null != mListener) {
            int id = v.getId();
            if (id == R.id.popupwindow_Button_saveProject) {
                mListener.takePhoto();
            } else if (id == R.id.popupwindow_Button_abandonProject) {
                mListener.pickPhoto();
            } else if (id == R.id.popupwindow_cancelButton) {

            }
        }
        dismiss();
    }

    /**
     * 设置拍照回调监听
     *
     * @param listener
     */
    public void setPickPhotoListener(PickPhotoListener listener) {
        mListener = listener;
    }

    public interface PickPhotoListener {
        void takePhoto();

        void pickPhoto();
    }


    public static class Builder {

        private TakePhotoPopWindow photoPopWindow;

        public Builder(Activity mActivity) {
            photoPopWindow = new TakePhotoPopWindow(mActivity);
        }

        public Builder setTitle(String... t1) {
            photoPopWindow.setTitle(t1);
            return this;
        }


        public Builder setCancel(String t1) {
            photoPopWindow.setCancel(t1);
            return this;
        }

        public Builder setListener(PickPhotoListener listener) {
            photoPopWindow.setPickPhotoListener(listener);
            return this;
        }

        public void show(int resId) {
            View view = LayoutInflater.from(photoPopWindow.mcontext).inflate(resId, null, false);
            photoPopWindow.showAtLocation(view, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);

        }
    }

}

share,分享的popwindow以及bean,分享那块说过了

MyToolBar,自定义toolbar,系统自带的个人感觉真是非常难用,显示效果也不理想,所以自定义一套,可以根据实际需求加工下,使用也很简单

详细:

未完待续