解bug方法

android开发中遇到的BUG总结集锦

2018-10-12  本文已影响331人  孙科技

java.lang.OutOfMemoryError

该异常表示未能成功分配字节内存,通常是因为内存不足导致的内存溢出

OOM就是内存溢出,即Out of Memory。也就是说内存占有量超过了VM所分配的最大。怎么解决OOM,通常OOM都发生在需要用到大量内存的情况下(创建或解析Bitmap,分配特大的数组等),这里列举常见避免OOM的几个注意点:

  1. 适当调整图像大小。
  2. 采用合适的缓存策略。
  3. 采用低内存占用量的编码方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省内存。
  4. 及时回收Bitmap。
  5. 不要在循环中创建过多的本地变量。
  6. 自定义对内存分配大小。
  7. 特殊情况可在mainfests的Application中增加 android:largeHeap="true"属性,比如临时创建多个小图片(地图marker)

WebP图片格式问题

虽然Android官方描述是在4.0之后开始支持WebP格式,但在4.0到4.2.1不支持有透明度设置和无损压缩的WebP格式图片。所以如果简单的判断,图片如果是WebP格式,且是4.0以上的系统,就通过BitmapFactory来解析,
很可能会出现有些图片能解析,有些又不能解析的情况。此外,还有一些特殊机型,例如NokiaXL虽然是Android4.1的系统,但并不支持WebP编解码。因此,最好是从4.2系统开始用BitmapFactory来解析WebP格式的图片。

解析大图时的OOM问题

Android为每个应用分配的堆内存空间是有限的,如果应用请求的内存超过了限制,就会导致OOM。根据手机内存大小的不同,一般应用能够使用的堆内存在几十兆到两三百兆之间。然后应用在读取图片文件时非常消耗内存的,
一张手机相机拍出的照片都有3M左右,如果每张图都直接读取,即使不造成OOM,也会导致频繁GC。还有些超大图一张就有几个G,如果直接读取肯定会导致OOM。为了避免读取大图时造成的OOM问题,
并减少内存消耗,一般在读取图片时都需要根据图片尺寸来取样。也就是设置BitmapFactory.Options的inSampleSize属性。示例代码如下。

