android快速开发常用第三方库整合,集成了优雅的日志打印(可自动格式化json,xml,日志输出无字符长度4000的限制),两行代码调用EventBus事件分发,okgo网络访问一行代码实现文件上传下载带进度,上送json xml 等参数,可设置缓存模式以及SSL认证等,万能的RecyclerView适配器BaseQuicklyAdapter,实现上啦刷新,下拉加载,item不同布局,一行代码设置头布局和脚布局.瀑布流,多媒体选择库,photoview图片预览,activity管理类,android端加解密工具类,CircleImageView圆角用户头像,android6.0权限检测
//全局只需初始化一次
KLog.init(BuildConfig.LOG_DEBUG, "KLog");
KLog.d("");
KLog.xml("");//打印xml数据 自动格式化 看图
KLog.json("");//打印json数据 自动格式化 看图
//注册监听
EventBus.getDefault().register(this);
//发出事件
EventBus.getDefault().post(new User("张三",26),"张三");
//接收事件
@Subscriber(tag = "张三", mode = ThreadMode.MAIN)
public void OnEventBus_ZhangSan(User user) {
KLog.d("EventBus使用tag张三接收到User:" + user);
}
//注销事件
EventBus.getDefault().unregister(this);
//全局只需初始化一次
OkGo.init(this);
//以下都不是必须的,根据需要自行选择,一般来说只需要 debug,缓存相关,cookie相关的 就可以了
OkGo.getInstance()
// 打开该调试开关,打印级别INFO,并不是异常,是为了显眼,不需要就不要加入该行
// 最后的true表示是否打印okgo的内部异常,一般打开方便调试错误
.debug("OkGo", Level.INFO, true);
//如果使用默认的 60秒,以下三行也不需要传
// .setConnectTimeout(OkGo.DEFAULT_MILLISECONDS) //全局的连接超时时间
// .setReadTimeOut(OkGo.DEFAULT_MILLISECONDS) //全局的读取超时时间
// .setWriteTimeOut(OkGo.DEFAULT_MILLISECONDS) //全局的写入超时时间
//可以全局统一设置缓存模式,默认是不使用缓存,可以不传,具体其他模式看 github 介绍 https://github.com/jeasonlzy/
// .setCacheMode(CacheMode.NO_CACHE)
//可以全局统一设置缓存时间,默认永不过期,具体使用方法看 github 介绍
// .setCacheTime(CacheEntity.CACHE_NEVER_EXPIRE)
//可以全局统一设置超时重连次数,默认为三次,那么最差的情况会请求4次(一次原始请求,三次重连请求),不需要可以设置为0
// .setRetryCount(3)
//如果不想让框架管理cookie(或者叫session的保持),以下不需要
// .setCookieStore(new MemoryCookieStore()) //cookie使用内存缓存(app退出后,cookie消失)
// .setCookieStore(new PersistentCookieStore()) //cookie持久化存储,如果cookie不过期,则一直有效
//可以设置https的证书,以下几种方案根据需要自己设置
// .setCertificates() //方法一:信任所有证书,不安全有风险
// .setCertificates(new SafeTrustManager()) //方法二:自定义信任规则,校验服务端证书
// .setCertificates(getAssets().open("srca.cer")) //方法三:使用预埋证书,校验服务端证书(自签名证书)
// //方法四:使用bks证书和密码管理客户端证书(双向认证),使用预埋证书,校验服务端证书(自签名证书)
// .setCertificates(getAssets().open("xxx.bks"), "123456", getAssets().open("yyy.cer"))//
//配置https的域名匹配规则,详细看demo的初始化介绍,不需要就不要加入,使用不当会导致https握手失败
// .setHostnameVerifier(new SafeHostnameVerifier())
//可以添加全局拦截器,不需要就不要加入,错误写法直接导致任何回调不执行
// .addInterceptor(new Interceptor() {
// @Override
// public Response intercept(Chain chain) throws IOException {
// return chain.proceed(chain.request());
// }
// })
//这两行同上,不需要就不要加入
// .addCommonHeaders(headers) //设置全局公共头
// .addCommonParams(params); //设置全局公共参数
//简单请求
OkGo.post("url").params("key","v").execute(new AbsCallback<User>() {
@Override
public void onSuccess(User user, Call call, Response response) {
}
@Override
public User convertSuccess(Response response) throws Exception {
return null;
}
});
//定义适配器
public abstract class MyAdapter extends BaseQuickAdapter<MainTab,BaseViewHolder> {
public MyAdapter(@LayoutRes int layoutResId, @Nullable List<MainTab> data) {
super(layoutResId, data);
}
}
//初始化
private MyAdapter mAdapter = new MyAdapter(R.layout.item_main_tab, null) {
@Override
protected void convert(BaseViewHolder helper, MainTab item) {
helper.setText(R.id.tv_tab, item.getTabName());
helper.addOnClickListener(R.id.tv_tab);
}
};
//设置适配器及填充数据
mRvMain.setLayoutManager(new LinearLayoutManager(this));//设置rv布局走向
mAdapter.isFirstOnly(false);//item的加载动画是否仅在第一次加载时生效
mAdapter.openLoadAnimation(BaseQuickAdapter.ALPHAIN);//设置加载动画
mRvMain.setAdapter(mAdapter);
//添加数据
List<MainTab> l = new ArrayList<>();
l.add(new MainTab("测试EventBus事件分发", 0));
l.add(new MainTab("新功能1", 1));
l.add(new MainTab("新功能2", 2));
l.add(new MainTab("新功能3", 3));
l.add(new MainTab("新功能4", 4));
mAdapter.setNewData(l);
//处理item点击事件
mRvMain.addOnItemTouchListener(new OnItemChildClickListener() {
@Override
public void onSimpleItemChildClick(BaseQuickAdapter adapter, View view, int position) {
//item中的单控件点击事件
switch (mAdapter.getData().get(position).getId()) {
case 0:
//测试EventBus事件分发
startActivity(new Intent(MainActivity.this, TwoActivity.class));
break;
case 1:
break;
case 2:
break;
case 3:
break;
}
}
});
mRvMain.addOnItemTouchListener(new OnItemClickListener() {
@Override
public void onSimpleItemClick(BaseQuickAdapter adapter, View view, int position) {
//item的点击事件
}
});
private void initAdapter() {
mAdapter = new MyAdapter(null);
mAdapter.isFirstOnly(false);
mAdapter.openLoadAnimation(BaseQuickAdapter.SCALEIN);
mRvMain.setLayoutManager(new StaggeredGridLayoutManager(3, LinearLayoutManager.VERTICAL));
mRvMain.setAdapter(mAdapter);
List<String> l = new ArrayList<>();
for (int i = 0; i < 80; i++) {
if (i % 2 == 0) {
l.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496372638951&di=be636f1362f06d68b902b8115cda13dc&imgtype=0&src=http%3A%2F%2Fd.5857.com%2Fxgs_150428%2Fdesk_005.jpg");
} else if (i % 3 == 0) {
l.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496373786557&di=bc8e94b8e82224a71ea7ea518d06e9ec&imgtype=0&src=http%3A%2F%2Fh7.86.cc%2Fwalls%2F20151020%2F1024x768_3fe2e5a70003597.jpg");
} else if (i % 4 == 0) {
l.add("http://pic.qiantucdn.com/58pic/15/36/00/73b58PICgvY_1024.jpg!/fw/780/watermark/url/L3dhdGVybWFyay12MS4zLnBuZw==/align/center");
} else {
l.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496373818671&di=d2fc21e4fbeec9792dfb53ff31c03093&imgtype=0&src=http%3A%2F%2Fimg17.3lian.com%2Fd%2Ffile%2F201701%2F23%2F10783ece0ff1eb32bf137ff9b7ba329e.jpg");
}
heightList.add(new Random().nextInt(300) + 200);
}
mAdapter.setNewData(l);
}
private class MyAdapter extends BaseQuickAdapter<String, BaseViewHolder> {
public MyAdapter(@Nullable List<String> data) {
super(R.layout.item_girls, data);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
ImageView imageView = (ImageView) helper.getView(R.id.iv);
//设置高度
int height = heightList.get(helper.getPosition());
//得到控件的高度
ViewGroup.LayoutParams layoutParams = (imageView).getLayoutParams();
//设置高度
layoutParams.height = height;
//使用Glide加载图片 placeholder参数为加载失败时显示的默认图片
Glide.with(BeautyPicturesActivity.this).load(item).placeholder(R.mipmap.ic_launcher).into(imageView);
}
}
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }//添加这行代码
}
}
<!--图片选择库相关aty-->
<activity
android:name="cn.kutils.boxing.impl.ui.BoxingActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/Boxing.AppTheme.NoActionBar">
</activity>
<activity
android:name="cn.kutils.boxing.impl.ui.BoxingViewActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/Boxing.AppTheme.NoActionBar">
</activity>
<activity
android:name="cn.kutils.boxing.impl.ui.BoxingBottomSheetActivity"
android:screenOrientation="portrait"
android:theme="@style/Boxing.AppTheme.NoActionBar"/>
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.file.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/boxing_file_provider"/>
</provider>
@Override
public void onCreate() {
super.onCreate();
IBoxingMediaLoader loader = new BoxingFrescoLoader(this);
BoxingMediaLoader.getInstance().init(loader);
BoxingCrop.getInstance().init(new BoxingUcrop());
}
- 打开图片选择器(多选不带裁剪功能)
//构造配置参数
BoxingConfig config = new BoxingConfig(BoxingConfig.Mode.MULTI_IMG); // Mode:Mode.SINGLE_IMG, Mode.MULTI_IMG, Mode.VIDEO
config.needCamera(R.mipmap.ic_launcher_round).needGif().withMaxCount(9); // 支持gif,相机,设置最大选图数
// .withMediaPlaceHolderRes(resInt) // 设置默认图片占位图,默认无
// .withAlbumPlaceHolderRes(resInt) // 设置默认相册占位图,默认无
// .withVideoDurationRes(resInt) // 视频模式下,时长的图标,默认无
// 初始化Boxing,构造Intent并启动
Boxing.of(config).withIntent(this, BoxingActivity.class).start(this, REQUESTCODE_1);
- 打开图片选择器(单选带裁剪功能)
String cachePath = BoxingFileHelper.getCacheDir(this);
if (TextUtils.isEmpty(cachePath)) {
Toast.makeText(getApplicationContext(), R.string.boxing_storage_deny, Toast.LENGTH_SHORT).show();
return;
}
Uri destUri = new Uri.Builder()
.scheme("file")
.appendPath(cachePath)
.appendPath(String.format(Locale.US, "%s.jpg", System.currentTimeMillis()))
.build();
BoxingConfig singleCropImgConfig = new BoxingConfig(BoxingConfig.Mode.SINGLE_IMG).withCropOption(new BoxingCropOption(destUri))
.withMediaPlaceHolderRes(R.mipmap.ic_launcher_round);
Boxing.of(singleCropImgConfig).withIntent(this, BoxingActivity.class).start(this, REQUESTCODE_3);
- 打开视频选择器
//启动视频选择
BoxingConfig videoConfig = new BoxingConfig(BoxingConfig.Mode.VIDEO).withVideoDurationRes(R.mipmap.ic_launcher_round);
Boxing.of(videoConfig).withIntent(this, BoxingActivity.class).start(this, REQUESTCODE_2);
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//
List<BaseMedia> medias = Boxing.getResult(data);
//注意判断null
}
- 定义方式1
<com.github.chrisbanes.photoview.PhotoView
android:id="@+id/pv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"/>
- 定义方式2
PhotoView photoView = new PhotoView(context);
photoView.setScaleType(ImageView.ScaleType.FIT_XY);
public class HackyProblematicViewGroup extends ProblematicViewGroup {
public HackyProblematicViewGroup(Context context) {
super(context);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
//uncomment if you really want to see these errors
//e.printStackTrace();
return false;
}
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mediaaty);
AppManager.getAppManager().addActivity(this);//将activity压入栈
@Override
protected void onDestroy() {
super.onDestroy();
AppManager.getAppManager().finishActivity(this);//将activity从栈取出
}
AppManager.getAppManager().AppExit(this);
<cn.kutils.view.CircleImageView
android:id="@+id/civ"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
app:border_color="@color/boxing_black1"
app:border_width="2dp"/>
- 在清单文件配置所需activity
<activity android:name="cn.kutils.permissionchecker.TedPermissionActivity"/>
- 开始检测权限
new TedPermission(getApplicationContext())
.setPermissionListener(mPermissionListener)
.setDeniedMessage("您有未授予的权限,可能导致部分功能闪退,请点击\"设置\"授权相关权限")
.setPermissions(
// Manifest.permission.VIBRATE,
// Manifest.permission.ACCESS_COARSE_LOCATION,
// Manifest.permission.ACCESS_FINE_LOCATION,
// Manifest.permission.ACCESS_WIFI_STATE,
// Manifest.permission.ACCESS_NETWORK_STATE,
// Manifest.permission.CHANGE_WIFI_STATE,
Manifest.permission.READ_PHONE_STATE,
// Manifest.permission.WRITE_EXTERNAL_STORAGE,
// Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS,
// Manifest.permission.READ_EXTERNAL_STORAGE,
// Manifest.permission.READ_LOGS,
// Manifest.permission.GET_TASKS,
// Manifest.permission.SET_DEBUG_APP,
// Manifest.permission.SYSTEM_ALERT_WINDOW,
// Manifest.permission.GET_ACCOUNTS,
// Manifest.permission.WRITE_SETTINGS,
// Manifest.permission.RECORD_AUDIO,
// Manifest.permission.WAKE_LOCK,
// Manifest.permission.MODIFY_AUDIO_SETTINGS,
// Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
Manifest.permission.CALL_PHONE)
.check();
//检测结果监听
private PermissionListener mPermissionListener = new PermissionListener() {
@Override
public void onPermissionGranted() {
KLog.d("全部权限已获取成功");
//业务逻辑代码
}
@Override
public void onPermissionDenied(ArrayList<String> deniedPermissions) {
//deniedPermissions 为用户未授予的权限
KLog.d("未授予的权限:" + deniedPermissions);
//业务逻辑
}
};
- 未授予的权限日志输出:
D/KLog: [ (MainActivity.java:191)#onPermissionDenied ] 未授予的权限:[android.permission.READ_PHONE_STATE, android.permission.CALL_PHONE]
<cn.kutils.view.progressbutton.AnimDownloadProgressButton
android:id="@+id/anim_btn"
android:layout_width="220dp"
android:layout_height="45dp"
android:focusable="true"
android:focusableInTouchMode="true"
app:progressbtn_backgroud_color="@color/colorAccent"
app:progressbtn_backgroud_second_color="@color/ccc"
app:progressbtn_text_size="25"/>
- 时间日期选择 四种选择模式,年月日时分,年月日,时分,月日时分
TimePickerView timePickerView = new TimePickerView(this, TimePickerView.Type.ALL);
timePickerView.setOnTimeSelectListener(new TimePickerView.OnTimeSelectListener() {
@Override
public void onTimeSelect(Date date) {
Toast.makeText(getApplicationContext(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date), Toast.LENGTH_SHORT).show();
}
});
timePickerView.show();//四种选择模式,年月日时分,年月日,时分,月日时分 ALL, YEAR_MONTH_DAY, HOURS_MINS, MONTH_DAY_HOUR_MIN , YEAR_MONTH
options1Items.add(new PriceBean("a"));
options1Items.add(new PriceBean("b"));
options1Items.add(new PriceBean("c"));
ArrayList<String> a_1
= new ArrayList<>();
a_1.add("a1");
a_1.add("a2");
a_1.add("a3");
options2Items.add(a_1);
ArrayList<String> b_1 = new ArrayList<>();
b_1.add("b1");
b_1.add("b2");
b_1.add("b3");
b_1.add("b4");
options2Items.add(b_1);
ArrayList<String> c_1 = new ArrayList<>();
c_1.add("c1");
c_1.add("c2");
c_1.add("c3");
c_1.add("c4");
c_1.add("c5");
c_1.add("c6");
c_1.add("c7");
options2Items.add(c_1);
pvOptions = new OptionsPickerView(this);
pvOptions.setPicker(options1Items, options2Items, true);
pvOptions.setTitle("XXXX");
pvOptions.setCyclic(false, false, false);
//设置默认选中的三级项目
//监听确定选择按钮
pvOptions.setSelectOptions(0, 0, 0);
pvOptions.setOnoptionsSelectListener(new OptionsPickerView.OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3) {
Toast.makeText(getApplicationContext(), options1Items.get(options1).getPickerViewText(), Toast.LENGTH_SHORT).show();
}
});
pvOptions.show();
//设置沉浸式状态栏
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(R.color.boxing_colorAccent);//通知栏所需颜色
- 在application初始化图片加载器
NineGridView.setImageLoader(new NineGridView.ImageLoader() {
@Override
public void onDisplayImage(Context context, ImageView imageView, String url) {
Glide.with(context).load(url).into(imageView);
}
@Override
public Bitmap getCacheImage(String url) {
return null;
}
});
- 定义
<cn.kutils.view.nineimages.NineGridView
android:id="@+id/ng"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- 填充数据
List<ImageInfo> list = new ArrayList<>();
for (int i = 0; i < medias.size(); i++) {
list.add(new ImageInfo(medias.get(i).getPath(),medias.get(i).getPath()));
}
mNg.setAdapter(new NineGridViewClickAdapter(NineImagesAty.this, list));
- 一行代码完成压缩
Luban.get(this).load(files).putGear(Luban.FIRST_GEAR).launch(new OnMultiCompressListener() {//FIRST_GEAR CUSTOM_GEAR THIRD_GEAR
@Override
public void onStart() {
append("开始压缩,压缩时间会根据图片大小和数量相应增加");
}
@Override
public void onSuccess(List<File> fileList) {
ArrayList<String> c = new ArrayList<>();
List<ImageInfo> list = new ArrayList<>();
for (int i = 0; i < fileList.size(); i++) {
c.add(String.valueOf(FileSizeUtil.getFileOrFilesSize(fileList.get(i).getPath(), SIZETYPE_MB))+ "Mb");
list.add(new ImageInfo(fileList.get(i).getPath(), fileList.get(i).getPath()));
}
append("张图片压缩完成,大小依次:" + c + "Mb");
append("设置到九图预览控件");
mNg.setAdapter(new NineGridViewClickAdapter(NineImagesAty.this, list));
mNg.setSingleImageSize(250);
}
@Override
public void onError(Throwable e) {
append("压缩出错," + e.toString());
}
});
- Luban压缩详细文档
- 效果图
- 修改KUtils的build.gradle文件里代码
resValue "string", "tray__authority", "cn.kutils.sample" //将cn.kutils.sample更换为自己软件的包名
- 初始化
AppPreferences appPreferences = new AppPreferences(getApplicationContext());
- 写入
appPreferences.put("key", 999);//写入
- 读取
String str = appPreferences.getString("key", "");//读取
- 初始化 全局只需要初始化依次
DialogUIUtils.init(this);
- 使用 详细请查看sample
DialogUIUtils.show...