Dagger2 Binding Missing - android

This is the first time i'm using this library, even more i have downloaded the project and implemented with new dependencies. First of all, I'm getting cannot resolve symbol error on DaggerApplicationCompoment. And more details about error is:
error: [Dagger/MissingBinding] #javax.inject.Named("movieDB") retrofit2.Retrofit cannot be provided without an #Provides-annotated method.
#javax.inject.Named("movieDB") retrofit2.Retrofit is injected at
free.movies.freemovies.dagger.modules.HttpClientModule.provideFithubApi(restAdapter)
free.movies.freemovies.data.Api.TheMovieDbAPI is injected at
free.movies.freemovies.ui.main.MainFragment.mDbAPI
free.movies.freemovies.ui.main.MainFragment is injected at
free.movies.freemovies.dagger.components.ApplicationComponent.inject(free.movies.freemovies.ui.main.MainFragment)
This is module class:
package free.movies.freemovies.dagger.modules;
import android.app.Application;
import java.io.File;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import dagger.Module;
import dagger.Provides;
import free.movies.freemovies.dagger.AppScope;
import free.movies.freemovies.data.Api.TheMovieDbAPI;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.moshi.MoshiConverterFactory;
/**
* Created by Marcus Gabilheri
*
* #author Marcus Gabilheri
* #version 1.0
* #since 9/4/16.
*/
#Module
public class HttpClientModule {
private static final long DISK_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
public static final String BACKDROP_URL = "http://image.tmdb.org/t/p/w1280";
public static final String POSTER_URL = "http://image.tmdb.org/t/p/w500";
public static final String API_URL = "https://api.themoviedb.org/3/";
public static final String NOW_PLAYING = "movie/now_playing";
public static final String LATEST = "movie/latest";
public static final String POPULAR = "movie/popular";
public static final String TOP_RATED = "movie/top_rated";
public static final String UPCOMING = "movie/upcoming";
public static final String MOVIE = "movie/";
public static final String PERSON = "person/";
public static final String DISCOVER = "discover/movie/";
public static final String SEARCH_MOVIE = "search/movie/";
public static final String TV = "tv/";
#Provides
#AppScope
public OkHttpClient provideOkHttpClient(Application app) {
File cacheDir = new File(app.getCacheDir(), "http");
return new OkHttpClient.Builder()
.readTimeout(1, TimeUnit.MINUTES)
.connectTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.cache(new okhttp3.Cache(cacheDir, DISK_CACHE_SIZE))
.build();
}
#Provides
#Named("TVDB") // Name is used in case a second Retrofit api is provided.
#AppScope
public Retrofit provideTVDBRestAdapter(MoshiConverterFactory moshiConverterFactory, OkHttpClient okHttpClient) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient = okHttpClient.newBuilder()
.addInterceptor(interceptor)
.build();
return new Retrofit.Builder()
.baseUrl(API_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(moshiConverterFactory)
.build();
}
#Provides
public TheMovieDbAPI provideFithubApi(#Named("movieDB") Retrofit restAdapter) {
return restAdapter.create(TheMovieDbAPI.class);
}
#Provides
#AppScope
public MoshiConverterFactory provideMoshiConverterFactory() {
return MoshiConverterFactory.create();
}
}
And fragment where i'm using that module:
package free.movies.freemovies.ui.main;
import android.os.Bundle;
import android.util.SparseArray;
import androidx.core.content.ContextCompat;
import androidx.leanback.app.BrowseSupportFragment;
import androidx.leanback.widget.ArrayObjectAdapter;
import androidx.leanback.widget.HeaderItem;
import androidx.leanback.widget.ListRow;
import androidx.leanback.widget.ListRowPresenter;
import androidx.leanback.widget.OnItemViewSelectedListener;
import androidx.leanback.widget.Presenter;
import androidx.leanback.widget.Row;
import androidx.leanback.widget.RowPresenter;
import javax.inject.Inject;
import free.movies.freemovies.App;
import free.movies.freemovies.Config;
import free.movies.freemovies.R;
import free.movies.freemovies.dagger.modules.HttpClientModule;
import free.movies.freemovies.data.Api.TheMovieDbAPI;
import free.movies.freemovies.data.models.Movie;
import free.movies.freemovies.data.models.MovieResponse;
import free.movies.freemovies.ui.base.GlideBackgroundManager;
import free.movies.freemovies.ui.movies.MoviePresenter;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
/**
* Created by Marcus Gabilheri
*
* #author Marcus Gabilheri
* #version 1.0
* #since 10/8/16.
*/
public class MainFragment extends BrowseSupportFragment implements OnItemViewSelectedListener {
#Inject
TheMovieDbAPI mDbAPI;
private GlideBackgroundManager mBackgroundManager;
private CompositeDisposable compositeDisposable = new CompositeDisposable();
private static final int NOW_PLAYING = 0;
private static final int TOP_RATED = 1;
private static final int POPULAR = 2;
private static final int UPCOMING = 3;
SparseArray<MovieRow> mRows;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
App.instance().appComponent().inject(this);
// The background manager allows us to manage a dimmed background that does not interfere with the rows
// It is the preferred way to set the background of a fragment
mBackgroundManager = new GlideBackgroundManager(getActivity());
// The brand color will be used as the background for the Headers fragment
setBrandColor(ContextCompat.getColor(getActivity(), R.color.primary_transparent));
setHeadersState(HEADERS_ENABLED);
setHeadersTransitionOnBackEnabled(true);
// The TMDB logo on the right corner. It is necessary to show based on their API usage policy
setBadgeDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.powered_by));
createDataRows();
createRows();
prepareEntranceTransition();
fetchNowPlayingMovies();
fetchTopRatedMovies();
fetchPopularMovies();
fetchUpcomingMovies();
}
/**
* Creates the data rows objects
*/
private void createDataRows() {
mRows = new SparseArray<>();
MoviePresenter moviePresenter = new MoviePresenter();
mRows.put(NOW_PLAYING, new MovieRow()
.setId(NOW_PLAYING)
.setAdapter(new ArrayObjectAdapter(moviePresenter))
.setTitle("Now Playing")
.setPage(1)
);
mRows.put(TOP_RATED, new MovieRow()
.setId(TOP_RATED)
.setAdapter(new ArrayObjectAdapter(moviePresenter))
.setTitle("Top Rated")
.setPage(1)
);
mRows.put(POPULAR, new MovieRow()
.setId(POPULAR)
.setAdapter(new ArrayObjectAdapter(moviePresenter))
.setTitle("Popular")
.setPage(1)
);
mRows.put(UPCOMING, new MovieRow()
.setId(UPCOMING)
.setAdapter(new ArrayObjectAdapter(moviePresenter))
.setTitle("Upcoming")
.setPage(1)
);
}
/**
* Creates the rows and sets up the adapter of the fragment
*/
private void createRows() {
// Creates the RowsAdapter for the Fragment
// The ListRowPresenter tells to render ListRow objects
ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
for (int i = 0; i < mRows.size(); i++) {
MovieRow row = mRows.get(i);
// Adds a new ListRow to the adapter. Each row will contain a collection of Movies
// That will be rendered using the MoviePresenter
HeaderItem headerItem = new HeaderItem(row.getId(), row.getTitle());
ListRow listRow = new ListRow(headerItem, row.getAdapter());
rowsAdapter.add(listRow);
}
// Sets this fragments Adapter.
// The setAdapter method is defined in the BrowseFragment of the Leanback Library
setAdapter(rowsAdapter);
setOnItemViewSelectedListener(this);
}
/**
* Fetches now playing movies from TMDB
*/
private void fetchNowPlayingMovies() {
Disposable disposable = mDbAPI.getNowPlayingMovies(Config.API_KEY_URL, mRows.get(NOW_PLAYING).getPage())
.subscribeOn(io.reactivex.schedulers.Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<MovieResponse>() {
#Override
public void accept(MovieResponse response) {
MainFragment.this.bindMovieResponse(response, NOW_PLAYING);
MainFragment.this.startEntranceTransition();
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable e) {
Timber.e(e, "Error fetching now playing movies: %s", e.getMessage());
}
});
compositeDisposable.add(disposable);
}
/**
* Fetches the popular movies from TMDB
*/
private void fetchPopularMovies() {
Disposable disposable = mDbAPI.getPopularMovies(Config.API_KEY_URL, mRows.get(POPULAR).getPage())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<MovieResponse>() {
#Override
public void accept(MovieResponse response) {
MainFragment.this.bindMovieResponse(response, POPULAR);
MainFragment.this.startEntranceTransition();
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable e) {
Timber.e(e, "Error fetching popular movies: %s", e.getMessage());
}
});
compositeDisposable.add(disposable);
}
/**
* Fetches the upcoming movies from TMDB
*/
private void fetchUpcomingMovies() {
Disposable disposable = mDbAPI.getUpcomingMovies(Config.API_KEY_URL, mRows.get(UPCOMING).getPage())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<MovieResponse>() {
#Override
public void accept(MovieResponse response) {
MainFragment.this.bindMovieResponse(response, UPCOMING);
MainFragment.this.startEntranceTransition();
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable e) {
Timber.e(e, "Error fetching upcoming movies: %s", e.getMessage());
}
});
compositeDisposable.add(disposable);
}
/**
* Fetches the top rated movies from TMDB
*/
private void fetchTopRatedMovies() {
Disposable disposable = mDbAPI.getTopRatedMovies(Config.API_KEY_URL, mRows.get(TOP_RATED).getPage())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<MovieResponse>() {
#Override
public void accept(MovieResponse response) {
MainFragment.this.bindMovieResponse(response, TOP_RATED);
MainFragment.this.startEntranceTransition();
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable e) {
Timber.e(e, "Error fetching top rated movies: %s", e.getMessage());
}
});
compositeDisposable.add(disposable);
}
/**
* Binds a movie response to it's adapter
* #param response
* The response from TMDB API
* #param id
* The ID / position of the row
*/
private void bindMovieResponse(MovieResponse response, int id) {
MovieRow row = mRows.get(id);
row.setPage(row.getPage() + 1);
for(Movie m : response.getResults()) {
if (m.getPosterPath() != null) { // Avoid showing movie without posters
row.getAdapter().add(m);
}
}
}
#Override
public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) {
// Check if the item is a movie
if (item instanceof Movie) {
Movie movie = (Movie) item;
// Check if the movie has a backdrop
if(movie.getBackdropPath() != null) {
mBackgroundManager.loadImage(HttpClientModule.BACKDROP_URL + movie.getBackdropPath());
} else {
// If there is no backdrop for the movie we just use a default one
mBackgroundManager.setBackground(ContextCompat.getDrawable(getActivity(), R.drawable.material_bg));
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
compositeDisposable.dispose();
}
}
I saw people had similar problem, but I don't understand what should I do to solve this. If someone could explain me or give me a hint what should I do.

After reviewing the commit that #peterwhy referenced. It seems as if they forgot to update the following dependency in the same HttpClientModule class as well.
To repair, change the following:
#Provides
public TheMovieDbAPI provideFithubApi(#Named("movieDB") Retrofit restAdapter) {
return restAdapter.create(TheMovieDbAPI.class);
}
to
#Provides
public TheMovieDbAPI provideFithubApi(#Named("TVDB") Retrofit restAdapter) {
return restAdapter.create(TheMovieDbAPI.class);
}
in the /dagger/modules/HttpClientModule.java file.

The error message states that there is no module that provides #Named("movieDB") Retrofit restAdapter for your
#Inject
TheMovieDbAPI mDbAPI;
to be injected since this is #Named("movieDB") Retrofit restAdapter it's dependency

Related

How to make NEW Networking Calls in MVVM?

I'm trying to implement pull to refresh with MVVM (and a recyclerview) yet I don't understand how I'm supposed to fetch new data. Inital load up of the app is fine as I'm just observing the livedata from the view model when it's created, but how do I query for more data?
MainActivity.java
package com.example.simplenews;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.example.simplenews.adapters.NewsArticleAdapter;
import com.example.simplenews.adapters.RecyclerItemClickListener;
import com.example.simplenews.models.Article;
import com.example.simplenews.models.NewsResponse;
import com.example.simplenews.repositories.NewsAPI;
import com.example.simplenews.repositories.NewsRepository;
import com.example.simplenews.viewmodels.NewsViewModel;
import com.victor.loading.rotate.RotateLoading;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import timber.log.Timber;
public class MainActivity extends AppCompatActivity {
private RecyclerView newsRecyclerView;
private NewsArticleAdapter newsAdapter;
private NewsAPI NewsAPI;
private ArrayList<Article> newsArticles = new ArrayList<>();
private RotateLoading rotateLoadingIndicator;
private SwipeRefreshLayout swipeRefreshLayout;
private NewsViewModel newsViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Planting timber debug tree here because this joint refuses to work when planted in the application class
Timber.plant(new Timber.DebugTree());
swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout);
newsRecyclerView = findViewById(R.id.newsRecyclerView);
rotateLoadingIndicator = findViewById(R.id.rotate_loading_indicator);
// Getting and setting up the viewmodel
newsViewModel = new ViewModelProvider(this).get(NewsViewModel.class);
newsViewModel.initNewsViewModel();
// Setting up the observer
newsViewModel.getNewsRepositoryQuery().observe(this, newsResponse -> {
ArrayList<Article> freshNewsArticles = (ArrayList<Article>) newsResponse.getArticles();
newsArticles.addAll(freshNewsArticles);
newsAdapter.notifyDataSetChanged();
});
initReyclerView();
// This is not the way to do recyclerview click listeners but this will suffice for now
newsRecyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(this, newsRecyclerView, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
Article article = newsArticles.get(position);
Uri uri = Uri.parse(article.getUrl());
Intent webIntent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(webIntent);
}
#Override
public void onLongItemClick(View view, int position) {
}
})
);
// Configure the refreshing colors
swipeRefreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary));
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
newsViewModel.getNewHeadlines().observe(MainActivity.this, new Observer<NewsResponse>() {
#Override
public void onChanged(NewsResponse newsResponse) {
if (newsResponse.getArticles() != null) {
refreshNewsRecyclerView(newsResponse.getArticles());
swipeRefreshLayout.setRefreshing(false);
}
swipeRefreshLayout.setRefreshing(false);
Timber.d("the articles in the refresh callback were null");
}
});
}
});
}
/*
* Helper method that refreshes topHeadlinesRecyclerView with new articles
* #param: list of new article objects from a network request
* */
private void refreshNewsRecyclerView(List<Article> freshArticles) {
newsRecyclerView.setVisibility(View.INVISIBLE);
showLoadingIndicator();
newsAdapter.clearNewsArticles();
newsAdapter.addAll(freshArticles);
newsRecyclerView.setVisibility(View.VISIBLE);
hideLoadingIndicator();
newsAdapter.notifyDataSetChanged();
}
/*
* Helper method to show the loading indicator
* */
private void showLoadingIndicator() {
rotateLoadingIndicator.setVisibility(View.VISIBLE);
rotateLoadingIndicator.start();
}
/*
* Helper method to hide loading indicator
* */
private void hideLoadingIndicator() {
rotateLoadingIndicator.stop();
rotateLoadingIndicator.setVisibility(View.GONE);
}
/*
* Helper method to setup the recyclerView
* */
private void initReyclerView() {
if (newsAdapter == null) {
showLoadingIndicator();
newsAdapter = new NewsArticleAdapter(newsArticles, this);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
newsRecyclerView.setLayoutManager(layoutManager);
newsRecyclerView.setAdapter(newsAdapter);
hideLoadingIndicator();
} else {
newsAdapter.notifyDataSetChanged();
}
}
}
NewsViewModel
public class NewsViewModel extends ViewModel {
private MutableLiveData<NewsResponse> mutableLiveData;
private NewsRepository newsRepository;
// When a viewmodel object is created fetch the data needed for the activitiy
public void initNewsViewModel() {
if (mutableLiveData != null) {
return;
}
newsRepository = NewsRepository.getInstance();
mutableLiveData = newsRepository.getTopHeadlines();
}
public MutableLiveData<NewsResponse> getNewsRepositoryQuery() {
return mutableLiveData;
}
public MutableLiveData<NewsResponse> getNewHeadlines() {
MutableLiveData<NewsResponse> response = newsRepository.getTopHeadlines();
return response;
}
}
News Repository
public class NewsRepository {
private static NewsRepository newsRepository;
private NewsAPI newsAPI;
private List<Article> freshArticles;
public static NewsRepository getInstance() {
if (newsRepository == null) {
newsRepository = new NewsRepository();
}
return newsRepository;
}
/*
* Private constructor because nobody should be creating this object direcly
* */
private NewsRepository() {
newsAPI = RetrofitClient.getRetrofitInstance().create(NewsAPI.class);
}
public MutableLiveData<NewsResponse> getTopHeadlines() {
MutableLiveData<NewsResponse> topHeadlines = new MutableLiveData<>();
newsAPI.getRootJSONObject().enqueue(new Callback<NewsResponse>() {
#Override
public void onResponse(Call<NewsResponse> call, Response<NewsResponse> response) {
if (response.isSuccessful()) {
topHeadlines.setValue(response.body());
Timber.d("Network call was succesful here is the response code " + response.code());
} else {
Timber.d("Network call was unsuccesful " + response.code());
}
}
#Override
public void onFailure(Call<NewsResponse> call, Throwable t) {
Timber.d("Network call completely failed lol");
topHeadlines.setValue(null);
}
});
return topHeadlines;
}
}
You can simply make a function which reset value of MutableLiveData
For example on swipe call viewmodel.resetNewsHeadlines() and in resetNewsHeadlines() method simple set value to null and recall mutableLiveData = newsRepository.getTopHeadlines(); again

