Android“无法打开 APK”、“无法添加资产路径”和“java.io.IOException:无法加载资产路径”

far*_*san 7 android repository-pattern kotlin android-room kotlin-coroutines

无法打开 APK '/data/app/~~Binr6SVO9dmLCUcPgCpAyA==/com.example.newspaper-yFV7fjvEt5i0gI4--yMcTA==/base.apk': I/O 错误\n无法打开 APK '/data/app/~ ~Binr6SVO9dmLCUcPgCpAyA==/com.example.newspaper-yFV7fjvEt5i0gI4--yMcTA==/base.apk': I/O 错误\n无法添加资源路径 '/data/app/~~Binr6SVO9dmLCUcPgCpAyA==/com.example.newspaper -yFV7fjvEt5i0gI4--yMcTA==/base.apk'\njava.io.IOException:无法加载资产路径/data/app/~~Binr6SVO9dmLCUcPgCpAyA==/com.example.newspaper-yFV7fjvEt5i0gI4--yMcTA==/base。 apk\nat android.content.res.ApkAssets.nativeLoad(本机方法)\nat android.content.res.ApkAssets.(ApkAssets.java:295)\nat android.content.res.ApkAssets.loadFromPath(ApkAssets.java:144 )\nat android.app.ResourcesManager.loadApkAssets(ResourcesManager.java:454)\nat android.app.ResourcesManager.access$000(ResourcesManager.java:72)\nat android.app.ResourcesManager$ApkAssetsSupplier.load(ResourcesManager.java: 168)\nat android.app.ResourcesManager.createAssetManager(ResourcesManager.java:530)\nat android.app.ResourcesManager.createResourcesImpl(ResourcesManager.java:612)\nat android.app.ResourcesManager.findOrCreateResourcesImplForKeyLocked(ResourcesManager.java:664) \nat android.app.ResourcesManager.createResources(ResourcesManager.java:1011)\nat android.app.ResourcesManager.getResources(ResourcesManager.java:1114)\nat android.app.ActivityThread.getTopLevelResources(ActivityThread.java:2414)\nat android.app.ApplicationPackageManager.getResourcesForApplication(ApplicationPackageManager.java:1751)\nat android.app.ApplicationPackageManager.getResourcesForApplication(ApplicationPackageManager.java:1737)\nat android.app.ApplicationPackageManager.getDrawable(ApplicationPackageManager.java:1506)\nat android. app.ApplicationPackageManager.loadUnbadgedItemIcon(ApplicationPackageManager.java:3029)\nat android.content.pm.PackageItemInfo.loadUnbadgedIcon(PackageItemInfo.java:290)\nat com.android.systemui.toast.SystemUIToast.getBadgedIcon(SystemUIToast.java:284) \nat com.android.systemui.toast.SystemUIToast.inflateToastView(SystemUIToast.java:198)\nat com.android.systemui.toast.SystemUIToast.(SystemUIToast.java:90)\nat com.android.systemui.toast.SystemUIToast .(SystemUIToast.java:77)\nat com.android.systemui.toast.ToastFactory.createToast(ToastFactory.java:78)\nat com.android.systemui.toast.ToastUI.lambda$showToast$0(ToastUI.java:113 )\nat com.android.systemui.toast.ToastUI.$r8$lambda$w_gPCh3F8Xxn1jN4lkQZoUci71c(未知来源:0)\nat com.android.systemui.toast.ToastUI$$ExternalSyntheticLambda0.run(未知来源:16)\nat com .android.systemui.toast.ToastUI.showToast(ToastUI.java:140)\nat com.android.systemui.statusbar.CommandQueue$H.handleMessage(CommandQueue.java:1441)\nat android.os.Handler.dispatchMessage(Handler .java:106)\nat android.os.Looper.loopOnce(Looper.java:201)\nat android.os.Looper.loop(Looper.java:288)\nat android.app.ActivityThread.main(ActivityThread.java :7842)\ nat java.lang.reflect.Method.invoke(本机方法)\ nat com.android。Internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)\nat com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

