android开发中遇到的问题汇总【十】

294. java中 volatile static结合使用 static 静态 volatile 不稳定的 JAVA 里static 和volatile的区别

变量放在主存区上,使用该变量的每个线程,都将从主存区拷贝一份到自己的工作区上进行操作。

volatile, 声明这个字段易变(可能被多个线程使用),Java内存模型负责各个线程的工作区与主存区的该字段的值保持同步,即一致性。

static, 声明这个字段是静态的(可能被多个实例共享),在主存区上该类的所有实例的该字段为同一个变量,即唯一性。

volatile, 声明变量值的一致性;static,声明变量的唯一性。

此外,volatile同步机制不同于synchronized, 前者是内存同步,后者不仅包含内存同步(一致性),且保证线程互斥(互斥性)。
static 只是声明变量在主存上的唯一性,不能保证工作区与主存区变量值的一致性;除非变量的值是不可变的,即再加上final的修饰符,否则static声明的变量,不是线程安全的。

1) If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. 

2) A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable。

295. ids的作用和使用场景

作用:通过ids.xml中事先定义好id,在使用时候不用重新生成对应的id,提高性能和可维护性。优化编译效率。统一管理资源Id。 eg:如果没有ids.xml中定义。在layout文件中声明方式如下@+id/xxx。 如果定义过,使用方式如下@id/xxx 即不用加"+"号。 使用场景,对于需要同意管理资源id的场景,比如框架id 参考android项目中values中ids.xml的作用

297. Android, ListView IllegalStateException: “The content of the adapter has changed but ListView did not receive a notification”

http://stackoverflow.com/questions/3132021/android-listview-illegalstateexception-the-content-of-the-adapter-has-changed

299. Error:Could not read cache value from ‘xxx/gradle/daemon/2.10/registry.bin’.

根据路径找到registry.bin,删除,重启androidstudio即可。

300. Android: AlertDialog causes a memory leak

in the leaked activity’s onDestroy(), set the AlertDialog’s ListView’s onItemClickListener() to null, which will release the reference to the listener an make whatever memory allocated within that listener to be eligible for GC. This way you won’t get OOM. It’s just a workaround and the real solution should actually be incorporated in the ListView.

Here’s a sample code for your onDestroy():

@Override 
protected void onDestroy() { 
    super.onDestroy(); 
    if(leakedDialog != null) { 
            ListView lv = leakedDialog.getListView();
            if(lv != null)  lv.setOnItemClickListener(null);
    } 
} 

对于adapter同理 参考 http://stackoverflow.com/questions/7083441/android-alertdialog-causes-a-memory-leak

301 viewpager setcurrentItem之后,调用相关的监听 onpageSelected onPageChangedState onPageScrolled

如果是想在动画执行完成之后,执行某些操作,可以通过如下方式

private class PageChangeListener implements OnPageChangeListener { 

    @Override 
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
   } 

    @Override 
    public void onPageSelected(int position) {
        isPageChanged = true; 
    } 

    @Override 
    public void onPageScrollStateChanged(int state) {
        switch (state) {
        case ViewPager.SCROLL_STATE_IDLE:
            if (isPageChanged) { 
                updateCurrentPage();//this will be called when animation ends 
                isPageChanged = false; 
            } 
            break; 
        case ViewPager.SCROLL_STATE_DRAGGING:
            break; 
        case ViewPager.SCROLL_STATE_SETTLING:
            break; 
        } 
    } 
} 

参考Android viewpager animation

302 Instant Run does not support deploying build variants with multidex enabled, to a target with API level 20 or below. To use Instant Run with a multidex enabled build variant, deploy to a target with API level 21 or higher.”);

http://stackoverflow.com/questions/36516931/instant-run-disabled-for-multidexed-application

303 java.util.ConcurrentModificationException at java.util.LinkedList$LinkIterator.next(LinkedList.java:124)

linkedlist 不是线程安全的,用ConcurrentLinkedQueue 参考 LinkedList多线程不安全的解决办法

304 sqlite 出现 unrecognized token: “xxxx”

使用sql 语句中,如果有字符串,必须加上 ‘ ‘单括号 括起来

