I am trying to use OkHTTP library. When making a call to the server and getting a successful response back. i need to update the UI.
How can this be done when doing an Async call using the enqueue()?
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
// NEED TO UPDATE UI HERE
}
}
});
You can refer to the following sample code, hope this helps!
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = "OkHttp";
private TextView mTextView;
private Handler mHandler;
private String mMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mHandler = new Handler(Looper.getMainLooper());
OkHttpClient client = new OkHttpClient();
// GET request
Request request = new Request.Builder()
.url("http://...")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
mMessage = e.toString();
Log.e(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
#Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}
#Override
public void onResponse(Response response) throws IOException {
mMessage = response.toString();
Log.i(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
#Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}
});
}
}
If your code doesn't update the UI, I would suggest you to specify the thread, since UI is on its own thread:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//TODO: update your UI
}
});
}
}
});
Try this:
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
// code to interact with UI
}
});
For the sake of having a clean code, I would suggest you not to put your entire code inside the runnable.
A simple example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://...").build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Response response) throws IOException {
final String body = response.body().string();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateUI(body);
}
});
}
});
}
private void updateUI(responseBody){
//TODO: update your UI
}
}
Related
I am creating app that can run 2 process at the time (saving to database / sending to api) but , i was encountering issue from my treading.This is my code upon my threading:
this is my code:
public void timerToSaveSend() {
Thread t1 = new Thread() {
#Override
public void run() {
saving();
}
};
t1.start();
Thread t2 = new Thread(){
#Override
public void run() {
sending();
}
};
t2.start();
}
private void sending() {
//dataSendApi
handler10 = new Handler();
handler10.postDelayed(new Runnable() {
#Override
public void run() {
try {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + ADDRESS + ":" + PORT)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
API locate = retrofit.create(API.class);
Call<MapDetails> call = locate.mapDetailLocation(data);
call.enqueue(new Callback<MapDetails>() {
#Override
public void onResponse(Call<MapDetails> call,
Response<MapDetails> response) {
String portString = String.valueOf(portss);
}
#Override
public void onFailure(Call call, Throwable t) {
Log.d("Message: ", "Data not sent, please check your
network connection.");
}
});
} catch (Exception e) {
Toast.makeText(NavDrawerFleet.this, "Disconnected from Internet, Please Configure Settings", Toast.LENGTH_SHORT).show();
restFailed();
}
}
}, 10000);
}
private void saving() {
//4SECOND
handler2 = new Handler();
handler2.postDelayed(new Runnable() {
#Override
public void run() {
DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());
SQLiteDatabase db = databaseHelper.getWritableDatabase();
well2 = String.valueOf(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault()).format(new java.util.Date()));
boolean accepted = databaseHelper.saveLocationToLocalDatabase(gg, hidelat.getText().toString(), hidelon.getText().toString(), well2, "1", "9090", db);
failedCount.setText(String.valueOf(retryList.size()));
lat2 = hidelat.getText().toString();
lon2 = hidelon.getText().toString();
MapDetails mapDetails = new MapDetails(gg, hidelat.getText().toString(), hidelon.getText().toString(), well2, "1", 9090);
data.add(mapDetails);
retry2 = new NotSentModuleGetterSetter(hidelat.getText().toString(), hidelon.getText().toString(), well2);
retryList.add(retry2);
retrylist_adapter.notifyDataSetChanged();
if (accepted == true)
Log.w("Data Entered: ", "1st Copy");
}
}, 2000);
saving();
}
and this is my error encountered:
PS. I was wondering that my code is to totally not working though i want also other possible code implementation with this one, like asynctask to work with this multiple process + with threading in a single meathod.
For threading, please consider using RxJava. It would be as simple as this
Observable.fromCallable(new Callable<Object>() {
#Override public Object call() throws Exception {
saving();
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override public void onSubscribe(Disposable d) {
}
#Override public void onNext(Object o) {
}
#Override public void onError(Throwable e) {
}
#Override public void onComplete() {
}
});
Check this link out on how to integrate RxJava into your project https://github.com/ReactiveX/RxAndroid
I have web request helper class in my app using OKHttp3 via standard async method call. everything just work fine, but in my Splash Activity just for first run (after new installation) web request calling not work! but if I close the app and run again everything work fine.
here is my call back interface:
public interface WebResult<T> {
void onValue(T value);}
here is calling method
public void getStatus(final WebResult result) {
urlBuilder.addQueryParameter("action", "test");
urlBuilder.addQueryParameter("reqbody", cd.toJSON());
String url = urlBuilder.build().toString();
Request request = new Request.Builder()
.header("Authorization", AuthKey)
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
setHasError(true);
setMsg(e.getMessage());
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
} else {
iAct.runOnUiThread(new Runnable() {
public void run() {
try {
String s = response.body().string();
ServerStat r = new ServerStat();
r.fromJSON(s);
result.onValue(r);
return;
} catch (IOException e) {
}
}
});
}
}
});
}
and its my splash activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
WebHelper wh = new WebHelper(context);
wh.getStatus(new WebResult() {
#Override
public void onValue(Object value) {
ServerStat r = (ServerStat) value;
if (r.getErrorCode() == 0) {
Toast.makeText(context, r.getErrorMsg(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, r.getErrorMsg(), Toast.LENGTH_LONG).show();
}
}
});
}
I replaced OKHttp3 with google Volley and it's work in my case!
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getString();
}
private void getString(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL_MOVIE)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
res_120 = response.body().string();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateUI(res_120);
}
});
}
});
}
void updateUI(String string) {
textView.setText(string);
}
How do i save the textView text on screen rotation ? Every time i rotate the screen a new string is retrieved from the response and the my textView text changes. how stop that from happening i want to make sure that same string remains on the textview during screen rotation until and unless i update it myself by calling the getString method on say any onclicklistener to get another string for the textview.
String yourstring="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
String myString = savedInstanceState.getString("MyString"); //get it
textView.setText(myString);
} else {
getString();
}
}
private void getString(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(URL_MOVIE)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
res_120 = response.body().string();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateUI(res_120);
}
});
}
});
}
void updateUI(String string) {
textView.setText(string);
yourstring=string;
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save UI state changes to the savedInstanceState.
// This bundle will be passed to onCreate if the process is
// killed and restarted.
savedInstanceState.putString("MyString", yourstring); // save your instance
// etc.
super.onSaveInstanceState(savedInstanceState);
}
//onRestoreInstanceState
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore UI state from the savedInstanceState.
// This bundle has also been passed to onCreate.
String myString = savedInstanceState.getString("MyString"); //get it
textView.setText(myString);
}
You can save your instance
I'd like to get color value inside void run, how can I do this? any example?
color is null there.
public void onResponse(Call call, final Response response) throws IOException {
String color = response.body().string();
Profile.this.runOnUiThread(new Runnable() {
#Override
public void run() {
setTheme(color); //color is null here.
}
}
}
color is null inside run()
full code:
protected void onCreate(Bundle savedInstanceState) {
this.context = getApplicationContext();
OkHttpClient client = new OkHttpClient();
okhttp3.Request request = new okhttp3.Request.Builder()
.url("http://ip/color.php")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
String color = response.body().string();
Profile.this.runOnUiThread(new Runnable() {
#Override
public void run() {
setTheme(color);
}
}
}
});...
If it says variable color is accessed from within inner class,
make the variable color as Global.
Declare it outside your onCreate.
Or make it final
final String color = response.body().string();
First of all your code shouldn't compile as you cannot access non final variable inside of "closure".
So the only change you need is
final String color = response.body().string();
Profile.this.runOnUiThread(new Runnable() {
#Override
public void run() {
setTheme(color);
}
}
I want to get string JSON response to the main activity after making the connection I know it is running in different thread so please help me how I can get it and then return it from this method;
public class MakeNetworkConnection {
private String mBaseUrl;
private String mApiKey;
private String mContentType;
private String mJsonResponce;
public MakeNetworkConnection(String baseUrl, String apiKey, String contentType) {
mBaseUrl = baseUrl;
mApiKey = apiKey;
mContentType = contentType;
}
public String startNetworkConnection() throws IOException {
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url("http://content.guardianapis.com/sections?api-key=1123456").build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
mJsonResponce=response.body().string();
}
}
});
return mJsonResponce;
}
}
The problem here is about understanding how asynchronous tasks work. When you are calling client.newCall(request).enqueue(new Callback(), it will run in the background thread (off the main thread) and control will pass to the next line which is return mJsonResponce; And thus, it will always return null.
What you should do is to pass a callback method which will be called when the response is successful. You can create an interface to return the result:
public interface NetworkCallback {
void onSuccess(String repsonse);
void onFailure();
}
Pass an object of this interface while making the network request and call appropriate method when network request finishes.
One more thing you will have take care is that OkHttp doesn't return the response on the main thread so you will have to return the response on UI/main thread if you are going to update any UI. Something like this will work.
#Override
public void onResponse(Call call, Response response) throws IOException {
if(response.isSuccessful()){
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//return response from here to update any UI
networkCallback.onSuccess(response.body().string());
}
});
}
}
Instead of using calls asynchronously, you could use it synchronously with execute().
public String startNetworkConnection() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://content.guardianapis.com/sections?api-key=1123456")
.build();
return client.newCall(request)
.execute()
.body()
.string();
}
after advice from Rohit Arya i did the following:
public class OkHttpUtil {
public interface OKHttpNetwork{
void onSuccess(String body);
void onFailure();
}
public void startConnection(String url, final OKHttpNetwork okHttpCallBack) throws IOException {
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()){
okHttpCallBack.onSuccess(response.body().string());
}
}
});
}
}
in the MainActvity i did the following :
OkHttpUtil okHttpUtil=new OkHttpUtil();
try {
okHttpUtil.startConnection("http://content.guardianapis.com/sections?api-key=8161f1e9-248b-4bde-be68-637dd91e92dd"
, new OkHttpUtil.OKHttpNetwork() {
#Override
public void onSuccess(String body) {
final String jsonResponse=body;
runOnUiThread(new Runnable() {
#Override
public void run() {
//show the response body
Toast.makeText(MainActivity.this,jsonResponse, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure() {
//do something
}
});
} catch (IOException e) {
e.printStackTrace();
}
Change this line
mJsonResponce=response.body().toString();
To
mJsonResponce=response.body().string();
Hope help you.