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新闻视图模型
\nclass 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}\nRun Code Online (Sandbox Code Playgroud)\n新闻库
\nclass 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}\nRun 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}\nRun 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}\nRun Code Online (Sandbox Code Playgroud)\n模型/数据文件
\ndata 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)\nRun Code Online (Sandbox Code Playgroud)\n转换器类
\nclass 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}\nRun Code Online (Sandbox Code Playgroud)\n文章片段
\nclass 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}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
4718 次 |
| 最近记录: |