how to send post request to retrofit server every 10 minutes? - java

I really need help!
I have a server that sends me predicting time. I need to send request to the server every 10 minutes(even if the app closed) and ask the current time. if the time changed I need to make a notification to the client.
the stop trigger is if the predicting time is now.
so - I have ClientActivity and I have the code to communicate the server.
How can I do that?
Thanks a lot!
public interface APIClient {
#POST("/api/post_some_data")
Call<PostResponse> getPostRequest(#Body PostRequest body);
}
public class NetworkClient {
public static final String BASE_URL = "http://*****:8080";
public static Retrofit retrofit;
/*
This public static method will return Retrofit client
anywhere in the appplication
*/
public static Retrofit getRetrofitClient() {
//If condition to ensure we don't create multiple retrofit instances in a single application
if (retrofit == null) {
//Defining the Retrofit using Builder
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL) //This is the only mandatory call on Builder object.
.addConverterFactory(GsonConverterFactory.create()) // Convertor library used to convert response into POJO
.build();
}
return retrofit;
}
}

Related

Why does my retrofit always get the query with old tokens?

In my app I use Retrofit2 with a service to collect data on eBay. For this I need a token that is valid for 2 hours.
If I start the query, the token is taken over from my database and works. If the 2 hours have expired, the token will be re-entered in the database. But when the data is picked up again on Ebay, I get an error 401 - unauthorized access. I use a MainActivity and invite the fragments there. As soon as I restart the app, everything works again. I suspect that the service does not update the token when query and use the old token. How can I end the service or query and start with the new token? What could be the problem?
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null) {
String auth = "Bearer " + token;
String cont = "application/json";
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.addInterceptor(chain -> {
Request request = chain.request().newBuilder()
.addHeader("Authorization", auth)
.addHeader("Content-Type", cont)
.build();
return chain.proceed(request);
});
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient.build())
.build();
}
return retrofit;
}
When picking up the token from the database, according to log, the current token is always read out. But the feedback from eBay is always the 401 error.
Edit: The OkHttp connection keeps the token. Since the same address is called up, the previous connection with the old token is used. How can I replace/replace the token?
Your method has the below logic:
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null) {
// ...
}
return retrofit;
}
Because retrofit is defined as static it will keep its given value from the moment it's first assigned / even without the static keyword it would keep that value for the duration of the instantiated object's lifetime.
The first time getClient is called the value is null, so the logic in the if block is run & the retrofit gets defined with an Authorization header which includes the given token value.
However, subsequent calls to getClient will see that retrofit is already assigned, so will just return it; regardless of what parameters were sent to the method (i.e. even if there's a new token), and as the variable is static this will be true even if you've created a new instance of your RetrofitClient.
There are various solutions:
Remove the if statement so that the logic within it is run every time. This will incur some performance overhead (i.e. as you're having to do work for every request, even if the baseUrl and token values are the same as previously), but will return a Retrofit instance with the correct values every time. If doing this, you may not need the private static Retrofit retrofit = null; line at all; as the value is created and returned entirely within your getClient method; so making the value accessible outside of this context just adds risk.
Remove the static keyword and create a new instance of the RetrofitClient class for each new baseUrl + token value (i.e. each time your token expires). This may require additional refactoring, as you'll then require an instance of your class to access the getClient method.
Add code such as below, to check if the values are different to previous requests and update retrofit only when required. E.g.
private static Retrofit retrofit = null;
private static String baseUrlCached = null;
private static String tokenCached = null;
public static Retrofit getClient(String baseUrl, String token) {
if (retrofit == null || (baseUrl != baseUrlCached || token != tokenCached)) {
// ...
}
return retrofit;
}

Can not get response from 000webhost using Retrofit in Android Studio

I am new to Android, i have a file named "https://codyderunner.000webhostapp.com/Server/songbannner.php" which response JSON like: Json response from my file
I want to get those JSON in Android studio using Retrofit.
I have a DataService interface:
public interface DataService {
#GET("songbannner.php")
Call<List<Ads>> GetDataBanner();
}
Ads is a model class of the Data I want to Receive.
My APIService.java file code:
public class APIService {
private static String base_url = "https://codyderunner.000webhostapp.com/Server/";
public static DataService getService(){
return APIRetrofitClient.getClient(base_url).create(DataService.class);
};
}
My API.RetrofitClient code:
public class APIRetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String base_url){
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(10000, TimeUnit.MILLISECONDS)
.writeTimeout(10000, TimeUnit.MILLISECONDS)
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(true)
.protocols(Arrays.asList(Protocol.HTTP_1_1))
.build();
Gson gson = new GsonBuilder().setLenient().create();
retrofit = new Retrofit.Builder()
.baseUrl(base_url)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return retrofit;
};
In my main class, i have a function to get data from that file:
private void GetData(){
DataService dataService = APIService.getService();
Call<List<Ads>> callback = dataService.GetDataBanner();
callback.enqueue(new Callback<List<Ads>>() {
#Override
public void onResponse(Call<List<Ads>> call, Response<List<Ads>> response) {
ArrayList<Ads> banner = (ArrayList<Ads>) response.body();
Log.d("AAAA", banner.get(0).getNameSong());
}
#Override
public void onFailure(Call<List<Ads>> call, Throwable t) {
}
});
}
Now, the thing is, i can not receive any response from the file, I think it may because of the authentication when I try to get the data which the file response. Its fine when I open the link with the browser, cause it remember my password, but when I try to read the JSON of the File from Android Studio, Its seem hopeless. I also try to read the link on Postman, its released "Unauthorized", so I think the point is how can I put my user-name and password in Retrofit so the file will response as it did in the browser.
Is there anyone meet the same problem? Help me, I tried Everything I know. Many thanks.
OK, finally, I find out that the website which I store my .php file require user name and password, just add it into the Okhttpclient.
First, I created a java class called BasicAuthInterceptor:
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
And add it with password and username into your OkhttpClient:
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
with your username and password which you use to login into the website. It took me 2 days finding out, hell ya.

Retrofit upload Base64 string as a Field (8MB) takes 4 minutes

I am trying to send the converted file (Base64 - String) as a parameter in POST, the file is about 8 MB, but sending takes about 4 minutes. Is there a way to speed up?
Interface:
#FormUrlEncoded
#POST("upload")
Call<Upload> upload(#Field("CONTENT") String content);
Retrofit instance:
public class RetrofitClientInstance {
private static Retrofit retrofit;
private static OkHttpClient client;
public static Retrofit getRetrofitInstance(String url) {
if (retrofit == null && !url.isEmpty()) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(url)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}}
Call:
private void upload(){
Api api = RetrofitClientInstance.getRetrofitInstance(SharedUtils.SERVER_URL).create(Api.class);
Call<Upload> request = api.upload(getBase64FromFile());
request.enqueue(new Callback<Upload>() {
#Override
public void onResponse(Call<Upload> call, Response<Upload> response) {
}
#Override
public void onFailure(Call<Upload> call, Throwable t) {
}
});
}
Try to compress your file or image before uploading, because it would take so much time to make it done
First of all, you are using enqueue() method of retrofit which is an asynchronous way of executing the code and you have registered callbacks to these methods on successful execution you will receive the call inside onResponse() method but on failure, you will get control inside the onFailure() method.
This will spawn a thread of execution from the daemon thread which creates another thread of execution you may never know when will this thread gets executed based on OS priority.
Use execute() method to execute this in a synchronous manner and then check the response time it would give a proper result.

Why is method not returning true?

I have an HTTP request inside of a method and i'm trying to return true/false based on the response from the request. im not sure what im doing wrong, I thought it was pretty straight forward. in the test scenario the condition inside of the onResponse call returns true. not sure whats getting lost in translation.
Also, in the final condition, the "message" variable is purple, in android studio, im not sure what this indicates. I think its related to my issue. suggestions?
public class DeleteButtonChecker {
public String message = new String();
public Boolean doCheck(int userID, int postID){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
Call<ServerResponse> response = requestInterface.check(postID, userID);
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, Response<ServerResponse> response) {
ServerResponse resp = response.body();
if(resp.getResult().equals(Constants.SUCCESS)){
message = "true";
} else {
message = "false";
}
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
}
});
if(message.equals("true")) {
return true;
} else{
return false;
}
}
}
The response is handled asynchronously. On the line:
response.enqueue(new Callback<ServerResponse>() {
...
You are simply giving a callback to be executed once the response is returned. However the method is not blocked and continues to the next statement - which is the:
if(message.equals("true")) {
Which can be translated to:
if("".equals("true")) {
An asynchronous request cannot be treated as a synchronous call, that is given your conditions.
If it was for me I would use RxJava 2 Single with Retrofit to return a usable result from the request.
Check this out: https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
And make sure to learn some RxJava which can help you on the road

Retrofit 2 Sequential Posts

I am just now learning about Retrofit 2. In my app Intent "UploadToServer"
I have three async tasks that I need to call sequentially:
1. Post UserName and get back UserId.
2. Post Geolocation and some other string data and get back a "report ticket number".
3. Post a jpg image along with the ticket number.
I have a web service running on my server.
In standard hand-coded Java I would use a looper or something equivalent.
How could this be accomplished using Retrofit 2? And oh, I would like to have a progress bar moving, especially when uploading the jpg image file.
Thanks.
You can chain the calls using the callbacks:
OkHttpClient client = new OkHttpClient.Builder().build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL_WEBAPI)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
mService = retrofit.create(IWebApi.class);
...
mService.first_operation(...params...).enqueue(callback);
callback is an instance of a class that expects the results of first_operation. If first_operation success, then call the second_method.
public class Example implements Callback<void> {
#Override
public void onResponse(Response<LoginResponse> response) {
second_method();
}
#Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
}
Hope it helps.
Edit:
I use a ProgressDialog with indeterminated in true. You can show it right before the call to the service and hide when a response arrives, in the onResponse or in the onFailure methods.
mProgressDialog = ProgressDialog.show(this, getString(R.string.wait_plaease),
getString(R.string.executing_action), true);

Categories

Resources