Search code examples
androidandroid-viewmodel

Nothing showed up from ViewModel


I'm new to Kotlin and trying to use ViewModel with retrofit to call responses, problem is retrofit won't call anything so nothing showed up.

Tried messing around with ViewModels where it's called

Tried generating new POJO from GSON

Put uses-permission INTERNET inside AndroidManifest

class MovieView(context: Context) : ViewModel() {

private val API_KEY: String = context.getString(R.string.api)
private val TAG = MovieView::class.java!!.getSimpleName()

private var resultsItem: MutableLiveData<List<ResultsItem>>? = null


fun getData(): LiveData<List<ResultsItem>> {
    if (resultsItem == null) {
        resultsItem = MutableLiveData()
        loadData()
    }
    return resultsItem as MutableLiveData<List<ResultsItem>>
}

fun loadData() {
    val apiInterface = ApiClient.getList().create(ApiInterface::class.java)

    val responseCall = apiInterface.getMovieList(API_KEY)
    responseCall.enqueue(object : Callback<Response> {
        override fun onResponse(call: Call<Response>, response: retrofit2.Response<Response>) {
            val resultsItemList = response.body()!!.results
            resultsItem?.value = resultsItemList
            Log.d(TAG,"response")
        }

        override fun onFailure(call: Call<Response>, t: Throwable) {
            Log.d(TAG, "null")
        }
    })
}

}

Expected response from retrofit but none were found, null was also not there means it wasn't even executed.

EDIT :

class MovieFragment : Fragment() {

companion object {
    fun newInstance() = MovieFragment()
}

private lateinit var viewModel: MovieView

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {

    recycler.setHasFixedSize(true)
    recycler.layoutManager = LinearLayoutManager(context)
    recycler.adapter = MovieAdapter(viewModel.getData(), this.context!!)
    viewModel = ViewModelProviders.of(this).get(MovieView::class.java)

    return inflater.inflate(R.layout.movie_fragment, container, false)
}

}

and

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    MovieFragment movieFragment = new MovieFragment();

    getSupportFragmentManager().beginTransaction().add(R.id.framelayout, movieFragment);

Solution

  • resultsItem has to be an immutable property which is observed by the Activity/Fragment and then you need to call just loadData(). fun getData() isn't even needed here.

    As for the call not executing.. Are you sure nothing is really executed? Not onResponse neither onFailure? That doesn't seem possible to me. Maybe put t.printStackTrace() inside onFailure and see in the LogCat if there's this stacktrace.

    Edit:

    Add commit to your fragment transaction in MainActivity, like that:

        getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.framelayout, movieFragment)
            .commit();
    

    Also you should observe your LiveData inside fragment:

    val adapter = MovieAdapter(this.context!!)
    recycler.adapter = adapter
    viewModel = ViewModelProviders.of(this).get(MovieView::class.java)
    viewModel.resultsItem.observe(this, Observer { adapter.update(it) })
    viewModel.loadData()
    

    And add a factory for your ViewModel:

    private val factory = object: ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return MovieView([email protected]!!) as T
        }
    }
    
    viewModel = ViewModelProviders.of(this, factory).get(MovieView::class.java)