首页 > 解决方案 > 当有一个值被传递给 .onNext 时,RxJava Observable.create 返回 null

问题描述

我正在通过来自 google calendar V3 Java API 的 ID 获取日历事件,该 API 是以下内容的包装: https ://developers.google.com/calendar/v3/reference/events/get?apix_params=%7B%22calendarId%22 %3A%22primary%22%2C%22eventId%22%3A%226msto66us6ou1ri503lem4absk%22%7D

当我调用事件时,我将它包装在 Observable 中并将其传递给映射它的服务,然后通过活动调用该服务。

我遇到的一个问题是,当我启动新的 Observable 并调用事件时,事件被返回,但随后作为 null 传递给 Observable.next,这导致我的应用程序崩溃。当我调试时,我可以看到日历事件,所以我觉得这是一些奇怪的异步/线程问题。

以下是此次活动的呼吁:

@Module
class GoogleCalendarsApiServiceModule @Inject constructor(): IGoogleCalendarsApiServiceModule {

    private lateinit var googleCalendarService: Calendar

    private val httpTransport: NetHttpTransport = NetHttpTransport()
    private val subscriptions: Disposable = Disposable.empty()

    init {
        this.subscriptions.apply {
            AndroidContextObservable.context()
                .subscribe { context ->
                    val googleCredential = GoogleCredentialsBuilder.getCredentials(httpTransport, context)
                    googleCalendarService = ServiceBuilder.buildGoogleCalendarService(googleCredential, httpTransport)
                }
        }
    }

    fun finalize() {
        this.subscriptions.dispose()
    }

    override fun getEventById(eventId: String): Observable<Event> {

        return Observable.create { observer ->
            val calendarEvents: Calendar.Events? = googleCalendarService.events()
            val event = calendarEvents!!
                .get("primary", eventId)
                .execute()

            observer.onNext(event)
            observer.onComplete()
        }
    }
}

然后映射事件的调用服务:

    override fun getCalendarEventById(eventId: String): Observable<FullMeetingEvent> {
        return this.googleCalendarsApiServiceModule.getEventById(eventId)
            .map { mapMeetingEvent(it) } // <-- skipped due to event being null/empty runnable
            .onErrorReturn { throw Exception(it) }
    }

最后是调用活动:

class ViewMeetingEventDataActivity: AppCompatActivity() {

    @Inject lateinit var bundleUtilityModule: BundleUtilityModule
    @Inject lateinit var fragmentUtilityModule: FragmentUtilityModule
    @Inject lateinit var googleCalendarService: GoogleCalendarService

    private val subscriptions: Disposable = Disposable.empty()
    private lateinit var eventId: String
    private lateinit var event: FullMeetingEvent

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        AndroidContextObservable.setContext(this)
        DaggerServiceModuleComponent.create().inject(this)
        DaggerUtilityModuleComponent.create().inject(this)

        this.eventId = intent.getStringExtra(BundleData.MEETING_EVENT_ID.name)!!

        setContentView(R.layout.layout_view_meeting_event_activity)
    }

    override fun onStart() {
        super.onStart()

        subscriptions.apply {
            googleCalendarService.getCalendarEventById(eventId)
                .subscribeOn(Schedulers.io())
                .subscribe(
                    {
                        event = it
                        setViewMeetingEventFragment(it)
                    },
                    {err -> println(err)}
                )
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        this.subscriptions.dispose()
    }

    private fun setViewMeetingEventFragment(meetingEvent: FullMeetingEvent) {
        fragmentUtilityModule.createSingleFragment<FullMeetingEvent, ViewMeetingEventDataFragment>(meetingEvent, BundleData.FULL_MEETING_EVENT.name, supportFragmentManager, R.id.view_meeting_event_data_container)
    }
}

显然,随着服务失败,活动中的订阅直接进入错误块。

我知道我有这个事件,在调试器中四处挖掘时,我设法找到了它:

在此处输入图像描述

但正如您在调试器上方的代码中看到的那样,它显然是在创建一个 null observable。

这就像 observable 在事件调用完成之前已经触发,但我有代码以完全相同的方式抓取我的所有事件并且它工作得很好。

标签: androidkotlinrx-javagoogle-calendar-api

解决方案


事实证明,该服务正在吞噬错误并将 s**t 推回 Activity。实际错误来自映射器并试图使用为空的东西。修复方法是:

    fun mapMeetingEvent(googleCalendarEvent: Event): FullMeetingEvent {
        val attendees = mutableListOf<String>()
        var organiser: String;

        if(googleCalendarEvent.attendees != null && googleCalendarEvent.attendees.size > 0) {
            googleCalendarEvent.attendees.forEach { x ->
                if(x.displayName != null) {
                    attendees.add(x.displayName)
                }
                else {
                    attendees.add(x.email)
                }
            }
        }

        if (googleCalendarEvent.organizer.displayName != null) {
            organiser = googleCalendarEvent.organizer.displayName
        } else {
            organiser = "No organiser"
        }

        return FullMeetingEvent(
            googleCalendarEvent.description,
            googleCalendarEvent.summary,
            googleCalendarEvent.id,
            googleCalendarEvent.start.dateTime,
            googleCalendarEvent.end.dateTime,
            googleCalendarEvent.location,
            attendees,
            organiser
        )
    }

很遗憾必须像这样进行空值检查,但我想就是这样。


推荐阅读