How to use the #GET method to make API call? - android

I'm trying to make a call to youtube data API to retrieve the subscriber count of a particular channel. But I don't know how to implement the API interface and define the endpoints so I pasted my whole remaining URL in the #GET method. But my app is crashing when started.
My complete URL is: https://www.googleapis.com/youtube/v3/channels?part=statistics&id=+UC-lHJZR3Gqxm24_Vd_AJ5Yw&key=AIzaSyAyON6YdgkFrtNHrGGs3IFS4groadJhhts
Here is my interface :
public interface ApiInterface
{
#GET("/channels?part=statistics&id=+UC-lHJZR3Gqxm24_Vd_AJ5Yw&key=AIzaSyAyON6YdgkFrtNHrGGs3IFS4groadJhhts")
Call<Mainjson> getMainJson();
}
Main Activity :
public class MainActivity extends AppCompatActivity
{
private Statistics statistics;
private String subscribers;
private TextView subscribersPreview;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
subscribersPreview=(TextView) findViewById(R.id.textView3);
ApiInterface service = ApiClient.getClient().create(ApiInterface.class);
Call<Mainjson> call = service.getMainJson();
call.enqueue(new Callback<Mainjson>() {
#Override
public void onResponse(Call<Mainjson> call, Response<Mainjson> response) {
List<Items> items = response.body().getItems();
statistics=items.get(0).getStatistics();
subscribers=statistics.getSubscriberCount();
subscribersPreview.setText(subscribers);
}
#Override
public void onFailure(Call<Mainjson> call, Throwable t) {
Toast.makeText(MainActivity.this,"Failed to retrieve data",Toast.LENGTH_SHORT).show();
}
});
}
}
The retrofit instance :
public class ApiClient {
public static final String BASE_URL = "https://www.googleapis.com/youtube/v3";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}

problem with BASE_URL.
BASE_URL should be end with / and remove / on start of interface method.
public static final String BASE_URL = "https://www.googleapis.com/youtube/v3/";
#GET("channels?part=statistics&id=+UC-lHJZR3Gqxm24_Vd_AJ5Yw&key=AIzaSyAyON6YdgkFrtNHrGGs3IFS4groadJhhts")
Call<Mainjson> getMainJson();

Easiest and fast way to implement use Android Fast networking use this:-
Android Fast networking

Related

What can be a good way to call network class other than an activity in android?

I have created a network client app (using Retrofit) where I call for network request and response in the activity. I learned that it is a bad practice. If anyone can suggest that what can be a good design pattern that I can follow to do such an operation?
For Start if you have to create an app from scratch, possibly try to follow one architecture since you are looking for network calls,
You can Use MVVM for best practice and it also handle the api request in best way possible As you can see from figure,
This architecture, basically separates the view(UI) from view Model(logic of view)
It's up to you how you want to develop the app, means you can skip the repository and handle the network calls in view models or else you can create a single repository class and place all the network related stuffs i.e: network call and similar stuff.
reference tutorial : https://learntodroid.com/consuming-a-rest-api-using-retrofit2-with-the-mvvm-pattern-in-android/
Create a RetrofitClient Class like this
public class RetrofitClient {
public static final String BASE_URL = "YOUR BASE URL HERE";
public static RetrofitClient mInstance;
private Retrofit retrofit;
public static RetrofitClient getInstance() {
if (mInstance == null)
mInstance = new RetrofitClient();
return mInstance;
}
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public ApiInterface getApiInterface() {
return retrofit.create(ApiInterface.class);
}
public interface ApiInterface {
#GET("api_name_here")
Call<ResponseBody> methodName();
}
}
Repository class
public class MyRepository {
private static MyRepository mInstance;
public static MyRepository getInstance() {
if (mInstance == null)
mInstance = new MyRepository();
return mInstance;
}
private MyRepository(){
}
private LiveData<T> getData(){
MutableLiveData<T> liveData = new MutableLiveData<>();
RetrofitClient.getInstance()
.getApiInterface()
.methodName()
.enqueue(new Callback<T>() {
#Override
public void onResponse(#NonNull Call<T> call, #NonNull Response<T> response) {
liveData.setValue(response.body());
}
#Override
public void onFailure(#NonNull Call<T> call, #NonNull Throwable t) {
// handleFailure
}
});
return liveData;
}
}
ViewModel Class
public class MyViewModel extends ViewModel{
private MyRepository myRepository;
public MyViewModel(){
myRepository = MyRepository.getInstance();
}
public LiveData<T> getData(){
return myRepository.getData();
}
}
Then in your Activity or fragment
MyViewModel myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
myViewModel.getData().observe(this, new Observer<T>() {
#Override
public void onChanged(T t) {
// handle your data here...
}
});

