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

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

1:fragment几种不同用法。

2:使用用onsaveInstence()

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

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

5:数据库外键建立

6:stringfrom中%d占位符

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

8:运行时权限

9:图片压缩

10:内存优化

一,首先来说ftagment。


图片发自简书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,所以在编码时候一定要规范化.

图片发自简书App

这种情况不会出现问题。
四:横竖屏问题上面已经讲到了,如果可以的话就自定义相册。
五:数据库外键的关联关系
图片发自简书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等等一些。

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容

  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,377评论 0 17
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,881评论 25 707
  • 线程和进程的区别是啥 详见 http://www.jianshu.com/p/04c3706521b5 线程切换如...
    MrWang915阅读 1,150评论 0 2
  • 1.什么是Activity?问的不太多,说点有深度的 四大组件之一,一般的,一个用户交互界面对应一个activit...
    JoonyLee阅读 5,729评论 2 51
  • 开始慢慢觉得,人生中遇到一些人和事都是缘分, 我想象不到如果我不学这个专业,不在这个寝室会是怎么样的, 所以开始变...
    小琳仔呀阅读 105评论 0 0