TMDB api trending endpoint call returns a null object

I am making an api call to themoviedb.org api in android using retrofit. I am expecting a json array with a list of movies in the response, however i get a null object reference when i call the getResults method of my POJO class. Kindly assist.
This is the error message i am getting;
2020-01-03 12:28:10.396 20851-20851/com.popularmovies E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.popularmovies, PID: 20851
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.gson.JsonArray com.popularmovies.TrendingPojo.getResults()' on a null object reference
at com.popularmovies.TrendingFragment$1.onResponse(TrendingFragment.java:109)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:71)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7045)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
Here is my api interface
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface TmdbApi {
final String BASE_URL = "https://api.themoviedb.org/4/";
#GET("list/{id}")
Call<CategoryJsonResponse> getMovies(#Path ("id") String id, #Query("api_key") String api_key);
#GET("discover/movie")
Call<DiscoverPOJO> getDiscover(#Query("sort_by") String sort_by,#Query("api_key") String api_key);
#GET("trending/{media_type}/{time_window}")
Call<TrendingPojo> getTrending(#Path("media_type") String media_type, #Path("time_window") String time_window, #Query("api_key") String api_key);
}
my problem is with the trending endpoint.
Below is my POJO class
package com.popularmovies;
import com.google.gson.JsonArray;
public class TrendingPojo {
private int page;
private JsonArray results;
private int total_results;
private int total_pages;
//Default constructor for api calls
public TrendingPojo(int page, JsonArray results, int total_pages, int total_results) {
this.page = page;
this.results = results;
this.total_results = total_results;
this.total_pages = total_pages;
}
public int getPage() {
return page;
}
public JsonArray getResults() {
return results;
}
public int getTotal_results() {
return total_results;
}
public int getTotal_pages() {
return total_pages;
}
public void setPage(int page) {
this.page = page;
}
public void setResults(JsonArray results) {
this.results = results;
}
public void setTotal_results(int total_results) {
this.total_results = total_results;
}
public void setTotal_pages(int total_pages) {
this.total_pages = total_pages;
}
}
Below is the fragment from which i make the api call using retrofit;
package com.popularmovies;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import static com.popularmovies.DiscoverFragment.API_KEY;
public class TrendingFragment extends Fragment implements MovieAdapter.MovieAdapterOnclickHandler {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private View rootView;
private ProgressBar progressBar;
private RecyclerView mRecyclerView;
private MovieAdapter movieAdapter;
private List<Movies> moviez;
public TrendingFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_trending, container, false);
progressBar = rootView.findViewById(R.id.trending_pb);
progressBar.setVisibility(View.VISIBLE);
mRecyclerView = rootView.findViewById(R.id.trending_rv);
GridLayoutManager layoutManager = new GridLayoutManager(rootView.getContext(), 2);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
movieAdapter = new MovieAdapter(this);
mRecyclerView.setAdapter(movieAdapter);
getTrendingResponse();
return rootView;
}
// TODO: Rename method, update argument and hook method into UI event
private void getTrendingResponse(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(TmdbApi.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
TmdbApi tmdbApi = retrofit.create(TmdbApi.class);
Call<TrendingPojo> call = tmdbApi.getTrending("movie","week",API_KEY);
call.enqueue(new Callback<TrendingPojo>() {
#Override
public void onResponse(Call<TrendingPojo> call, Response<TrendingPojo> response) {
TrendingPojo movies = response.body();
JsonArray allmovies;
allmovies = movies.getResults();
if(allmovies!= null){
for(int i = 0; i < allmovies.size(); i++){
Gson gson = new Gson();
Type listType = new TypeToken<Collection<Movies>>(){}.getType();
moviez = gson.fromJson(allmovies, listType);
}
movieAdapter.setData(moviez);
progressBar.setVisibility(View.INVISIBLE);
}
}
#Override
public void onFailure(Call<TrendingPojo> call, Throwable t) {
Toast.makeText(rootView.getContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
#Override
public void onDetach() {
super.onDetach();
}
#Override
public void onClick(int s) {
}
}
Finally here is a link to the api documentation for the trending endpoint.
https://developers.themoviedb.org/3/trending/get-trending
Turns out the problem was I was using a version 4 base URL which returns a 404 error code for some endpoints instead of version 3.
changing
"https://api.themoviedb.org/4/"
to
"https://api.themoviedb.org/3/"
was the solution.

LiveData fails to notify it's observer of changes in PagedList object

I have written this simple example to test paging library and observe changes to PagedList using LiveData but it notifies the observer only once, when the LiveData<PagedList<Integer>> object is created. I load more data using a button in my activity and pagedList object is loaded correctly but changes are not observed. here's the code for my activity:
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.arch.paging.PagedList;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MainViewModel mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);
Button b = findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PagedList<Integer> s = mainViewModel.getIntegers().getValue();
s.loadAround(s.size());
}
});
mainViewModel.setUpPaging(1);
mainViewModel.getIntegers().observe(this, new Observer<PagedList<Integer>>() {
#Override
public void onChanged(#Nullable PagedList<Integer> integers) {
//logging some text
Log.i("MyLog","new list Observed");
}
});
}
}
here's my ViewModel class:
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;
import android.arch.paging.LivePagedListBuilder;
import android.arch.paging.PagedList;
public class MainViewModel extends ViewModel {
LiveData<PagedList<Integer>> integers;
public LiveData<PagedList<Integer>> getIntegers() {
return integers;
}
public void setUpPaging(Integer startFrom){
integers = new LivePagedListBuilder<Integer,Integer>(IntegersDataSource.randomNumbersStartingFrom(startFrom),
new PagedList.Config.Builder()
.setPageSize(5)
.setEnablePlaceholders(false)
.build()).build();
}
}
and here's my DataSource which for simplicity only generate random integers :
import android.arch.paging.DataSource;
import android.arch.paging.PageKeyedDataSource;
import android.support.annotation.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class IntegersDataSource extends PageKeyedDataSource<Integer,Integer> {
private Integer initialInt;
private final Integer BOUND = 300;
public IntegersDataSource(Integer initialInt) {
this.initialInt = initialInt;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l,initialInt-1, initialInt+1);
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l, params.key-1);
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, Integer> callback) {
Random r = new Random();
Integer i = r.nextInt(BOUND - 1) + 1;
List<Integer> l = new ArrayList<>();
l.add(i);
callback.onResult(l, params.key+1);
}
private static class RandomsFactory extends DataSource.Factory{
Integer srartFrom;
public RandomsFactory(Integer startFrom) {
this.srartFrom = startFrom;
}
#Override
public DataSource create() {
return new IntegersDataSource(srartFrom);
}
}
public static DataSource.Factory<Integer, Integer> randomNumbersStartingFrom(Integer startFrom) {
return new RandomsFactory(startFrom);
}
}
and this is in my build gradle :
implementation "android.arch.paging:runtime:1.0.0-rc1"
I keep pushing the button multiple times but only one time it is observed(for creation time).
PagedListAdapter doesn’t reflect changed item itself. To put it another way, PagedList is immutable. you should call invalidate() on the current DataSource when an update occurs. A new PagedList / DataSource pair will be created via LivePagedListBuilder and It will be passed through LiveData to observers when the current DataSource is invalidated.
Try this code.
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PagedList<Integer> s = mainViewModel.getIntegers().getValue();
s.getDataSource().invalidate();
}
});
Please check out this demo app.
https://github.com/jungilhan/cheese-aac-paging-sample/tree/item_based_paging

