一、关于SwipeRefreshLayout的坑
众所周知,SwipRefreshLayout可以手动停止刷新动画,只需要调用SwipeRefreshLayout.setRefreshing(false).可是当我们需要手动开启动画时候,SwipeRefreshLayout.setRefreshing(true)将不会生效。其真正的手动开启动画需要调用
SwipeRefreshLayout.post(new Runnable(){
Public void run(){
SwipeRefreshLayout.setRefreshing(true)
}
});
这样我们就可以实现手动调用动画了。
二、Rtrofit2使用详解
了解Retrofit2中的网络访问常用注解接口,其实这些接口都是在retrofit2.http这个包下面的
1、@GET GET网络请求方式
2、@POST POST网络请求方式
3、@Headers()头信息参数
4、@Path()路径参数,替换url地址中{ }所括的部分
5、@Query()查询参数,将在url地址中追加类似“page=1”的字符串,形成提交给服务端的请求参数
6、@QueryMap查询参数集合,将在url地址中追加类似
“type=text&username=abc&password=123”的字符串
7、@FormUrlEncoded对表单域中填写的内容进行编码处理,避免乱码
8、@Field()指定form表单域中每个空间的额name以及相应的数值
9、@FieldMap表单域集合
10、@Multipart Post提交分块请求,如果上传文件,必须指定Multipart
11、@Body Post提交分块请求
//获取Retrofit对象,设置地址
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://localhost")
.client(OK_HTTP_CLIENT)//设置client 我们可以放入一个okhttpClient,便于我们设置超时时间
.build();
//创建RequstService
创建你的RequstService接口类
@GET
//定义返回的方法,返回的响应体使用了ResponseBody
Call getString(@Url String url);
@FormUrlEncoded
@POST
Call post(@Url String url, @FieldMap Map params);(post请求中用到了@FieldMap,所以必须在方法前加上@FormUrlEncoded否则将会报错)
通过Rtrofit对象创建 retrofit.create(你的RequstService类);
//发起请求如果是post请求需要传入一个map
Call call = requestServices.post(url,pamars);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()){
try {
Log.i("cc",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.i("cc","访问失败");
}
});
注意:关于retrofit2中baseurl的问题 如果设置了baseurl则可以在请求时传入接口进行拼接即可。
组合一://成功
baseUrl("http://api.m.mtime.cn/")
@GET("onebox/basketball/nba?key=98020a1e920819b8ff4fcfbdd7747f8c")
Observable getNBA2();
组合二://成功
baseUrl("http://api.m.mtime.cn/")
@GET("onebox/basketball/nba?key=98020a1e920819b8ff4fcfbdd7747f8c")
Observable getNBA2();
三、Parcelable和Serializable的使用
Parcel就是一个存放读取数据的容器, android系统中的binder进程间通信(IPC)就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel来交互的。在Java空间和C++都实现了Parcel,由于它在C/C++中,直接使用了内存来读取数据,因此,它更有效率。
最重要的是其可以实现通过intent进行传递。
在使用时把需要传递的类implement Parcelable即可,完成其必要方法。
Serializable也是一个可传递的容器,它和Parcelable一样可以通过Bundle来进行传递,而且其实现更为简单,它就是一个java类,只需要直接implement Serializable即可,直接通过bundle.putSerializable()方法进行传递即可。
四、SQLiteDataBase
通过SQLiteDataBase来打开外部数据库。首先把数据库加载到本地,通过输入流实现。
然后通过SQLiteDataBase来打开数据库
Db = SQLiteDataBase.openOrCreateDatabase(dbfile,null);
查找
Cursor cursor = db.query(表名,null,null,null,null,null,null);//返回游标
查找结束后关闭游标。
五、关于activity及fragment生命周期的监听
在Application中可以监听所有activity的生命周期。在Activity中可以监听其所包含的fragment的生命周期。
activity生命周期的监听需要在application中调用registerActivityLifeecycleCallbacks方法
fragement生命周期的监听需要在其所属的activity中通过fragmentManager来调用registerFragementLifeecycleCallbacks方法
/**
* 在activity内监听fragment的生命周期
*/
public void setRegisterFragmentLifecycleCallbacks()
{
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentResumed(FragmentManager fm, Fragment f) {
super.onFragmentResumed(fm, f);
}
@Override
public void onFragmentPaused(FragmentManager fm, Fragment f) {
super.onFragmentPaused(fm, f);
}
},false);
}
六、关于Android File.delete删除文件不够彻底的问题
在调用file.delete方法前我们必须发送一条广播告诉手机我们准备删除该文件,以达到彻底删除文件。
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
Intent.setData(uri);
Context.sendBroadcast(intent);
file.delete();
七、关于安卓7.0不允许使用Intent直接打开文件,必须使用FileProvider
使用FileProvider的方法
1、在mainfest中注册
2、在res文件下创建xml文件目录下创建新文件,内容如下:
对应Context.getFilesDir();
对应getCacheDir();
对应Environment.getExternalStorageDirectory();
对应Context.getExternalCacheDir();
3. Uri的创建
Uri uri = getUriForFile(content,authorities,file);
4. 重点为URI临时授权
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
八、android6.0以后某些敏感权限需要动态申请
/**
* 请求授权
*/
private void requestPermission(){
if (Build.VERSION.SDK_INT >= 23) {
int checkCallPhonePermission = ContextCompat.checkSelfPermission
(this, Manifest.permission.CALL_PHONE);
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
//在String[]中传入需要申请的权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
else{
//sendHomework();
//已经拥有了权限
}
}
else {
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//sendHomework();
//获取权限成功后的处理
}
else {
//showToast("fail");
//获取权限失败的处理
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
需要动态申请的权限
九、关于TransactionTooLargeException异常
该异常中文意思传输数据过大异常,造成该异常的原因应该是通过Bundle进行数据传输时,数据过大造成的,Bundle进行数据传输严格限制共享区域缓存大小只有1M。
从以上异常的描述,可以总结出现该异常的原因:
解决办法
十、Toolbar详解
为NavigationIcon设置点击事件有两种不同的方法
(1)通过onOptionsItemSelected设置点击事件
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
(2)通过OnClickListener设置点击事件
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
如果希望Menu里面的按钮常驻Toolbar还需要在Menu的xml文件的item添加下面这条属性
app:showAsAction="always"
注意:setNavigationIcon需要放在 setSupportActionBar之后才会生效
菜单直接在toolbar中创建子组件即可。
优点:在这样的架构设计下,ToolBar直接成了Layout中可以控制的东西,相对于过去的actionbar来说,设计与可操控性大幅提升。
十一、隐式意图
隐式意图必须判断是否有应用可以打开该意图。
Intent openAlbumIntent = new Intent();
openAlbumIntent.setType("image/*");
openAlbumIntent.setAction(Intent.ACTION_PICK);
openAlbumIntent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
if (getPackageManager().resolveActivity(openAlbumIntent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
startActivityForResult(openAlbumIntent, CHOOSE_PICTRUE);
} else {
showToast("打开图库失败");
}
十二、动态监听wrap_content的布局宽高
mLl.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
//通过布局上下左右运算后可获得布局宽高
}
});
十三、Onkey事件无法响应
给布局添加OnkeyListener时,Onkey事件没有响应,因为可能其事件被父类拦截了所以我们需要在代码中加上一句获取焦点且响应OnKey事件的代码即可。
mLinearLayout.setFocusableInTouchMode(true);//设置获取焦点且响应OnKey事件
十四、关于Android File.delete删除文件不够彻底的问题
我们必须发送一条广播告诉手机我们已经删除了文件,以达到彻底删除文件。
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);
file.delete();
十五、在OnCreate中View.getHeight()无法获取宽高
我们可以通过一个Runnable来实现异步获取布局宽高
mHiddenLayout.post(new Runnable() {
@Override
public void run() {
mHiddenLayout.setVisibility(View.GONE);
mHiddenViewMeasureHeight = mHiddenLayout.getHeight();
isInitComplet = true;
}
});
十六、通过颜色过滤器或者tint来修改图标颜色
ColorFilter颜色过滤器
/**
* 修改图标的颜色
* @param icon 要修改的图标
*/
public void changeIconColor(ImageView icon,int color){
if(icon!=null){
float[] colorMatrix = new float[]{
0, 0, 0, 0, Color.red(color),
0, 0, 0, 0, Color.green(color),
0, 0, 0, 0, Color.blue(color),
0, 0, 0, (float) Color.alpha(color) / 255, 0
};
icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
}
}
Tint和TintMode修改图标颜色
十七、截断TextView,设置不同颜色
private SpannableString formatSpannableString(Context context, String title, String content) {
if (content == null) {
content = "";
}
SpannableString result = new SpannableString(String.format(title, content));
ForegroundColorSpan contentSpan = new ForegroundColorSpan(
ContextCompat.getColor(context, R.color.font_black_primary));
result.setSpan(contentSpan,
result.length() - content.length(),
result.length(),
Spanned.SPAN_EXCLUSIVE_INCLUSIVE);
return result;
}