Retrofit2/GSON cannot convert to object

I'm making requets to Google Books API with Retrofit2 and use GSON converter, but have an error
ErrorExpected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path
$
API URL to JSON
This is my
BookService.java
public class BookService{
private static final String BASE_URL = "https://www.googleapis.com/";
private BookApiService mApiService;
private BookCallback mListener;
public BookService(BookCallback listener){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
mApiService = retrofit.create(BookApiService.class);
mListener = listener;
}
public void getBooks(String query){
final ApiResponse apiResponse = new ApiResponse();
Call<List<Book>> call = mApiService.getBooks(query);
call.enqueue(new Callback<List<Book>>() {
#Override
public void onResponse(Call<List<Book>> call, Response<List<Book>> response) {
apiResponse.setBooks(response.body());
mListener.notifyDataReceived(apiResponse);
}
#Override
public void onFailure(Call<List<Book>> call, Throwable t) {
apiResponse.setError(t);
mListener.notifyDataReceived(apiResponse);
}
});
}
public interface BookCallback{
void notifyDataReceived(ApiResponse apiResponse);
}
}
and my Interface
BookApiService.java
public interface BookApiService {
#GET("/books/v1/volumes")
Call<List<Book>> getBooks(#Query("q") String query);
}
Then making request from MainActivity.java that implements BookCallback
public class MainActivity extends AppCompatActivity implements BookService.BookCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
new BookService(this).getBooks("android");
}
}
Your response is not an array. its an object with array in it.
For fix this you must create other response class like BookResponse
BookResponse.java
public class BookResponse{
#SerializedName("kind")
private Sting kind;
#SerializedName("totalItems")
private Int totalItems;
#SerializedName("items")
private List<Book> items;
}
And change your interface like this
public interface BookApiService {
#GET("/books/v1/volumes")
Call<BookResponse> getBooks(#Query("q") String query);
}
The response you are having is not an array of Books, but it is an object, which perhaps is a response that has an array with books. So what the error says: Your JsonResponse is not starting with [] but is starting with {}

Android - How to use viewmodel for handling http call in OnCreate which doesn't get called on screen rotation?

. Get stuck with a basic scenario of loading the data in oncreate of an activity. So I am trying to load the data as soon as i open my activity but when i change the screen orientation it gets called again.
below is my rest client for retrofit
public class MyRestApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).connectTimeout(30,TimeUnit.SECONDS).readTimeout(30,TimeUnit.SECONDS).build();
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
retrofit = new Retrofit.Builder()
.baseUrl("http://localhost:8080/rest/")
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
return retrofit;
}
}
below is my resturl interface for loading the data
public interface MyRestUrlInterface {
#GET("user/{user_id}")
Call<Object> getData(#Path("user_id") String user_id);
}
below is my viewmodel class:
public class MyViewModelObserver extends ViewModel {
private MutableLiveData<Object> httpCallBackObserver;
public MutableLiveData<Object> getHttpCallBackObserver() {
if (httpCallBackObserver == null) {
httpCallBackObserver = new MutableLiveData<Object>();
}
return httpCallBackObserver;
}
}
below is my Activity code :
public class MyActivity extends AppCompatActivity {
private static final String TAG = "MyActivity" ;
MyRestUrlInterface restUrlInterface;
public MyViewModelObserver myViewModelObserver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
restUrlInterface = MyRestApiClient.getClient().create(MyRestUrlInterface.class);
myViewModelObserver = ViewModelProviders.of(this).get(MyViewModelObserver.class);
myViewModelObserver.getHttpCallBackObserver().observe(this, getData());
//load data via http
Call<Object> call = restUrlInterface.getData("123");
call.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
myViewModelObserver.getHttpCallBackObserver().setValue(response.body());
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
}
});
}
private Observer<Object> getData(){
return new Observer<Object>() {
#Override
public void onChanged(#Nullable final Object responseString) {
Log.d(TAG,"***** Loaded Data --- "+responseString);
}
};
}
}
How to use view model so that it wont make http call again in screen orientation change
suggested answer:
public class MyViewModelObserver extends ViewModel {
private MutableLiveData<Object> httpCallBackObserver;
public MutableLiveData<Object> getHttpCallBackObserver() {
if (httpCallBackObserver == null) {
httpCallBackObserver = new MutableLiveData<Object>();
loadData();
}
return httpCallBackObserver;
}
private void loadData(){
Call<Object> call = restUrlInterface.getData("123");
call.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
myViewModelObserver.getHttpCallBackObserver().setValue(response.body());
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
}
});
}
}