How do I use dagger inject with Mockito?

I am trying to write unit tests for Android app that uses dagger for ViewModel injection. I don't seem to get injection working for the JUnitTest. Retrofit is returning null call request when I inject the gapiService using #Mock here:
final MutableLiveData<GissuesResponse> lData = new MutableLiveData<>();
Call<List<Issue>> callRequest = gapiService.getIssues(owner, repo);
My whole project is at http://github.com/CodingWords/Gissues
Not sure how to properly setup the ViewModel for injection in JUnitTest. Thanks!
Here is my JUnitTest
import android.arch.lifecycle.ViewModelProvider;
import android.arch.lifecycle.ViewModelProviders;
import com.codingwords.sobrien.gissues.api.GAPIService;
import com.codingwords.sobrien.gissues.model.SearchIssuesModel;
import com.codingwords.sobrien.gissues.repo.IssueRepository;
import com.codingwords.sobrien.gissues.vm.GissuesViewModel;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import javax.inject.Inject;
public class GissuesUnitTest {
#Mock //Mock annotation tells Mockito to give a mocked object
GissuesScreen gissuesScreen;
#Mock
GAPIService gapiService;
//class that is being tested
#Inject
ViewModelProvider.Factory viewModelFactory;
IssueRepository gissuesRepo;
GissuesViewModel gissuesViewModel;
final String dummyOwner = "ethereum";
final String dummyRepo = "solidity";
#Before
public void setupGissuesViewModel(){
//this function will be called before all tests are run
// call this function to init all objects annotated with #mock
MockitoAnnotations.initMocks(this);
gissuesRepo = new IssueRepository();
gissuesRepo.setGapiService(gapiService);
gissuesViewModel = new GissuesViewModel(gissuesRepo);
gissuesViewModel.setGissuesScreen(gissuesScreen);
SearchIssuesModel sim = new SearchIssuesModel();
gissuesViewModel.setSearchModel(sim);
//we create an instance of the class to be tested by passing the mocked objec
}
#Test
public void requestIssuesWithEmptyOwner_showsOwnerError(){
gissuesViewModel.getSearchModel().setOwner("");
gissuesViewModel.pullIssues();
//use mockito to verify that the showOwnerError() method is called in the screen object
Mockito.verify(gissuesScreen).showOwnerError();
}
#Test
public void requestIssuesWithEmptyRepo_showsRepoError(){
gissuesViewModel.getSearchModel().setOwner("ethereum");
gissuesViewModel.getSearchModel().setRepo("");
gissuesViewModel.pullIssues();
Mockito.verify(gissuesScreen).showRepoError();
}
#Test
public void requestIssuesWithEmptyList_showsIssuesNotFound(){
gissuesViewModel.getSearchModel().setOwner("ethereum");
gissuesViewModel.getSearchModel().setRepo("ethereum");
gissuesViewModel.pullIssues();
Mockito.verify(gissuesScreen).showIssuesNotFound();
}
}
Here is IssueRepo
public class IssueRepository implements IssueRepo {
#Inject
public IssueRepository() {
}
#Inject
GAPIService gapiService;
#Override
public LiveData<GissuesResponse> receiveIssues(String owner, String repo) {
final MutableLiveData<GissuesResponse> lData = new MutableLiveData<>();
// callRequest is returned as null because gapiService was mock object?
Call<List<Issue>> callRequest = gapiService.getIssues(owner, repo);
callRequest.enqueue(new Callback<List<Issue>>() {
#Override
public void onResponse(Call<List<Issue>> call, Response<List<Issue>> response) {
lData.setValue(new GissuesResponse(response.body()));
}
#Override
public void onFailure(Call<List<Issue>> call, Throwable t) {
lData.setValue(new GissuesResponse(t));
}
});
return lData;
}
public GAPIService getGapiService() {
return gapiService;
}
public void setGapiService(GAPIService gapiService) {
this.gapiService = gapiService;
}
}
Here is View Model
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MediatorLiveData;
import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;
import com.codingwords.sobrien.gissues.GissuesScreen;
import com.codingwords.sobrien.gissues.entity.GissuesResponse;
import com.codingwords.sobrien.gissues.model.SearchIssuesModel;
import com.codingwords.sobrien.gissues.repo.IssueRepo;
import javax.inject.Inject;
/**
* Created by Administrator on 2/19/2018.
*/
public class GissuesViewModel extends ViewModel {
private IssueRepo issueRepository;
private MediatorLiveData<GissuesResponse> gapiResponse;
private SearchIssuesModel searchModel;
private GissuesScreen gissuesScreen;
#Inject
public GissuesViewModel(IssueRepo repository) {
this.issueRepository = repository;
this.gapiResponse = new MediatorLiveData<GissuesResponse>();
}
public MediatorLiveData<GissuesResponse> getGapiResponse() {
return gapiResponse;
}
public void pullIssues(){
if (getSearchModel() != null){
if ((getSearchModel().getOwner() == null) || (getSearchModel().getOwner().length() < 2)){
gissuesScreen.showOwnerError();
} else if ((getSearchModel().getRepo() == null) || (getSearchModel().getRepo().length() < 2)) {
gissuesScreen.showRepoError();
} else {
pullIssues(getSearchModel().getOwner(), getSearchModel().getRepo());
}
}
}
public void pullIssues(#NonNull String user, String repo) {
LiveData<GissuesResponse> issuesSource = issueRepository.receiveIssues(user, repo);
gapiResponse.addSource(
issuesSource,
gapiResponse -> {
if (this.gapiResponse.hasActiveObservers()) {
this.gapiResponse.removeSource(issuesSource);
}
this.gapiResponse.setValue(gapiResponse);
}
);
}
public SearchIssuesModel getSearchModel() {
return searchModel;
}
public void setSearchModel(SearchIssuesModel searchModel) {
this.searchModel = searchModel;
}
public GissuesScreen getGissuesScreen() {
return gissuesScreen;
}
public void setGissuesScreen(GissuesScreen gissuesScreen) {
this.gissuesScreen = gissuesScreen;
}
}

