1Answer

I'm trying to make an app to check the weather using OpenWeatherMap, Kotlin, Retrofit, and MVP with the clean architecture.

The app is very simple, has only one activity and the layout shows different data according to the location that the user selects. When initiating the activity, this initializes the presenter in onCreate and calls the method that initiates the request process. When I return to my activity with the answer, I am trying to show some information about that response in a TextView, but the app crashes because that view is null.

I'm using Kotlin Android Extensions, which allows me, theoretically, to invoke the view only with its id, without needing to use findViewById.

I'm new to Kotlin and maybe I'm missing something.

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.climaconsulta.R
import com.climaconsulta.user.model.pojos.MainWeather
import com.climaconsulta.user.presenter.MainActivityPresenter
import com.climaconsulta.user.presenter.MainActivityPresenterImpl
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), MainActivityView {
    var presenter: MainActivityPresenter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        presenter = MainActivityPresenterImpl()
        presenter!!.getMainWeather("London")
    }

    override fun showCurrentCity() {
        presenter!!.getCurrentCity()
    }

    override fun showMainWeather(mainWeather: MainWeather) {
        mainTemperature.text = mainWeather.main!!.temp.toString()
        // HERE I TRY TO SET THE TEXT. BUT "mainTemperature" IS NULL
    }

    override fun showFiveDaysWeather(cityName: String) {
        presenter!!.getFiveDaysWheather(cityName)
    }

    override fun showError(error: String) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}
Answer

Firstly, why you force nullable type to run itself? Why you do not call it in a safe way like this presenter?.func()? Force call will crash your app but safe call - not.

Secondly, move these lines below into onStart()

presenter = MainActivityPresenterImpl()
presenter?.getMainWeather("London")

I would like to recommend you to use in presenter MainActivityView interface that implements your MainActivity. I do not see when you set it into presenter.

Example -->

BasePresenter:

abstract class BasePresenter<View : BaseView> {
    protected var view: View? = null

    open fun attachView(view: View) {
        this.view = view
    }

    open fun detachView(view: View) {
        if (this.view == view) {
            this.view = null
        }
    }
}

interface BaseView {
    fun showError(error: String)
}

Presenter:

class MainPresenter() : BasePresenter<MainActivityView>() {
    private fun getMainWeather(name: String) {
        view?.showProgress(true)
        ...
    }
}

MainActivity:

@Inject
protected lateinit var presenter: MainPresenter
...

override fun onStart() {
    super.onStart()
    presenter.attachView(this)
}

override fun onStop() {
    presenter.detachView(this)
    super.onStop()
}

And yes, I use Dagger 2 to provide dependencies. You may use it as I sad:

presenter = MainActivityPresenterImpl()
presenter?.getMainWeather("London")

But if you want you may look at simple Dagger 2 implementation for a small project.

  • 1
Reply Report
      • 1
    • Does not work .. I get data. I mean, weather data is coming to my activity. But the view still null. Thank you about the info about safe call. I was using !! just because I believed that was the correct way. But after your answer, I read about it.

Warm tip !!!

This article is reproduced from Stack Exchange / Stack Overflow, please click

Trending Tags

Related Questions