Android 開發中遇到的 bug(11)

前言

記錄開發中遇到的 bug,不再讓自己重複地被同樣的 bug 折磨。

正文

1. If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.

時間:2019年12月29日12:04:20
問題描述:
在 kotlin 工程中,使用 Databinding 的 @BindingAdapter 報錯:

Cannot find a setter for <androidx.recyclerview.widget.RecyclerView app:items> that accepts parameter type 'androidx.lifecycle.LiveData<java.util.List<com.readbook.chinesepoetry.data.model.PoetryBean>>'

If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.

問題解決:
在 build.gradle 文件中添加:

apply plugin: 'kotlin-kapt'

2. 在 RecyclerView.Adapter 的 onBindViewHolder 方法中使用 Databinding,導致列表條目重複

時間:2019年12月29日16:40:29
問題描述:

class RecommendAdapter(private val viewModel: RecommendViewModel) :
        ListAdapter<PoetryBean, RecommendViewHolder>(PoetryBeanDiffCallback()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecommendViewHolder {
        val binding = RecommendRecycleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return RecommendViewHolder(binding)
    }


    override fun onBindViewHolder(holder: RecommendViewHolder, position: Int) {
        val item = getItem(position)
        holder.bindItem(item)
    }

    class RecommendViewHolder(private val binding: RecommendRecycleItemBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bindItem(item: PoetryBean) {
            Timber.d("item=$item")
            with(item) {
                binding.tvName.text = name + Integer.toString(id)
                binding.tvDynastyPoet.text = itemView.context.getString(R.string.common_dynasty_poet, dynasty, poet)
                binding.tvContent.text = Html.fromHtml(content)
            }
        }
    }
}

問題分析:
對比查看 android-architecture 的代碼,發現會在 bindItem() 方法中最後一行再調用一次:

binding.executePendingBindings()

增加這一行代碼後,解決了問題。但還是要再詳細瞭解一下。
再去查看一下官方文檔的說明:https://developer.android.google.cn/topic/libraries/data-binding/generated-binding#immediate_binding

When a variable or observable object changes, the binding is scheduled to change before the next frame. There are times, however, when binding must be executed immediately. To force execution, use the executePendingBindings() method.

並且官方也給了實例代碼 https://developer.android.google.cn/topic/libraries/data-binding/generated-binding#dynamic_variables :

override fun onBindViewHolder(holder: BindingHolder, position: Int) {
    item: T = items.get(position)
    holder.binding.setVariable(BR.item, item);
    holder.binding.executePendingBindings();
}

參考:https://stackoverflow.com/questions/53043412/android-why-use-executependingbindings-in-recyclerview

3. kotlin.TypeCastException: null cannot be cast to non-null type com.readbook.chinesepoetry.data.model.Response<com.readbook.chinesepoetry.data.model.RecommendListBean>

時間:2020年1月5日21:30:35
問題描述:

object CacheUtil {
    private val cache = ACache.get(File(Utils.getApp().filesDir, "ACache"))
    private const val RECOMMEND_LIST = "recommend_list"

    fun getRecommendList(page: Int): Response<RecommendListBean>? {
        return cache.getAsObject(RECOMMEND_LIST + page) as Response<RecommendListBean>
    }
}

第一次取出 cache.getAsObject(RECOMMEND_LIST + page)null,轉爲 Response<RecommendListBean> 這個非空類型時報錯的。
解決辦法:
把代碼改爲:

return cache.getAsObject(RECOMMEND_LIST + page) as Response<RecommendListBean>?

4. Java:Inner class cannot have static declaration

時間:2020年1月11日13:17:22
問題描述:

public class Apply {
     class  ApplyTest {
     	// 下面的方法編譯報錯:Inner class cannot have static declaration
        public static void main(String[] args) throws Exception {
            List<Shape> shapes = new ArrayList<>();
        }
    }
}

解決辦法:

public class Apply {
     static class ApplyTest {
     	// 下面的方法編譯報錯:Inner class cannot have static declaration
        public static void main(String[] args) throws Exception {
            List<Shape> shapes = new ArrayList<>();
        }
    }
}

5. javax.net.ssl.SSLHandshakeException(Chain validation failed)

時間:2020年1月19日10:13:44
問題描述:
我在應用裏面使用 Glide 加載 github 上存儲的圖片資源,可是在一個手機上原來加載出來,後來卻加載不出來了。

2020-01-29 09:57:22.392 9043-9043/com.readbook.chinesepoetry W/Glide: Load failed for https://raw.githubusercontent.com/xxx/poetry/master/image/image_248.jpg with size [192x192]
    class com.bumptech.glide.load.engine.GlideException: Failed to load resource
    There was 1 cause:
    javax.net.ssl.SSLHandshakeException(Chain validation failed)
     call GlideException#logRootCauses(String) for more detail
      Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE
    There was 1 cause:
    javax.net.ssl.SSLHandshakeException(Chain validation failed)
     call GlideException#logRootCauses(String) for more detail
        Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed
    There was 1 cause:
    javax.net.ssl.SSLHandshakeException(Chain validation failed)
     call GlideException#logRootCauses(String) for more detail
          Cause (1 of 1): class javax.net.ssl.SSLHandshakeException: Chain validation failed
2020-01-29 09:57:22.396 9043-9043/com.readbook.chinesepoetry I/Glide: Root cause (1 of 1)
    javax.net.ssl.SSLHandshakeException: Chain validation failed
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:355)
        at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:192)
        at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
        at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127)
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(Unknown Source:0)
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:100)
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:56)
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:164)
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154)
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:62)
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
        at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63)
        at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310)
        at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279)
        at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)
        at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:431)
     Caused by: java.security.cert.CertificateException: Chain validation failed
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:705)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:537)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:558)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:626)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:493)
        at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:416)
        at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:337)
        at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
        at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:88)
        at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:203)
        at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:592)
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:351)
        at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:192) 
        at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149) 
        at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:112) 
        at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184) 
        at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126) 
        at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95) 
        at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281) 
        at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224) 
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:461) 
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:127) 
        at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89) 
        at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(Unknown Source:0) 
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:100) 
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:56) 
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) 
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:164) 
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154) 
        at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:62) 
        at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100) 
        at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63) 
        at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310) 
        at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279) 
        at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
        at java.lang.Thread.run(Thread.java:764) 
        at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:431) 
     Caused by: java.security.cert.CertPathValidatorException: Response is unreliable: its validity interval is out-of-date
2020-01-29 09:57:22.399 9043-9043/com.readbook.chinesepoetry I/Glide:     at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:133)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:225)
        at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:143)
        at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
        at java.security.cert.CertPathValidator.validate(CertPathValidator.java:301)
        at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:701)
        	... 39 more
     Caused by: java.security.cert.CertPathValidatorException: Response is unreliable: its validity interval is out-of-date
        at sun.security.provider.certpath.OCSPResponse.verify(OCSPResponse.java:619)
        at sun.security.provider.certpath.RevocationChecker.checkOCSP(RevocationChecker.java:709)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:363)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:337)
        at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:125)
        	... 44 more
    	Suppressed: java.security.cert.CertPathValidatorException: Could not determine revocation status
        at sun.security.provider.certpath.RevocationChecker.buildToNewKey(RevocationChecker.java:1092)
        at sun.security.provider.certpath.RevocationChecker.verifyWithSeparateSigningKey(RevocationChecker.java:910)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:577)
        at sun.security.provider.certpath.RevocationChecker.checkCRLs(RevocationChecker.java:465)
        at sun.security.provider.certpath.RevocationChecker.check(RevocationChecker.java:394)
        		... 46 more

解決辦法:原來是手機時間的問題,修改爲當前時間,解決了這個問題。

最後

代碼出錯了,關鍵是要仔細查看日誌。能夠仔細地查看日誌,就離解決問題很近了。

發佈了76 篇原創文章 · 獲贊 44 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章