How to load data from json in expandable listview using retrofit?

I want to load question and answer in expandable listview from json using retrofit library. I dont know how to do this. Find me a solution.
Here is the two model class i am using.
public class QuestionResult {
boolean IsSuccess;
List<QuestionsModel> question;
public boolean isSuccess() {
return IsSuccess;
}
public List<QuestionsModel> getQuestion() {
return question;
}
}
And
public class QuestionsModel {
private int q_id;
private int category_id;
private String question;
private String answer;
public int getQ_id() {
return q_id;
}
public int getCategory_id() {
return category_id;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
Here is my Activity
public class QuestionBank extends AppCompatActivity {
#InjectView(R.id.ques_type_spinner)
Spinner courseSpinner;
#InjectView(R.id.home_btn_qbank)
Button homeButton;
#InjectView(R.id.no_questions)
TextView textView;
#InjectView(R.id.ques_ans_listview)
ExpandableListView listView;
List<String> courseNames;
ArrayAdapter<String> courseAdapter;
ExpandableListAdapter listAdapter;
List<QuestionResult> resultList;
ProgressDialog progress;
int selectedPosition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_question_bank);
ButterKnife.inject(this);
StatusBarTheme.setStatusBarColor(this);
showCourseCategory();
homeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
courseSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedPosition = courseSpinner.getSelectedItemPosition() + 1;
Log.d("cat_id ", " " + selectedPosition);
loadQuestions(selectedPosition);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void loadQuestions(final int selectedPosition) {
ApiInterface apiInterface = ApiClient.getClient(this).create(ApiInterface.class);
Call<QuestionResult> call = apiInterface.loadQuesAndAnswers(selectedPosition);
call.enqueue(new Callback<QuestionResult>() {
#Override
public void onResponse(Call<QuestionResult> call, Response<QuestionResult> response) {
List<QuestionsModel> questionsModelList = response.body().getQuestion();
if (questionsModelList != null) {
listAdapter = new ExpandListAdapter(QuestionBank.this, questionsModelList, selectedPosition);
listView.setAdapter(listAdapter);
} else {
listView.setVisibility(View.GONE);
textView.setVisibility(View.VISIBLE);
}
}
#Override
public void onFailure(Call<QuestionResult> call, Throwable t) {
}
});
}
private void showCourseCategory() {
ApiInterface apiInterface = ApiClient.getClient(this).create(ApiInterface.class);
Call<CategoryResult> call = apiInterface.loadCourseTitle();
progress = new ProgressDialog(QuestionBank.this);
progress.setMessage("Loading.. Please wait");
progress.show();
call.enqueue(new Callback<CategoryResult>() {
#Override
public void onResponse(Call<CategoryResult> call, Response<CategoryResult> response) {
if (progress.isShowing()) {
progress.dismiss();
}
if (response.body().isSuccess() && response.body().getCategory() != null) {
response.body().getCategory();
courseNames = new ArrayList<>();
for (CourseType courseType : response.body().getCategory()) {
courseNames.add(courseType.getCategory_title());
}
loadSpinner(courseNames);
}
}
#Override
public void onFailure(Call<CategoryResult> call, Throwable t) {
}
});
}
private void loadSpinner(List<String> educationTypeList) {
courseAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, educationTypeList);
courseAdapter.setDropDownViewResource(android.R.layout.simple_list_item_checked);
courseSpinner.setAdapter(courseAdapter);
}
}
Here is the complete code. Change it for your purposes. If anything will happen you can write comment i will answer.
Application.class
public class Application extends Application{
private static Application instance;
private I_Requests iWebEndpoint;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static Application i() {
return instance;
}
public I_Requests w() {
if(this.iWebEndpoint == null){
initRetrofit();
}
return iWebEndpoint;
}
private void initRetrofit(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient
.Builder()
.addInterceptor(interceptor)
.readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.connectTimeout(1, TimeUnit.MINUTES)
.build();
client.readTimeoutMillis();
this.iWebEndpoint = new Retrofit.Builder()
.baseUrl(I_Requests.address)
.client(client)
.addConverterFactory(JacksonConverterFactory.create())
.build()
.create(I_Requests.class);
}
}
JacksonConverterFactory.class
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
/**
* A {#linkplain Converter.Factory converter} which uses Jackson.
* <p>
* Because Jackson is so flexible in the types it supports, this converter assumes that it can
* handle all types. If you are mixing JSON serialization with something else (such as protocol
* buffers), you must {#linkplain Retrofit.Builder#addConverterFactory(Converter.Factory) add this
* instance} last to allow the other converters a chance to see their types.
*/
public final class JacksonConverterFactory extends Converter.Factory {
/** Create an instance using a default {#link ObjectMapper} instance for conversion. */
public static JacksonConverterFactory create() {
return create(new ObjectMapper());
}
/** Create an instance using {#code mapper} for conversion. */
public static JacksonConverterFactory create(ObjectMapper mapper) {
return new JacksonConverterFactory(mapper);
}
private final ObjectMapper mapper;
private JacksonConverterFactory(ObjectMapper mapper) {
if (mapper == null) throw new NullPointerException("mapper == null");
this.mapper = mapper;
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
JavaType javaType = mapper.getTypeFactory().constructType(type);
ObjectReader reader = mapper.reader(javaType);
return new JacksonResponseBodyConverter<>(reader);
}
#Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
JavaType javaType = mapper.getTypeFactory().constructType(type);
ObjectWriter writer = mapper.writerWithType(javaType);
return new JacksonRequestBodyConverter<>(writer);
}
}
JacksonRequestBodyConverter.class
import com.fasterxml.jackson.databind.ObjectWriter;
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Converter;
final class JacksonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private final ObjectWriter adapter;
JacksonRequestBodyConverter(ObjectWriter adapter) {
this.adapter = adapter;
}
#Override public RequestBody convert(T value) throws IOException {
byte[] bytes = adapter.writeValueAsBytes(value);
return RequestBody.create(MEDIA_TYPE, bytes);
}
}
JacksonResponseBodyConverter.class
import com.fasterxml.jackson.databind.ObjectReader;
import java.io.IOException;
import okhttp3.ResponseBody;
import retrofit2.Converter;
final class JacksonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final ObjectReader adapter;
JacksonResponseBodyConverter(ObjectReader adapter) {
this.adapter = adapter;
}
#Override public T convert(ResponseBody value) throws IOException {
try {
return adapter.readValue(value.charStream());
} finally {
value.close();
}
}
}
I_Request.interface
import java.util.ArrayList;
import manqaro.com.projectz.ServerSide.Response.TestData;
import manqaro.com.projectz.ServerSide.Response.TestResponse;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
public interface I_Requests {
//PUT HERE YOUR SERVER MAIN ADDRES
String address = "http://goto.xcodes.club";
//SAMPLE EXAMPLE OF POST TYPE , YOU SHOULD CHANGE EVERYTHING YOU WANT.
//IN THIS EXAMPLE YOU WILL GET JSON DATA WHICH WILL BE CONVERTED TO JAVA OBJECT.
#FormUrlEncoded
//Here YOU HAVE TO GIVE ADDRESS TO SPECIFIC CALL
#GET("/api/v1/objects/")
Call<TestResponse<ArrayList<TestData>>> login(
);
#FormUrlEncoded
#POST("/api/v1/objects/")
Call<TestResponse<ArrayList<TestData>>> register(
);
}
TestResponse.class
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by ArsenSench on 11/9/2016.
*/
public class TestResponse<T> {
#JsonProperty("status")
public int status;
#JsonProperty("message")
public String message;
#JsonProperty("data")
public T data;
}
TestData.class
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Created by ArsenSench on 11/9/2016.
*/
public class TestData extends {
#JsonProperty("id")
public int id;
#JsonProperty("name")
public String name;
#JsonProperty("description")
public String description;
#JsonProperty("avatar")
public String avatar;
#JsonProperty("rate")
public int rate;
}
ServerCalls.class
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import manqaro.com.projectz.ServerSide.Application.Tickle_Application;
import manqaro.com.projectz.ServerSide.Response.TestData;
import manqaro.com.projectz.ServerSide.Response.TestResponse;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by ArsenSench on 11/9/2016.
*/
public class ServerCalls {
Context context;
public ServerCalls(Context context){
this.context = context;
}
public void testCallBack(){
Tickle_Application.i().w().login().enqueue(new Callback<TestResponse<ArrayList<TestData>>>() {
#Override
public void onResponse(Call<TestResponse<ArrayList<TestData>>> call, Response<TestResponse<ArrayList<TestData>>> response) {
if(response.code()==200){
if(response.body().status==200){
Toast.makeText(context, response.body().data.get(0).name, Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(context, "No Name", Toast.LENGTH_SHORT).show();
}
}
else{
Toast.makeText(context, "No Connection", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<TestResponse<ArrayList<TestData>>> call, Throwable t) {
Toast.makeText(context, t.getCause().getMessage(), Toast.LENGTH_SHORT).show();
Log.e("jex", "onFailure: " + t.getCause().getMessage() );
}
});
}
}
TestActivity.activity
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import manqaro.com.projectz.R;
import manqaro.com.projectz.ServerSide.Main.ServerCalls;
public class TestActivity extends AppCompatActivity {
ServerCalls sc = new ServerCalls(this);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
}
public void clickThatShit(View view){
sc.testCallBack();
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="your.package.name">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".Application"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:replace="android:icon">
<activity
android:name=".TestActivity">
</activity>
</application>
</manifest>
build.gradle(module app)
Include these dependencies in yourdependencies
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
compile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
compile 'com.fasterxml.jackson.core:jackson-annotations:2.7.3'
Include this lines in your android{} block
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
}

Categories

Resources