I want to get notifications from a server using API. I'm using Retrofit2 to work with API.
The problem is when I'm passing parameter in POST method I'm getting "IllegalArgumentException URL does not contain the parameter."
The parameter is correct and working in iOS. I want to implement in android.
Below is the result when debugging the app.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
I've tried changing parameters and asked the API developer too. He says parameter is correct.
This is code for API Interface:
public interface API{
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
RetrofitClient.java
public class RetrofitClient {
public static final String BASE_URL = "http://danceglobe.co/dance/api/";
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance(){
if(mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public API getApi(){
return retrofit.create(API.class);
}
}
Calling Function from MainActivity
private void getNotification(String currentUserId) {
Call<ResponseBody> call = RetrofitClient.getInstance().getApi().getUserNotification(Integer.parseInt(currentUserId));
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(!response.isSuccessful()){
Toast.makeText(MainActivity.this,response.message(),Toast.LENGTH_SHORT).show();
}
try {
String s = response.body().string();
Toast.makeText(MainActivity.this,s,Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(MainActivity.this,t.getMessage(),Toast.LENGTH_SHORT).show();
}
});
}
I want it to respond to some data.
Please help me. I got stuck into this from past 2 days.
Caused by: java.lang.IllegalArgumentException: URL
"notification/newnotification" does not contain "{userid}". (parameter #1)
means you should add the userId to the path like
public interface API {
#POST("notification/newnotification/{userid}")
Call<ResponseBody> getUserNotification(
#Path("userid") int userid
);
}
#Path("userid") maps the variable to the placeholder {userid}, that was missing.
I got it working by making some changes in API interface.
Below is new Code for API interface
#FormUrlEncoded
#POST("notification/newnotification")
Call<ResponseBody> getUserNotification(
#Field("userid") String userid // changed line
);
Related
I passing TranID from using GET method. I have a problem for API call , please give some example API calls. http://testing.ppms.co.in/Redipae/Payout/Approvemercsmspwalink?TranID=20
{
"result": true,
"newurl": "/Redipae/Payout/mercpushsmslink"
}
Retrofit client defined below
public class API {
public static Retrofit getClient() {
return new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl(" http://testing.ppms.co.in/").client(new OkHttpClient.Builder().connectTimeout(120, TimeUnit.SECONDS).writeTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS).build();
}
}
You need an interface for the API
public interface RequestServer {
#GET("Redipae/Payout/Approvemercsmspwalink")
Call<ResponseBody> getResponse(#Query("TranID") int transId);
}
Finally, call it like this
RequestServer requestServer = API .getClient().create(RequestServer.class);
requestServer.getResponse(20).enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(#NonNull Call<ResponseBody> call, #NonNull Response<ResponseBody> response) {
// do something with the data here
}
#Override
public void onFailure(#NonNull Call<ResponseBody> call, #NonNull Throwable t) {
// check the error and inform the user about it
}
});
I'm trying to get the data I parse from onResponse method via Callback. Here is my ApiClient:
public class ApiClient implements Callback<Map<String, Channel>> {
private ChannelCallback listener;
static final String BASE_URL = "https://www.radyoodtu.com.tr/";
public void start(ChannelCallback listener) {
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RestInterface restInterface = retrofit.create(RestInterface.class);
Call<Map<String, Channel>> call = restInterface.getChannels();
call.enqueue(this);
}
#Override
public void onResponse(retrofit2.Call<Map<String, Channel>> call, Response<Map<String, Channel>> response) {
System.out.println(response.code());
if(response.isSuccessful()) {
Map<String, Channel> body = response.body();
listener.setChannels(body);
List<Channel> channels = new ArrayList<>(body.values());
for (Channel channel : body.values()) {
System.out.println(channel.getSong());
}
}
}
#Override
public void onFailure(retrofit2.Call<Map<String, Channel>> call, Throwable t) {
//TODO
}
}
and this is the class I'm trying to get the data:
public class Radio implements ChannelCallback {
private ApiClient apiClient = new ApiClient();
public Radio(){
apiClient.start(this);
}
#Override
public void setChannels(Map<String, Channel> body) {
this.apiClient.onResponse(body); // NOT WORKING
}
}
here is my Interface:
public interface ChannelCallback {
void setChannels(Map<String, Channel> body);
}
what I need to do is get the onResponse body data for Radio class I'm using right now. In Radio class I have to create a List of channel objects with that data I need but I can't even get the data so I can't even create that list. I don't know how to manipulate the data from listener at all and I don't know how can I access that listener I use in ApiClient in Radio class.
It looks like you've got a cyclic reference here. Radio calls ApiClient start, which triggers the network request, which calls Radio.setChannels, which tries to call the client again.
I think you need to resolve two things:
Avoid this cyclic reference
You pass the listener to ApiClient.start() but you never assign it to the actual value inside ApiClient. So, my guess is that you get an NPE here if you have a successful response.
//i think no need to impliments ChannelCallback if this code works
//just asign your interface and apiclient in class
public class Radio implements ChannelCallback {
private ApiClient apiClient = new ApiClient();
private ChannelCallback channelCallback;
and in inside radio()
public Radio(){
apiClient.start(this);
channelCallback = apiClient.onResponse(body).create(ChannelCallback.class);
channelCallback.setChannels(Map<String, Channel> body)
}
//and recieve callback
}
I begin with android dev and retrofit.
My app uses datas from a mysql/apache server. All work fine with retrofit.
But, I would like to add a dummy function in the app, with a accountId == 0 (so no login), which uses datas hard coded in the app, and not on the server.
So, I'd like to modify the call, to use MY class/method if accountID == 0 AND returning the same type of result in the same callbaks as retrofit.
I try to show you with code :
MyService.java
interface MyService {
#GET("get.php")
Call<List<MyObject>> getAll(#Query("a") int accountid);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Consts.URL_SERVER)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
MyCalls.java
public class MyCalls {
public interface CallbacksAll {
void onResponse(#Nullable List<MyObject> myobjetcs);
void onFailure();
}
public static void getAll(CallbacksAll callbacks, int accountId) {
final WeakReference<CallbacksAll> callbacksWeakReference = new WeakReference<>(callbacks);
///////////////////
// actually :
///////////////////
MyService myService = MyService.retrofit.create(MyService.class);
Call<List<MyObject>> call = myService.getAllByAccount(accountId);
///////////////////
// end actually
///////////////////
///////////////////
// what I'ld like
///////////////////
MyService myService;
Call<List<MyObject>> call;
if ( accountId > 0 ) {
myService = MyService.retrofit.create(MyService.class);
call = myService.getAll(accountId);
} else {
myService = ??? // I don't really know what to create and do here
call = MyClass.getAll(); // my class/method nevermind
}
///////////////////
// end what I'd like
///////////////////
///////////////////
// what I'd like to NOT change
///////////////////
call.enqueue(new Callback<List<MyObject>>() {
#Override
public void onResponse(#NonNull Call<List<MyObject>> call, #NonNull Response<List<MyObject>> response) {
if (callbacksWeakReference.get() != null)
callbacksWeakReference.get().onResponse(response.body());
}
#Override
public void onFailure(#NonNull Call<List<MyObject>> call, #NonNull Throwable t) {
if (callbacksWeakReference.get() != null) callbacksWeakReference.get().onFailure();
}
});
}
I hope you will understand my poor english and what I want, and you will be able to give me ideas with simple examples.
Thanks
Not enough rep to comment, so I put my solution here.
So much time spent although the solution was so simple.
I just had to add :
if (accountId == 0) {
callbacks.onResponse(MyObject.getAll());
} else {
final WeakReference<CallbacksAll> callbacksWeakReference = new WeakReference<>(callbacks);
[...]
});
}
in
public static void getAll(CallbacksAll callbacks, int accountId) {
Have been having issue using Rxjava with Retrofit in my android app, everything seems ok and fine in the code implementation but app crashes whenever i navigate to the activity/fragment with the error message below.
//Error message
java.lang.IllegalArgumentException: Unable to create converter for java.util.List<com.thebestprice.bestprice.model.SearchRequestModel>
for method DataEndpointService.getStarredRepositories
//Endpoint Declaration
#GET("users/{user}/starred")
Observable<List<SearchRequestModel>> getStarredRepositories(#Path("user") String username);
//Client Class
public class DataClient {
private static final String PROJECT_BASE_URL = "https://api.github.com/";
private static DataClient instance;
private DataEndpointService queryResultService;
private DataClient(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
final Retrofit retrofit = new Retrofit.Builder().baseUrl(PROJECT_BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
queryResultService = retrofit.create(DataEndpointService.class);
}
public static DataClient getInstance(){
if (instance == null){
instance = new DataClient();
}
return instance;
}
public io.reactivex.Observable<List<SearchRequestModel>> queryForUserRepo(#NonNull String searchRequestModel){
return queryResultService.getStarredRepositories(searchRequestModel);
}
}
//Fragment to display the list
private void queryResultForSearchData(String userName){
disposable = DataClient.getInstance().
queryForUserRepo(userName).
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Consumer<List<SearchRequestModel>>() {
#Override
public void accept(List<SearchRequestModel> searchRequestModels) throws Exception {
mShimmerFrameLayout.stopShimmerAnimation();
rvAllSearch.setAdapter(new ResultAdapter(getActivity(), searchRequestModels));
}
},
new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
}`enter code here`
});
}
//gradle dependencies for rxjava and retrofit with compileSdk27
//For using RxJava
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.1.12'
//logging interceptor
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
//For Using retrofit to do network request
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0'
Don't know what i'm doing wrong, have search for similar issues but doesn't seems to help in my own case
Main point of using RxJava it's avoid loops and list, to invoke Subscriptions and map functions, cause Observables managed all items. So you don't neet to return List.
Just one of example of using Github API with Rx.
public interface GithubService {
String SERVICE_ENDPOINT = "https://api.github.com";
#GET("/users/{login}")
Observable<Github> getUserRx(#Path("login") String login);
#GET("/users/{login}")
Github getUser(#Path("login") String login);
}
.
public class ServiceFactory {
/**
* Creates a retrofit service from an arbitrary class (clazz)
* #param clazz Java interface of the retrofit service
* #param endPoint REST endpoint url
* #return retrofit service with defined endpoint
*/
public static <T> T createRetrofitService(final Class<T> tClass, final String endPoint) {
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(endPoint)
.build();
T service = restAdapter.create(tClass);
return service;
}
}
.
// .....
service = ServiceFactory.createRetrofitService(
GithubService.class, GithubService.SERVICE_ENDPOINT);
service.getUserRx(login)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.cache()
.subscribe(new Subscriber<Github>() {
#Override
public final void onCompleted() {
}
#Override
public final void onError(Throwable e) {
Log.e(LOG, " ErrorRx Default Github" + e.getMessage());
}
#Override
public final void onNext(Github response) {
mCardAdapter.addData(response);
}
});
// .....
As you add GsonConverterFactory.
Check out the Bean you use (SearchRequestModel) the variable or the #SerializedName(alternate) annotation does not have the same variable name.
it work for me
I wanted to refactor code for simplicity and readability and that's why I want to move the code outside the class and return a result to class whenever the method is called.
Trying:
ArrayList<MovieReview> movieReview;
public ArrayList<MovieReview> getReviews(String id) {
if (NetworkUtil.isNetworkConnected(getActivity())) {
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<MovieReviewResponse> call = null;
call = apiService.getMovieReviews(id, BuildConfig.THE_MOVIE_DB_API_KEY);
call.enqueue(new Callback<MovieReviewResponse>() {
#Override
public void onResponse(Call<MovieReviewResponse> call, Response<MovieReviewResponse> response) {
movieReview= (ArrayList<MovieReview>) response.body().getMovieReviews();
}
#Override
public void onFailure(Call<MovieReviewResponse> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
return movieReview;
}
Output: if I used array list outside the on response gives null value.
but if I called a method from on response and pass the result movieReview, as a parameter, it works fine.
Previously used:
public void getReviews(String id) {
if (NetworkUtil.isNetworkConnected(getActivity())) {
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<MovieReviewResponse> call = null;
call = apiService.getMovieReviews(id, BuildConfig.THE_MOVIE_DB_API_KEY);
call.enqueue(new Callback<MovieReviewResponse>() {
#Override
public void onResponse(Call<MovieReviewResponse> call, Response<MovieReviewResponse> response) {
movieReview = (ArrayList<MovieReview>) response.body().getMovieReviews();
setData(movieReview);
}
#Override
public void onFailure(Call<MovieReviewResponse> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
}`
Output: if I used array list outside the on response gives null value
Because that is how asyncronus methods work. Your return happens before onResponse ever happens, so the list object is null.
Tip: In ideal situations, you want to always return an empty list, not null anyway.
Rename your method.
public ArrayList<MovieReview> getReviews(String id)
To Instead
public ArrayList<MovieReview> getReviews(String id, Callback<MovieReviewResponse> callback)
Replace this code
call.enqueue(new Callback<MovieReviewResponse>() {
...
});
With this
call.enqueue(callback);
Wherever you call that method
// In Activity
String id = "X";
api.getReviews(id);
Now do....
// In Activity
String id = "X";
api.getReviews(id, new Callback<MovieReviewResponse>() {
...
});
And now from within onResponse, you can update a ListView adapter, or whatever you need to do
Instead of using only Retrofit make use of RxAndroid. By using this you will get response of Observable<T> which consists of three Override methods onCompleted(), onError() and onNext().
In onNext() method call your specific activity, pass your data through putExtra and get through getExtra.