Я создал специальный запечатанный класс для проверки своих обнуляемых URL-адресов, чтобы я мог безопасно и легко узнать его состояние (Нет, Неверный, Действительный)
sealed class UrlType : Parcelable {
@Parcelize class Valid private constructor(val url: String) : UrlType() {
companion object : CompanionTest<UrlType.Valid, String>(::Valid)
}
@Parcelize object None : UrlType()
@Parcelize class Invalid(val invalidUrl: String) : UrlType()
companion object {
fun getUrlType(url: String?): UrlType {
return if (url == null) {
UrlType.None
} else if (!url.isValidUrl()) {
UrlType.Invalid(url)
} else {
Valid.create(url)
}
}
}
}
open class CompanionTest<out T, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
fun create(arg1: A): T {
return creator!!(arg1)
}
}
@Parcelize
data class NewsPost(
val id: String,
val title: String,
val description: String?,
val webContentUrl: UrlType,
val imageUrl: UrlType,
val created: String,
val updated: String,
val feeds: List<Feed>
) : Parcelable
Когда я впервые попробовал эту идею, у меня возникли подозрения, что она не сработает из-за частного конструктора и Parcelize, но я провел несколько тестов, и это сработало.
У меня также есть запечатанный класс для указания типа запуска для моей активности, который может быть введен несколькими путями
sealed class NewsLaunchType : Parcelable {
@Parcelize object FeedList : NewsLaunchType()
@Parcelize class FeedDetail(val newsFeedType: NewsFeedType) : NewsLaunchType()
@Parcelize class PostDetail(val newsPost: NewsPost) : NewsLaunchType()
}
Когда я запускаю свою активность с NewsLaunchType.PostDetail(newsPost)
, приложение вылетает со следующей ошибкой
fun startActivity(){
val intent = Intent(context, NewsActivity::class.java).apply {
putExtra("key", NewsLaunchType.PostDetail(newsPost))
}
startActivity(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_news)
val newsActivityLaunchType = intent.getParcelableExtra<NewsLaunchType>("key")
}
2018-11-08 11:08:33.897 17030-17030/com.something.internal E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.something.internal, PID: 17030
java.lang.IllegalAccessError: Method 'void com.something.somethingkit.helper.UrlType$Valid.<init>(java.lang.String)' is inaccessible to class 'com.something.somethingkit.helper.UrlType$Valid$Creator' (declaration of 'com.something.somethingkit.helper.UrlType$Valid$Creator' appears in /data/app/com.something.internal-QTiupS4yw25rZK5uXP7UCQ==/base.apk:classes2.dex)
at com.something.somethingkit.helper.UrlType$Valid$Creator.createFromParcel(Unknown Source:11)
at android.os.Parcel.readParcelable(Parcel.java:2798)
at com.something.somethingkit.model.news.local.NewsPost$Creator.createFromParcel(Unknown Source:25)
at android.os.Parcel.readParcelable(Parcel.java:2798)
at com.something.screens.news.NewsLaunchType$PostDetail$Creator.createFromParcel(Unknown Source:13)
at android.os.Parcel.readParcelable(Parcel.java:2798)
at android.os.Parcel.readValue(Parcel.java:2692)
at android.os.Parcel.readArrayMapInternal(Parcel.java:3059)
at android.os.BaseBundle.unparcel(BaseBundle.java:257)
at android.os.Bundle.getParcelable(Bundle.java:888)
at android.content.Intent.getParcelableExtra(Intent.java:7734)
at com.something.screens.news.NewsActivity.onCreate(NewsActivity.kt:31)
at android.app.Activity.performCreate(Activity.java:7183)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2908)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3030)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Теперь это не совсем неожиданно, за исключением того, что оно работает, если я пытаюсь вытащить его в том же месте, где я его создал в
fun startActivity(){
val intent = Intent(context, NewsActivity::class.java).apply {
putExtra("key", NewsLaunchType.PostDetail(newsPost))
}
val test = intent.getParcelableExtra<NewsLaunchType>("key")
startActivity(intent)
}
Это также работает, если я добавляю его в комплект фрагментов и добавляю / заменяю новый фрагмент в свою деятельность.
companion object {
fun newInstance(newsPost: NewsPost): NewsDetailFragment {
val bundle = Bundle()
bundle.putParcelable(extraNewsPost, newsPost)
val fragment = NewsDetailFragment()
fragment.arguments = bundle
return fragment
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val newsPost = arguments?.getParcelable<NewsPost>(extraNewsPost)
}
Примечание. При передаче его между действиями происходит дополнительный слой Запечатанных Классов, но он также падает, если я просто попытаюсь передать NewsPost между действиями, поэтому дополнительный слой не является проблемой.
Похоже, что это может быть ошибка с функцией Kotlin Parcelize.
Есть ли какая-либо причина, по которой при передаче его между действиями возникает ошибка, а при передаче между фрагментами - нет? Если есть причина ... какие-нибудь предложения о том, как я мог бы передать это через действия?