开发过程中遇到的一些坑(汇总)

前端时间新开发一个项目,其中真是遇到了不少坑和疑难杂症,趁还没忘记,记录下来与各位分享。

1:fragment几种不同用法。

2:使用用onsaveInstence()

3:广播的多种方法和注销

4:横竖屏禁用后,退出复原

5:数据库外键建立

6:stringfrom中%d占位符

7:中英文切换支持国际化

8:运行时权限

9:图片压缩

10:内存优化

一,首先来说ftagment。


开发过程中遇到的一些坑(汇总)_第1张图片
图片发自App

onAttach()-oncreate()-oncreateview()
-onviewcreate()-onactivitycreate()-onstar()-onresume()-onpause()-onstop()-ondestoryview()-ondestory()-ondeatch()
那么我们在创建fragment的时候也有两种方式,其一:如果我们用fragmentManager.replace()的话,这个时候如果是从aFragment跳转到bFragment的话,那么aFragment就经历onpause-onstop-ondestoryview-ondestory,每次去执行replace都会先销毁旧实例对象。这里建议如果旧fragment无需再次使用可以用replace().大多数情况都是在tab上来回切换,所以推荐用第二种方法:getFragmentManager().beginTransaction().add(R.id.content,f1).add(R.id.content,f2).show(f1).hide(f2).commit();这样使用hide和show时不会重新执行生命周期的方法,这里会遇到两个问题,一个是怎么去判断显示f1时候刷新界面?我们可以在点击tab时候设置f1.setUservisibilitehite(true);然后在f1里面重写onUservisibilitehite()方法。第二个常见问题,如果我们点击多次然后切换到其他app再次返回时候会出现fragment重叠现象,因为切换时候调用onsaveInstanceState(),已经保存过fragment的实例了,这个时候我们可以重写父activity的onsaveInstanceState()注销掉super()即可。
二:使用onsaveInstanceState()保存数据。
在做图片选择时候如果选择时候切换了横竖屏那么,这个activity将直接挂掉,大多开发者都喜欢自定义图片选择应该就是为了避免这个问题了,当时处理这个问题是先判断横竖屏的状态值,然后禁用系统横屏,结束时候再次设置系统原始横竖屏状态。
//判断横竖屏
public boolean isScreenChange() {

Configuration mConfiguration = this.getResources().getConfiguration(); //获取设置的配置信息
int ori = mConfiguration.orientation ; //获取屏幕方向

if(ori == mConfiguration.ORIENTATION_LANDSCAPE){

//横屏
return true;
}else if(ori == mConfiguration.ORIENTATION_PORTRAIT){

//竖屏
return false;
}
return false;
}
//设置系统横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
在相册选择完毕后判断之前横竖屏的状态后,重新设置横竖屏。
//onSaveInstanceState中设置值
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
outState.putInt("currentposition", videoView.getCurrentPosition());
Log.v("tag", "onSaveInstanceState");
super.onSaveInstanceState(outState);
}
然后在oncreate的bundle中取对应的值就好。
三:广播的多种方法。前段时间和同事们讨论一个问题,当两个完全不依赖的activity做数据交互时候,可以用接口来实现吗?这里不说全局和startActivityforresult,单从接口来说是实现不了,因为接收数据的一方需要拿到发起数据的实例对象才行,用不可以去new activity吧,所以用了一个广播来实现传递数据,这里就不说怎么使用广播了,在onReceive()中取值,在activity中sendBrodcast(),这里很多人都使用完后就直接了事,其实如果不在destory的时候对广播注销的话很容易引起oom,所以在编码时候一定要规范化.

开发过程中遇到的一些坑(汇总)_第2张图片
图片发自App

这种情况不会出现问题。
四:横竖屏问题上面已经讲到了,如果可以的话就自定义相册。
五:数据库外键的关联关系
开发过程中遇到的一些坑(汇总)_第3张图片
图片发自App

