超出Activity类的Android上下文

17

我正在尝试处理应用程序中的异常。我试图记录异常,然后使用Toast来提示用户出现问题。在所有扩展Activity类的类中,我已经成功实现了这一点。

但是,在任何不扩展activity的类中,我无法使用toast方法,因为我无法获取当前上下文。是否有简单的方法可以解决这个问题,或者应该将所有类都扩展为Activity?


你具体正在使用哪些数据结构?其中许多数据结构已经有了上下文,或者在某个时候会传递一个上下文。 - FoamyGuy
你可以将上下文作为成员字段并在构造函数中设置。但这可能会导致内存泄漏,因此请谨慎使用(避免对上下文进行静态引用)。 - j0ntech
我有两个类:1)RegistrationScreen扩展Activity。2)SocketClient不扩展Activity。当用户在RegistrationScreen中提交表单时,它会创建一个新的SocketClient对象,通过套接字连接进行注册(这是抛出IOException的部分)。如果成功,SocketClient将返回值到RegistrationScreen类,但当它不成功时,我很困惑。我应该让SocketClient抛出异常并在RegistrationScreen中捕获它们吗? - Joseph
除了下面Samir的直接回答之外,还可以看看Roboguice。 - Jeff Axelrod
3个回答

18

当您从Activity类调用非活动(Non-Activity)类时,只需传递Context即可。

YourNonActivtyClass obj = new YourNonActivtyClass(Activity.this);

1
谢谢。只有一个问题,当使用上述代码时,我会得到“在范围内无法访问Activity类型的封闭实例”的错误。这是在扩展Activity类的类内部发生的。 - Joseph
首先调用Android活动类,然后您可以调用任何不需要Activity的类,因此对我来说上面的代码没有任何问题... - Samir Mangroliya
上下文不是一个非常重的对象吗?这样发布它不太好吧? - Wooff
跟任何一种语言一样,Java将对象通过引用传递:https://dev59.com/EXVD5IYBdhLWcg3wQJOT(primitive types按值传递) - Mars Robertson

0
我使用RXJava和Kotlin提出了一个解决方案。不过,用Java重新创建它应该很容易。这是一个单例类,只有一个getter和setter。getter创建了一个context的observable实例,由Activity通过setContext(context: Context)进行设置。
object AndroidContextObservable { // needs to be singleton. 

    private lateinit var context: Context

    fun context(): Observable<Context> {
        return Observable.create { subscriber ->
            subscriber.onNext(this.context)
            subscriber.onComplete()
        }
    }

    fun setContext(context: Context) {
        this.context = context
    }
}

假设我有一个使用Google日历的服务:我首先会在我的活动中设置它:

class ViewMeetingRoomDataActivity : AppCompatActivity() {
    @Inject lateinit var googleCalendarsService: GoogleCalendarService // abstraction over the GoogleCalendarAPI Class (Below)

    private var subscriptions: Disposable = Disposable.empty()
    private lateinit var meetingRoomBundleData: ParcelableMeetingRoomData

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AndroidContextObservable.setContext(this) // set the context here
        DaggerServiceModuleComponent.create().inject(this)

        setContentView(R.layout.activity_view_meeting_room_data)
    }

    override fun onPause() {
        super.onPause()

        this.subscriptions.dispose()
    }

}

然后因为可观察对象来自单例,我们可以在init生命周期钩子中订阅它。

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

    private lateinit var googleCredential: Credential
    private lateinit var googleCalendarService: Calendar

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

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

    fun finalize() {
        this.subscriptions.dispose() // <-- Don't forget to discard Observables :)
    }
}

我喜欢这个解决方案,因为它是可测试的,并且现在的上下文来自于单一的真相来源。这是我能想到的最干净的方法,在Activity之外获取上下文。

希望我有所帮助。


-13

Toast消息应该在应用程序上下文中工作,即:

Toast.makeText(getApplicationContext(), ...);

2
如果他不在一个活动中,那么可能没有getApplicationContext()方法。此外,也没有必要使用这个方法。活动对象本身就是一个上下文。因此,使用YourActivityName.this代替getApplicationContext()会很好用。 - FoamyGuy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接