`Options options = new BitmapFactory.Options();
//设置inJustDecodeBounds为true表示只获取大小,不生成Btimap
options.inJustDecodeBounds = true;
//解析图片大小
InputStream stream = getContentResolver().openInputStream(uri);
BitmapFactory.decodeStream(stream, null, options);
stream.close();
int width = options.outWidth;
int height = options.outHeight;
int ratio = 0;
//如果宽度大于高度,交换宽度和高度
if (width > height) {
    int temp = width;
    width = height;
    height = temp;
}
//计算取样比例
it sampleRatio = Math.max(width/900, height/1600);
//定义图片解码选项
Options options = new Options();
options.inSampleSize = sampleRatio;

//读取图片,并将图片缩放到指定的目标大小
InputStream stream = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
stream.close();
FileOutputStream openFileOutput = null;
    boolean success = true;
    try {
        // 使用openFileOutput()函数,直接在/data/data/包名/files/目录下创建文件
        openFileOutput = openFileOutput("testmemeryio.html", Context.MODE_PRIVATE); // 私有模式写文件
        openFileOutput.write(text.getBytes("utf-8"));
        openFileOutput.flush();
    } catch (IOException e) {
        success = false;
        e.printStackTrace();
    } finally {
        if (openFileOutput != null) {
            try {
                openFileOutput.close();
                openFileOutput = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    Toast.makeText(context, success == true ? "写入内存文件成功" : "写入内存文件失败", 0).show();

启动调试时应用安装失败,提示"INSTALL_FAILED_UID_CHANGED"

出现此问题的原因大多是APK卸载不彻底造成冲突。

解决方案:

分别进入 /data,/system/app,/data/data 目录把相应的APP数据全部删除。
提示:手机需要Root权限,不然进入 /data/ 目录之后看不见数据(推荐使用RE文件管理器)

启动调试时应用安装失败,提示"INSTALL_FAILED_INVALID_APK"

Android 4.1的手机上做一个恢复程序功能时发现,在adb shell里用pm install -r /data/local/tmp/temp.apk时报错

错误原因:

发现这个文件的读写属性是rw-------, 属主是root,因为是用root用户拷贝过来的。将读写属性改成rw-rw-rw-后,
再用pm install -r /data/local/tmp/temp.apk安装就成功了,推测pm安装时会用到别的身份,而别的身份又没有读的权限,所以导致失败。

解决方案:

因此在调用pm安装前加了一个chmod 666 /data/local/tmp/temp.apk命令, 问题解决!

java.lang.IllegalStateException:Cannot forward a response that is already committed IllegalStateException:response already commited

错误原因:

该异常表示,当前对客户端的响应已经结束,不能在响应已经结束(或说消亡)后再向
客户端(实际上是缓冲区)输出任何内容。

具体分析:

首先解释下flush(),我们知道在使用读写流的时候数据先被读入内存这个缓冲区中,
然后再写入文件,但是当数据读完时不代表数据已经写入文件完毕,因为可能还有
一部分仍未写入文件而留在内存中,这时调用flush()方法就会把缓冲区的数据强行
清空输出,因此flush()的作用就是保证缓存清空输出。

Unable to open log device ‘/dev/log/main’: No such file or directory

解决方案:

1、在拨号界面输入:##2846579## 进入测试菜单界面。

2、Project Menu–后台设置–LOG设置

3、LOG开关–LOG打开 LOG级别设置–VERBOSE

4、Dump&Log– 全部选中

5、重启手机

Error:Unknown host 'proxy.tencent.com'. You may need to adjust the proxy settings in Gradle.

解决方案:

gradle->distributionBase=GRADLE_USER_HOME

distributionPath=wrapper/dists

zipStoreBase=GRADLE_USER_HOME

zipStorePath=wrapper/dists

distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip->中的distributionUrl修改为已下载完成的路径

build.gradle->dependencies {

classpath'com.android.tools.build:gradle:2.3.2'

// NOTE: Do not place your application dependencies here; they belong

// in the individual module build.gradle files

}->classpath路径修改为正确的配置

java.lang.ClassNotFoundException

Android studio 引入第三方包运行项目时出现java.lang.ClassNotFoundException错误,包冲突多次引入

解决方案:

新建application 集成MultiDexApplication

`public class MultiDexApplication extends Application {

 @Override

protected void attachBaseContext(Context base) {

super.attachBaseContext(base);

    MultiDex.install(this);

}

}`

build.gradle配置

defaultConfig {

multiDexEnabled true

}

lintOptions {

    checkReleaseBuilds false

    abortOnError false

}

dexOptions {

    javaMaxHeapSize "4g"

}

packagingOptions {

    exclude 'META-INF/rxjava.properties'

    exclude 'META-INF/rxjava'

}

AS Could not download javaparser-core.jar No cached version available for offline mode

解决方案:

setting-Build,Execution,Deployment-Gradle把Offline work 前的勾去掉

java.net.ProtocolException: unexpected end of stream

一种“unexpected end of stream”异常

此异常在使用OkHttp下载文件时出现

特点1:必现;

特点2:不是一开始出现,多出现在下载结尾处,并且每一次位置相同

原因:http响应报文中,header中含有“content-length”,并且它的值比实际文件大,哪怕几个byte也不行,就会报上面的错误,所以请服务器修正这个错误吧;

代码如下:

longread = source.read(sink, Math.min(bytesRemaining, byteCount));
if(read == -1) {
  // The server didn't supply the promised content length.thrownewProtocolException("unexpected end of stream");
  endOfInput(false);
}

当然unexpected end of stream还有其他产生的原因,这里只是其中之一;

注:同样的链接,用浏览器下载也不能下载完成,所以请保证content-length与实际大小保持一致;

解决方案:

1、java.net.ProtocolException: unexpected end of stream 的出现,实现了一个RequestBody的上传包装进度的类。出现以上的问题。

搞了半天也不知啥原因,后来去掉了okhttp设置的logger拦截器,就可以了。无语。上传文件不能使用自带logger打印网络请求,打印网络请求不能上传文件。

2、if (bufferedSink == null) {

//包装

bufferedSink = Okio.buffer(sink(sink));

}

你把上面的if语句去掉就可以正常了

但是很多网上都是这样写的,目前不知道去掉有什么影响

onFailure:javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Couldnotvalidatecertificate:null

1、因为请求的接口是https,开始以为是证书的原因,但是在模拟器和别的手机上没有发现这个问题,后来Google搜了一下,发现是魅蓝note手机本地时间的原因

解决方案:

联网校验手机本地时间即可

2、OKhttp3 添加安全认证

/**

* okhttp HTTPS安全认证

* Okhttp3 Could not validate certificate: null

*

* @return

*/

private static SSLSocketFactorygetSSLSocketFactory() {

final TrustManager[] trustAllCerts =new TrustManager[]{

new X509TrustManager() {

@Override

public void checkClientTrusted(X509Certificate[] x509Certificates, String s)

throws CertificateException {

}

@Override

public void checkServerTrusted(X509Certificate[] x509Certificates, String s)

throws CertificateException {

}

@Override

public X509Certificate[]getAcceptedIssuers() {

return new X509Certificate[0];

}

}

};

SSLContext sslContext =null;

try {

sslContext = SSLContext.getInstance("SSL");

sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

}catch (KeyManagementException e) {

e.printStackTrace();

}catch (NoSuchAlgorithmException e) {

e.printStackTrace();

}

// Create an ssl socket factory with our all-trusting manager

final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

return sslSocketFactory;

}

Execution failed for task ':app:prepareDebugAndroidTestDependencies' Dependency Error

caused by:

Conflict between the versions of the test-app and the main app of the libary: 'com.android.support:support-annotations'

soultion:

i change this

configurations.all{resolutionStrategy.force'com.google.code.findbugs:jsr305:3.0.1'}

to this:

configurations.all{resolutionStrategy{force'com.android.support:support-annotations:24.2.1'}}

No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android##

其实解决方法很简单,就是修改build.gradle版本,改为3.1以上版本即可

dependencies {
classpath 'com.android.tools.build:gradle:3.2.0'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
 }

Error:All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com##

解决方案:

'在主app的build.gradle里面的
defaultConfig {
targetSdkVersion:***
minSdkVersion :***
versionCode:***
versionName :***
//版本名后面添加一句话,意思就是flavor dimension 它的维度就是该版本号,这样维度就是都是统一的了
flavorDimensions "versionCode"
}'

Android studio-3.x升级问题,无法引用library里面引用的第三方库##

 implementation 改为api

AndroidP 高版本联网失败报错解决java.net.UnknownServiceException: CLEARTEXT communication ** not permitted by##

(1)APP改用https请求

(2)targetSdkVersion 降到27以下

(3)更改网络安全配置

前面两个方法容易理解和实现,具体说说第三种方法,更改网络安全配置。

1.在res文件夹下创建一个xml文件夹,然后创建一个network_security_config.xml文件,文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

2.接着,在AndroidManifest.xml文件下的application标签增加以下属性:

<application
...
 android:networkSecurityConfig="@xml/network_security_config"
...
    />

完成,这个时候App就可以访问网络了。

上一篇下一篇

猜你喜欢

热点阅读