I'm trying to Post JSON object in my application's login page. I searched for many examples and tried for them. But only my android 4.3 devices is running well and the other upper api level devices is not even response coming back. My code like below:
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.LoginBtn:
loading.show();
try {
login();
} catch (JSONException e) {
e.printStackTrace();
}
break;
}
}
public void login(){
okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.build();
final JSONObject JObje = new JSONObject();
try {
JObje.put("Username", String.valueOf(Username.getText()));
JObje.put("Password", String.valueOf(Password.getText()));
} catch (JSONException e) {
e.printStackTrace();
}
okhttp3.Request request = null;
okhttp3.RequestBody body = null;
body = new FormBody.Builder()
.addEncoded("JSONVALUE", String.valueOf(JObje))
.build();
request = new okhttp3.Request.Builder()
.url(context.getString(R.string.rutKontrolServis))
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.post(body)
.build();
client.newCall(request).enqueue(new okhttp3.Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, okhttp3.Response response) throws IOException {
Log.d("TAG","responded");
}
});
}
the R.string.rutKontrolServis url is like this: https://ourwebsite.com/folder/package_name.mywebservice
In my gradle file I added dependency this:
compile 'com.squareup.okhttp3:okhttp:3.11.0'
Is there any different request syntax or any constraint about tls or ssl certificates with newer api level devices? Can someone show a point
Did you try to increase the connection timeout and read timeout? I think 10 seconds is too short:
okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10,TimeUnit.SECONDS)
.readTimeout(10,TimeUnit.SECONDS)
.build();
Increase to 30 seconds and try again.
Sometimes OkHTTP just suddenly stops responding - no onFailure results, no onResponse results, even after increasing timeout. Nothing.
Switching your wifi / network provider to another provider worked for me.
Related
This question basically wants to know how to use stored cookies for subsequent request. The long text below is just for example. Basic question is how to use the same cookie for all requests on a particular website.
Basically I am trying to reach the login page of a website within the android app. The website works the following way.
There are 3 urls to consider.
1 -> "http://www.example.com/timeoutPage"
2 -> "http://www.example.com/mainPage"
3 -> "http://www.example.com/loginPage"
The two main points to consider are
(1) If we directly go to the 3rd url (loginPage), it redirects to the 1st url(timeoutPage). The timeoutPage has a button to go to the mainPage.
(2) If we go to the 2nd url (mainPage), it gives us a cookie. Now, after getting the cookie, when we visit the 3rd url (loginPage), we are able to access it. The loginPage has a captcha so it's essential to visit it(loginPage) in order to login.
Without the cookie, which is given at visiting 2nd url(mainPage), we cannot directly access 3rd url(loginPage).
so what i am doing is to make a ClearableCookieJar and attach it to OkHttpClient.
OkHttpClient client;
ClearableCookieJar cookieJar;
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
client = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.build();
Request request = new Request.Builder()
.url("http://www.example.com/mainPage")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String myResponse = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse);
}
});
}
}
});
Everthing is fine till here as i am able to print the html of mainPage in my textview.
Problem starts here when i make another request for the loginPage.
request = new Request.Builder()
.url("http://www.example.com/loginPage")
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
textView.setText("Failed to get response");
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
final String myResponse2 = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(myResponse2);
}
});
}
}
});
Here i again make a request to the loginPage but i reach the timeoutPage. How should i make the request for the loginPage url so that my request sends the cookie which i stored in the cookieJar while making a request to mainPage. One way i thought of was
request = new Request.Builder()
.url("http://www.example.com/loginPage")
.addHeader("Cookie", cookieStringGivenAtMainPage)
.build();
But i don't know how to access that cookieStringGivenAtMainPage. How should i reach that loginPage?
I print the html of the response to see if i reached the correct page.
It seems the answer you want to know is the singleton pattern.
Please refer to below sample code. I got it from kakao developer site about 3 years ago.
public class NetworkManager {
private static NetworkManager instance;
private OkHttpClient client;
/**
* By using Singleton Pattern we can share cookie, client values.
**/
private NetworkManager() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
Context context = GlobalApplication.getGlobalApplicationContext();
ClearableCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(context));
builder.cookieJar(cookieJar);
builder.followRedirects(true);
builder.addInterceptor(new RedirectInterceptor());
File cacheDir = new File(context.getCacheDir(), "network");
if (!cacheDir.exists()) {
cacheDir.mkdir();
}
Cache cache = new Cache(cacheDir, 10 * 1024 * 1024);
builder.cache(cache);
builder.connectTimeout(30, TimeUnit.SECONDS);
builder.readTimeout(10, TimeUnit.SECONDS);
builder.writeTimeout(10, TimeUnit.SECONDS);
client = builder.build();
}
public static NetworkManager getInstance() {
if (instance == null) {
instance = new NetworkManager();
}
return instance;
}
public OkHttpClient getClient() {
return client;
}
}
In addition below is sample usage.
OkHttpClient client = NetworkManager.getInstance().getClient();
RequestBody formBody = new FormBody.Builder()
.add("userId", getTargetUserId())
.build();
Request request = new Request.Builder()
.url("www.test.com/insert.php")
.post(formBody)
.build();
client.newCall(request).enqueue(callback);
I am building an Android APP where I use the Internet Game Database API through Mashape market place. I am using Retrofit for the get requests and getting data from the API requires an API key.
I got it to work but the API only return game ids and I want the game names and other information, but I am not sure how to add the fields. This is how Mashape query it:
HttpResponse<String> response = Unirest.get("https://igdbcom-internet-game-database-v1.p.mashape.com/games/?fields=name%2Crelease_dates")
.header("X-Mashape-Key", "API KEY HERE")
.header("Accept", "application/json")
.asString();
and this is my Retrofit Interface
public interface GamesAPIService {
#GET("/games/")
Call<List<GamesResponse>> gameList(#Query("mashape-key") String apikey);
}
I tried to use this
#GET("/games/?fields=name,release_dates")
But no luck, I also tried with #Field but didn't work either. Any ideas? Thanks.
Edit: Just to clarify when I add the "?fields=name,release_dates" I get 401 Unauthorized Error.
Firstly I think you need to add mashape key to all your request.
OkHttpClient httpClient = new OkHttpClient();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("X-Mashape-Key", "API_KEY_HERE")
.addHeader("Accept", "application/json")
.build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://igdbcom-internet-game-database-v1.p.mashape.com")
.client(httpClient)
.build();
And then this is information query.
public interface GamesAPIService {
#GET("/games")
Call<List<GamesResponse>> gameList(#Query("fields") String value);
}
And last thing for calling.
GamesAPIService gamesAPIService = retrofit.create(GamesAPIService.class);
Call<List<GamesResponse>> call = gamesAPIService.gameList("name,release_dates");
if (call!=null){
call.enqueue(new Callback<List<GamesResponse>>() {
#Override
public void onResponse(Call<List<GamesResponse>> call, Response<List<GamesResponse>> response) {
// handle success
}
#Override
public void onFailure(Throwable t) {
// handle failure
}
});
}
I'm implementing retrofit in my app. I use code below to getString and write to file from server.
Callback callback = new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.i(TAG, "onResponse");
File file = new File(fileDirectory);
file.mkdirs();
File outputFile = new File(file,
XXX);
try {
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream(outputFile));
osw.write(new String(response.body().string()));
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.i(TAG,"onFailure, getTermAndPoliciesDocument()");
t.printStackTrace();
}
};
PortalService portalService = ServiceGeneratorDemo.createService(PortalService.class);
Call<ResponseBody> call = portalService.getStringFromFile(AppSetting.Default.TERM_AND_POLICIES_DOC_NAME);
call.enqueue(callback);
Now i want show information about download of that file. Like 1 - 100% to complete progress like below image. . Anyone know how to callback time remain ?
Now i want show information about download of that file. Like 1 - 100% to complete progress
Your image shows time remaining, but once you know the percentage complete, you can calcuate the time yourself. Here's how I found to get the percent progress update using Retrofit 2:
First, create a progress listener:
final ProgressResponseBody.ProgressListener progressListener = new ProgressResponseBody.ProgressListener() {
#Override public void update(long bytesRead, long contentLength, boolean done) {
int percent = (int)((100 * bytesRead) / contentLength);
//Do something with the progress (I sent the event through EventBus)
}
};
Next, create a client as shown here, which will call the listener:
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
Finally, specify the client when building Reftrofit:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
It took me a while to get this figured out and I wish I could find the link that provided the final information, but this is the code I'm using. (I thought it was on Future Studio but I don't see it.)
I'm writing an android app that needs to communicate with a server. I'm struggling to make a MultipartBody for OkHttp3 to use. My code looks like this:
OkHttpClient client = new OkHttpClient();
try
{
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("someKey1", "someString1")
.addFormDataPart("someKey2", "someString2")
.build();
System.out.println(requestBody.toString());
Request request = new Request.Builder()
.url("server url")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
return response;
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
This is pretty much the standard code everyone uses. The server receives the request, but I can't get the MultipartBody from the request. When the multipart body is printed, it looks like this:
I/System.out: okhttp3.MultipartBody#14040826
So my questions are: Why doesn't it contain my data and should it? Am I missing a library (I included compile 'com.squareup.okhttp3:okhttp:3.2.0' in the gradle and assume MultipartBody is part of this library)? What is a MultipartBody supposed to look like?
I tried sending a FormBody as well but it looks the same.
Remove okhttp3.Response response = client.newCall(request).execute();
okhttp3.Call call = client.newCall(request);
call.enqueue(new okhttp3.Callback() {
#Override
public void onFailure(okhttp3.Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
}
});
On Nexus 6 Android M (v23), calling HTTP Api using Retrofit waits for around 5 secs, before getting request hit on server.
Both the phone and the server are on the same WiFi. From browser on other workstation in same wifi gets results instantaneously (~40-60ms).
Opening same API from Android chrome on same mobile too takes 5 secs.
What can be the issue for delayed HTTP call?
Code:
Retrofit2/Okhttp service Factory
public class ApiGenerator {
public static String TAG = ApiGenerator.class.getSimpleName();
public static final String API_BASE_URL = BuildConfig.API_ENDPOINT;
public static final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response;
}
}).addInterceptor(new LoggingInterceptor());
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
.....
Retrofit2 Service
public interface AuthService {
#GET("/api/v1/auth")
public void authenticate(#Query("token") String token);
#POST("/api/v1/signup")
Call<Object> signup();
}
Service Call -
Observable<Response<SignupV1Response>> observable = service.signupRx(signupReq);
observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.unsubscribeOn(Schedulers.io())
.subscribe(new Subscriber<Response<SignupV1Response>>() {
#Override
public void onCompleted() {
...
}
#Override
public void onError(Throwable e) {
...
}
#Override
public void onNext(Response<SignupV1Response> response) {
if (response != null) {
final int statusCode = response.code();
if (response.isSuccess()) {
// Do something
} else {
ResponseBody errorBody = response.errorBody();
// Show error
}
}
}
});
At last found that, it has nothing to do with Okhttp and Retrofit. Its android networking issue, which has IPv6 enabled, on Andoid L (v21) and higher.
If the WiFi network does not correctly handle IPv6 (most routers including recent releases), these http client libraries takes few secs before getting response.
Refer issue - https://code.google.com/p/android/issues/detail?id=79576
For a workaround, you can tunnel local development server to Amazon EC2 with ssh or use ngrok. Works fine with this approach.