\n

我正在为我的新闻应用程序使用新闻 API。这些是崩溃之前的步骤:

\n
    \n
  1. 显示新闻列表
  2. \n
  3. 单击其中之一即可将其详细信息显示到 ArticleFragment 中
  4. \n
  5. 当我单击浮动操作按钮将其保存在 SavedNewsFragment 中时,它因上述错误而崩溃。
  6. \n
\n

相关文件:

\n

新闻视图模型

\n
class NewsViewModel(val repo : NewsRepository) : ViewModel()\n{\n    val breakingNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()\n    val breakingNewsPage = 1        // update later\n\n    val searchNews: MutableLiveData<Resource<NewsResponse>> = MutableLiveData()\n    val searchNewsPage = 1        // update later\n\n    var savedNews: MutableLiveData<List<Article>> = MutableLiveData()\n\n    init {\n        getBreakingNews()\n    }\n\n/**For BreakingNewsFragment**/\n    private fun getBreakingNews(countryString : String = "eg") = viewModelScope.launch {\n        breakingNews.postValue(Resource.Loading())\n        val response = repo.getBreakingNews(countryString, breakingNewsPage)\n        breakingNews.postValue(handleBreakingNewsResponse(response))\n    }\n\n    private fun handleBreakingNewsResponse(response: Response<NewsResponse>) : Resource<NewsResponse>\n    {\n        if(response.isSuccessful)\n            response.body().let {\n                return Resource.Success(it)\n            }\n        else\n            return Resource.Error(response.message(), response.body())\n    }\n\n/**For SearchNewsFragment**/\n    fun searchForNews(text : String) = viewModelScope.launch {\n        searchNews.postValue(Resource.Loading())\n        val response = repo.getSearchedNews(text, searchNewsPage)\n        searchNews.postValue(handleSearchForNewsResponse(response))\n    }\n\n    private fun handleSearchForNewsResponse(response: Response<NewsResponse>) : Resource<NewsResponse>\n    {\n        if(response.isSuccessful)\n            response.body().let {\n                return Resource.Success(it)\n            }\n        else\n            return Resource.Error(response.message(), response.body())\n    }\n\n/**Deal with Room**/\n    fun saveThisArticle(article: Article) = viewModelScope.launch {\n        repo.addIfNotExist(article)\n        /*Log.d("NewsViewModel "," => Start saving")\n        val num = repo.addIfNotExist(article).wait()\n        Log.d("NewsViewModel => saveThisArticle(article: Article) ", "--------- $num")*/\n    }\n\n    fun getMySavedArticles() = savedNews.postValue(repo.getSavedNews().value)\n\n    fun deleteThisArticle(article: Article) = viewModelScope.launch {\n        repo.deleteArticle(article)\n    }\n\n\n    class NewsVMFactory(val repo: NewsRepository) : ViewModelProvider.Factory {\n        override fun <T : ViewModel> create(modelClass: Class<T>): T {\n            if(modelClass.isAssignableFrom(NewsViewModel::class.java)){\n                @Suppress("UNCHECKED_CAST")\n                return NewsViewModel(repo) as T\n            }\n            throw IllegalArgumentException("Unknown viewModel class")\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

新闻库

\n
class NewsRepository(val db: ArticleDatabase)\n{\n    /**Remote**/\n    suspend fun getBreakingNews(country_of_2Letters : String, pageNum : Int) =\n        RetrofitInstance.newsAPI.getNewsHeadlines()\n\n    suspend fun getSearchedNews(text : String, pageNum : Int) =\n        RetrofitInstance.newsAPI.searchFor(text, pageNum)\n\n    /**Local**/\n    suspend fun addIfNotExist(article : Article) =\n        withContext(Dispatchers.IO) {\n            db.newsDatabaseDao.upsert(article)\n    }\n\n    fun getSavedNews() = db.newsDatabaseDao.getAllArticles()\n\n    suspend fun deleteArticle(article : Article) = db.newsDatabaseDao.deleteArticle(article)\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

接口 NewsDao

\n
@Dao\ninterface NewsDao {\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    suspend fun upsert(article : Article): Long      // TODO ???? Int\n\n    @Query("SELECT * FROM articles")\n    fun getAllArticles(): LiveData<List<Article>>   // TODO There will be two tables. one for saved articles and other for cashing.\n\n    @Delete\n    suspend fun deleteArticle(article: Article)\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

文章数据库

\n
@Database(entities = [Article::class], version = 1, exportSchema = false)\n@TypeConverters(Converters::class)\nabstract class ArticleDatabase : RoomDatabase() {                                   \n\n    abstract val newsDatabaseDao: NewsDao       \n\n    companion object {\n\n        @Volatile\n        var INSTANCE: ArticleDatabase? = null\n\n        fun getInstance(context: Context): ArticleDatabase {\n            synchronized(this) {\n                return INSTANCE ?: Room.databaseBuilder(\n                    context.applicationContext,\n                    ArticleDatabase::class.java,\n                    "article_database"\n                )\n                    .fallbackToDestructiveMigration()\n                    .build()\n            }\n        }\n\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

模型/数据文件

\n
data class NewsResponse(\n    val articles: List<Article>,\n    val status: String, // ok\n    val totalResults: Int // 383\n)\n\n@Entity(tableName = "articles")\ndata class Article(\n  //  @PrimaryKey(autoGenerate = true)\n  //  val id : Int? = null,      // tried: var, Int, Int = 0, Int?\n    @ColumnInfo(name = "author")\n    val author: String? = "",\n    @ColumnInfo(name = "content")\n    val content: String? = "",\n    @ColumnInfo(name = "description")\n    val description: String? = "",\n    @ColumnInfo(name = "published_at")\n    val publishedAt: String, \n    @ColumnInfo(name = "source")\n    val source: Source,\n    @ColumnInfo(name = "title")\n    val title: String,\n    @ColumnInfo(name = "url")\n    val url: String, \n    @ColumnInfo(name = "url_to_image")\n    val urlToImage: String?\n) : Serializable\n{\n    override fun hashCode(): Int {\n        var result = id.hashCode()\n        if(url.isNullOrEmpty()){\n            result = 31 * result + url.hashCode()\n        }\n        return result\n    }\n}\n\ndata class Source(\n    val id: String, // business-insider\n    val name: String // The Guardian\n)\n
Run Code Online (Sandbox Code Playgroud)\n

转换器类

\n
class Converters {\n\n//    data class Source(\n//    val id: String,\n//    val name: String\n//    )\n\n    @TypeConverter\n    fun fromSource(source: Source): String =\n        Gson().toJson(source)      // set in the database as a string\n\n    @TypeConverter\n    fun toSource(stringSource: String) : Source =\n        Gson().fromJson(stringSource, Source::class.java)      // get it from the database and compose it into its original datatype\n}\n
Run Code Online (Sandbox Code Playgroud)\n

文章片段

\n
class ArticleFragment : BaseFragment(R.layout.fragment_article) {\n\n    lateinit var binding : FragmentArticleBinding\n    val args : ArticleFragmentArgs by navArgs()\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {\n        binding = FragmentArticleBinding.inflate(inflater)\n\n        val data = args.anArticle\n\n        binding.webView.apply {\n            try{\n                webViewClient = WebViewClient()\n                    loadUrl(data.url)\n            }\n            catch (e: Exception){\n                loadUrl("https://www.google.co.in/")\n                Toast.makeText(context, "There is a problem in the url", Toast.LENGTH_LONG).show()\n            }\n        }\n\n        binding.fab.setOnClickListener {\n            viewModel.saveThisArticle(data)\n            Toast.makeText(context, "Saved successfully \xe2\x9c\x85", Toast.LENGTH_SHORT).show()\n        }\n\n        return binding.root\n    }\n\n\n    override fun onDestroyView() {\n        super.onDestroyView()\n        binding.unbind()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n