Retrofit getting data from web throws null object reference

I'm trying to get data from web api but something is wrong and I can't figure it out.
My JSON looks like this
{
"partners":
[
"partner1",
"partner2",
"partner3",
... ,
"partner150"
]
}
I have Table partners (ActiveAndroid) in which I would like to save all partners from api.
#Table(name = "Partners")
public class Partners extends Model {
#Column(name = "Name")
String name;
public Partners() {}
public Partners(String name) {
this.name = name;
}
}
Here is my Pojo model class:
public class Partners extends ArrayList<String> {
#SerializedName("partners")
#Expose
public List<String> partners = new ArrayList<String>();
public List<String> getPartners() {
return partners;
}
public void setName(List<String> partners) {
this.partners = partners;
}
}
This is my interface
public interface APIService {
#GET("Partners")
Call<Partners> getPartners();
}
This is my APIHelper class
public class APIHelper {
public static final String PARTNERS_URL = "https://part-of-link.com/partners.json/";
public static APIService apiService;
public static APIService getApiService() {
if (apiService == null) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(PARTNERS_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
apiService = retrofit.create(APIService.class);
}
return apiService;
}
}
And this is Fragment where I have an Button on which I would like to implement onClick method to get data from API and save it into Partners table.
public class DownloadMain extends Fragment implements Callback<Partners> {
private Button dloadPartners;
private Call<Partners> callPartners;
public static APIService apiService;
public DownloadMain() {}
public DownloadMain newInstance() { return new DownloadMain(); }
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.download_main, container, false);
dloadPartners = (Button) view.findViewById(R.id.downloadPartners);
dloadPartners.setOnClickListener(btnListener);
callPartners = APIHelper.getApiService().getPartners();
callPartners.enqueue(this);
return view;
}
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
APIHelper helper = new APIHelper();
apiService = helper.getApiService();
Call<Partners> call = apiService.getPartners();
call.enqueue(new Callback<Partners>() {
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
APIHelper helper = new APIHelper();
helper.getApiService();
Call<Partners> call = apiService.getPartners();
call.enqueue(new Callback<Partners>() {
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
List<String> partners = response.body().getPartners();
Log.d(TAG, "Number of partners received: " + partners.size());
/*if (response.body() != null) {
ArrayList<String> partnersList;
partnersList = response.body();
Log.d("DOWNLOAD", String.valueOf(partnersList));
}*/
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
Toast.makeText(getActivity(), "FAIL!!!", Toast.LENGTH_SHORT).show();
}
});
}
});
#Override
public void onResponse(Call<Partners> call, Response<Partners> response) {
}
#Override
public void onFailure(Call<Partners> call, Throwable t) {
}
}
And here is my problem. Everything works and there is no errors but when I click on button nothing happens.
So I presume I've made some mistake but I can't figure it out (First time doing with retrofit).
What I want on button click is to get all partners from web and save it into my Partners table.
Question: Could somebody guide me and tell me what is wrong and help me to fix this?
EDIT:
Button.OnClickListener btnListener = (new View.OnClickListener() {
#Override
public void onClick(View v) {
APIHelper helper = new APIHelper();
apiService = helper.getApiService();
Call<ArrayList<String>> call = null;
call.enqueue(new Callback<ArrayList<String>>() {
#Override
public void onResponse(Call<ArrayList<String>> call, Response<ArrayList<String>> response) {
ArrayList<String> partners = response.body();
Log.d(TAG, "Number of partners received: " + partners.size());
}
#Override
public void onFailure(Call<ArrayList<String>> call, Throwable t) {
Toast.makeText(getActivity(), "FAIL!!!", Toast.LENGTH_SHORT).show();
}
});
}
});
Error logs:
Error:(68, 60) error: is not abstract and does not
override abstract method
onResponse(Call>,Response>) in
Callback
Error:(72, 53) error: cannot find symbol method body()
Error:(69, 17) error: method does not override or implement a method
from a supertype
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
your problem is here in the onClick()
helper.getApiService();
you did not assign the service into the variable
change it to this:
apiService = helper.getApiService();
EDIT:
based on new updates i think you dont need to use a POJO
just use the following in your Call
Call<ArrayList<String>>
and to get response just use response.body() without .partners() .
try to replace it everywhere in your code and check
Based on your JSON response, your POJO class should be:
public class Partners {
private ArrayList<String> partners = new ArrayList<>(0);
// Get; Set methods //
}
Try putting this in your APIHelper class to get more information about what you are sending
public static APIService apiService;
//this http loggin interceptor allows you debug requests and responses
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging); // <-- this is the important line!
public static APIService getApiService() {
if (apiService == null) {
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
}
return apiService;
}
Maybe you are sending information in a wrong way...
And remember that in server side you must decode the information that receive (with json_decode).