B表是主表,A表是子表,uuid是外键,关系并不复杂,主要是写法上容易出错,A表常规写法,B表:create table 表名(
列名1 参数,
列长2 参数,
foreign key(列名) references 目标表名(目标列名)
);
后续贴完整验证代码。
补充:

Paste_Image.png

六:stringFormat使用。
很多时候我们需要在string.xml中用到只修改部分数据的情况,比如string.xml中"一共24条",这个string不应该每次去settext的时候都去做"一共"+getcount()+"条"。这样不可取,我们最常使用的占位符是%s(字符串),%d(整型)。那么直接可以在string.xml中用"一共%d条",代码里面textView.setText(String.format(R.string.xx,24));
七:中英文切换。很多app都是给外国人使用的,所以为了支持国际化,应该在原有res下建立values-en或者values-zh文件夹存放string.
//对应切换语言的方法
一)切换为英文的代码:
Locale.setDefault(Locale.ENGLISH);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = Locale.ENGLISH;
getBaseContext().getResources().updateConfiguration(config,getBaseContext().getResources().getDisplayMetrics());
//切换后重启界面
Intent intent = new Intent();
intent.setClass(this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
这样就可以了。
八:运行时权限问题。android6.0开始就新增了运行时权限管理,也就是从23开始就需要在代码中申请权限了,如果你的targetsdk设置的是22,那么在6.0上也不会给你动态申请权限,所以在做到了5.1已下和6.0以上兼容后,选择targetsdk建议23或者更高。下面就来说说遇到的坑。 这里详细讲了录音和拍照在23以上我们可以直接先用activity.checkselfpermission检测是否被授权,如果是packager.permission_denied也需要申请权限。第二步是申请权限activity.requestpermission最后在onrequestpremissionresult的回调中判断是否申请成功。大部分可以直接百度来用,这里说下5.1以下的机型,判断相机是否允许拍照,直接用cramer.open去尝试开启,如果异常也禁用状态,给出dialog提示被禁止。判断是否允许录音,一般我们将单纯的录制比较容量少的用audiorecorder,如果是用录制声音和视屏的话,就用mediarecorder.当audiorecorder.Recording通过扑捉异常来判断是否开启权限,mediarrecorder通过setoutfile文件是否存在来判断是否开启权限。这里是分为了两步去实现,首先直接开启mediarecorder.start方法,如果直接弹出提示框证明第一次调用,第二步判断结束录音后文件地址是否存在,不存在,则设置录音未开启状态。相对6.0动态申请来说,5.1以下判断权限更加复杂。
九:图片压缩,handler释放。当相册中选择过发图片时候,处理生成bitmap往往会内存溢出,这里说下三种图片压缩方式,在onactivityforresult中调用。
等比压缩:
/**
* @param path 图片路径
* @param targetSize 缩放后期待的长边(图片长和宽大的那一个边)的长度
* @param targetW 期待的缩放后宽度
* @param targetH 期待的缩放后高度
* @return
/
public static Bitmap equalRatioScale(String path,int targetW,int targetH){
// 获取option
BitmapFactory.Options options = new BitmapFactory.Options();
// inJustDecodeBounds设置为true,这样使用该option decode出来的Bitmap是null,
// 只是把长宽存放到option中
options.inJustDecodeBounds = true;
// 此时bitmap为null
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
int inSampleSize = 1; // 1是不缩放
// 计算宽高缩放比例
int inSampleSizeW = options.outWidth / targetW;
int inSampleSizeH = options.outHeight / targetH;
// 最终取大的那个为缩放比例,这样才能适配,例如宽缩放3倍才能适配屏幕,而
// 高不缩放就可以,那样的话如果按高缩放,宽在屏幕内就显示不下了
if (inSampleSizeW > inSampleSizeH) {
inSampleSize = inSampleSizeW;
}else {
inSampleSize = inSampleSizeH;
}
// 设置缩放比例
options.inSampleSize = inSampleSize;
// 一定要记得将inJustDecodeBounds设为false,否则Bitmap为null
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
通过matrix进行缩放。
/
*
* @param path 原图路径
* @param offsetX 截取开始点在X轴偏移量
* @param offsetY 截取开始点在Y轴偏移量
* @param targetW 截取多宽(像素)
* @param targetH 截取多高(像素)
* @return
/
public static Bitmap matrixScale(String path,int offsetX,int offsetY,int targetW,int targetH){
// 构建原始位图
Bitmap bitmap = BitmapFactory.decodeFile(path);
// 获取原始宽高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 计算宽高缩放比例,targetW,targetH即期待缩放完成后位图的宽高
float scaleW = (float)targetW / width;
float scaleH = (float)targetH / height;
// 将缩放比例放进矩阵
Matrix matrix = new Matrix();
matrix.postScale(scaleW, scaleH);
// 这个方法作用非常多,详细解释一下各个参数的意义!
// bitmap:原始位图
// 第二到第五个参数,即截取原图哪一部分构建新位图,
// offsetX和offsetY代表在X轴和Y轴上的像素偏移量,即从哪个位置开始截取
// width和height代表截取多少个像素,但是要注意,offsetX+width应该小于等于原图的宽度
// offsetY+height小于等于原图高度,要不然会报错,因为截到原图外面去了
// 像下面这样填写,就代表截取整个原图,
// Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
// 如果填写100,100,200,200,就代表
// 从原图左上角往右和下各偏移100像素,然后往后和往下各截取200构建新位图
// matrix:缩放矩阵
// 最后一个参数表示如果矩阵里面还存放了过滤条件,是否按条件过滤(如果matrix里面只放了平移数据),最后一个参数设置成什么都不会生效
bitmap = Bitmap.createBitmap(bitmap, offsetX, offsetY, width, height, matrix, false);
return bitmap;
}
无损压缩(质量压缩)这种情况只能改变file的size不能改变bitmap大小,直接用无损压缩同样会导致内存溢出。
/
*
* @param path 图片路径
* @param quality 质量 0-100,100表示原图
* @return
*/
public static Bitmap losslessScale(String path,int quality){
Bitmap bitmap = BitmapFactory.decodeFile(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.JPEG, quality, baos);
Log.e("哈哈","原始大小:" + baos.toByteArray().length);
// 因为质量压缩不是可以无限缩小的,所以一张高质量的图片,再怎么压缩,
// 最终size可能还是大于你指定的size,造成异常
// 所以不建议循环压缩,而是指定quality,进行一次压缩就可以了
// while (baos.toByteArray().length / 1024 > maxSize) {
// quality -= 10;
// baos.reset();
// bitmap.compress(CompressFormat.JPEG, quality, baos);
// Log.e("哈哈","过程中大小为:"
// + baos.toByteArray().length);
// }
bitmap.compress(CompressFormat.JPEG, quality, baos);
Log.e("哈哈","最终大小" + baos.toByteArray().length);
Bitmap compressedBitmap = BitmapFactory.decodeByteArray(
baos.toByteArray(), 0, baos.toByteArray().length);
return compressedBitmap;
}
一般导致内存溢出时候大部分是bitmap叠加没有释放导致的,一般可以在activity中的ondestory方法中判断如果bitmap≠null,则bitmap.recycle();bitmap=null;常见的溢出还有handler使用不当导致,activity中被销毁,可是handler还持有activity对象导致activity一直得不到释放,建议创建handler时候为静态内部类,
public class MainActivity extends Activity {

static class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {  }
}

}
或者对当前activity采用弱引用也可以避免内存溢出,不然也可以在ondestory中处理handler.removeCallbacksAndMessages(null);来释放对象。另外内存优化还有listview中的adater使用viewHorder和判断convertView等等一些。

感谢与我一起发现问题处理问题的同事们##

你可能感兴趣的:(开发过程中遇到的一些坑(汇总))