You need to escape the filename parameter. The punctuation in the filename is confusing SQLite. You could do it by surrounding the filename in 'single quotes' in the string you pass in to SQLite, but it`s cleaner and safer to pass it as a separate argument, like this:

sqliteDatabase.update(AndroidOpenDbHelper.TABLE_FILE, values, 
        AndroidOpenDbHelper.COLUMN_NAME_FILE_NAME+"=?", new String[] {filename});

android.database.sqlite.SQLiteException: unrecognized token:

305 ScrollView嵌套ListView,listItem.measure(0,0);报空指针异常NullPointerException

当调用listItem.measure(0, 0);报空指针时问题:
检查Adapter适配时Item的根容器为RelativeLayout,
报错原因:

In platform version 17 and lower, RelativeLayout was affected by a measurement bug that could cause child views to be measured with incorrect MeasureSpec values. (See MeasureSpec.makeMeasureSpec for more details.) This was triggered when a RelativeLayout container was placed in a scrolling container, such as a ScrollView or HorizontalScrollView. If a custom view not equipped to properly measure with the MeasureSpec mode UNSPECIFIED was placed in a RelativeLayout, this would silently work anyway as RelativeLayout would pass a very large AT_MOST MeasureSpec instead.
This behavior has been preserved for apps that set android:targetSdkVersion="17" or older in their manifest`s uses-sdktag for compatibility. Apps targeting SDK version 18 or newer will receive the correct behavior

有三种解决方案:

一、升级版本到4.2.2
二、更改根容器为LinearLayout
三、在适配器里添加convertView.setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); convertView为Item的view

参考ScrollView嵌套ListView,listItem.measure(0,0);报空指针异常NullPointerException

306 Webview访问https 报错 primary error: 5 certificate: Issued to: CN=*

public void onReceivedSslError(final WebView view, final SslErrorHandler handler, SslError error) {
    Log.d("CHECK", "onReceivedSslError");
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    AlertDialog alertDialog = builder.create();
    String message = "Certificate error.";
    switch (error.getPrimaryError()) {
        case SslError.SSL_UNTRUSTED:
            message = "The certificate authority is not trusted.";
            break;
        case SslError.SSL_EXPIRED:
            message = "The certificate has expired.";
            break;
        case SslError.SSL_IDMISMATCH:
            message = "The certificate Hostname mismatch.";
            break;
        case SslError.SSL_NOTYETVALID:
            message = "The certificate is not yet valid.";
            break;
    }
    message += " Do you want to continue anyway?";
    alertDialog.setTitle("SSL Certificate Error");
    alertDialog.setMessage(message);
    alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "OK", new OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d("CHECK", "Button ok pressed");
            // Ignore SSL certificate errors
            handler.proceed();
        }
    });
    alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Log.d("CHECK", "Button cancel pressed");
            handler.cancel();
        }
    });
    alertDialog.show();
    }
});
webView.loadUrl("https://www.google.co.in/");

参考
Android : Workaround for webview not loading https url
Android WebView not loading an HTTPS URL
How can load https url without use of ssl in android webview

[Android安全开发之安全使用HTTPS](https://www.easyaq.com/newsdetail/id/37169867.shtml) 这是一篇很好的文章!!!

目前很多应用都用webview加载H5页面,如果服务端采用的是可信CA颁发的证书,在webView.setWebViewClient(webviewClient)时重载WebViewClient的onReceivedSslError(),如果出现证书错误,直接调用handler.proceed()会忽略错误继续加载证书有问题的页面,如果调用handler.cancel()可以终止加载证书有问题的页面,证书出现问题了,可以提示用户风险,让用户选择加载与否,如果是需要安全级别比较高,可以直接终止页面加载,提示用户网络环境有风险:
![](https://cdn.easyaq.com/@/image/download/y2361mq04769o3.JPG)
不建议直接用handler.proceed(),聚安全的应用安全扫描器会扫出来直接调用handler.proceed()的情况。
如果webview加载https需要强校验服务端证书,可以在onPageStarted()中用HttpsURLConnection强校验证书的方式来校验服务端证书,如果校验不通过停止加载网页。当然这样会拖慢网页的加载速度,需要进一步优化,具体优化的办法不在本次讨论范围,这里也不详细讲解了。

需要在客户端中预埋证书文件,或者将证书硬编码写在代码中

正确使用HTTPS并非完全能够防住客户端的Hook分析修改,要想保证通信安全,也需要依靠其他方法,比如重要信息在交给HTTPS传输之前进行加密,另外实现客户端请求的签名处理,保证客户端与服务端通信请求不被伪造 

更多问题请关注 android开发遇到问题点滴

展开阅读全文

没有更多推荐了,返回首页