Getting error while using Retrofit and Rxjava

I am trying to implement RxJava and Retrofit2. But I am getting this error java.lang.IllegalArgumentException: Unable to create call adapter for rx.Observable
Here is my code :-
MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bFetch = (Button) findViewById(R.id.button_fetch);
assert bFetch != null;
bFetch.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
GithubService service;
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GithubService.SERVICE_ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(GithubService.class);
Observable<Github> observable = service.getUser("writingminds");
observable.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Github>() {
#Override
public final void onCompleted() {
// do nothing
}
#Override
public final void onError(Throwable e) {
Log.e("GithubDemo", e.getMessage());
}
#Override
public final void onNext(Github response) {
Log.e("---%s", response.getBlog());
Log.e("--%s", response.getLogin());
}
});
}
});
}
}
And here is my Interface GithubService
public interface GithubService {
String SERVICE_ENDPOINT = "https://api.github.com";
#GET("/users/{login}")
Observable<Github> getUser(#Path("login") String login);
}
Here is my model :
public class Github {
private String login;
private String blog;
private int public_repos;
public String getLogin() {
return login;
}
public String getBlog() {
return blog;
}
public int getPublicRepos() {
return public_repos;
}
}
Thank you in advance
you need to tell Retrofit, you want to use RxJava. You can do it using
addCallAdapterFactory(RxJavaCallAdapterFactory.create())
E.g
final Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GithubService.SERVICE_ENDPOINT)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
you will have to add
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
to your build.gradle dependency list, if you didn't it already

Categories

Resources