I am a iOS programmer (not very experienced). I usually create a HttpClient.class for all other class to use. Like:
#implementation HttpClient
-(NSString*)getGetResponse :(NSString*)url{
//do all http get request work
return result;
}
#end
Then I can call this getGetResponse: anywhere in my project to do the http get work.
NSString *result = [httpClient getGetResponse:#"http://www.example.com/api"]
But Android request network running in class extends AsyncTask.Like:
public class HttpTask extends AsyncTask<String,String, String > {
#Override
protected String doInBackground(String... params) {
//network code here
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
}
This makes me confused. How do I do the same thing like the objective-c code does above?(return the result back to caller)
You don't. HTTP calls need to happen asycnhronously. Instead of returning a result, forcing the thread to wait, you need to do any processing that requires the result in onPostExecute.
Related
I'm currently studying android on my own and pretty new to java. I'm wondering how AsyncTask works like this: onPreExecute() -> doInBackground() -> onPostExecute(). When I look at others define their AsynTask, it seems like only method is declared in their code with no calls upon the method. I can't figure out how doInBackground() comes after onPreExecute() with no code that links both like:
onPreExecute(){ ~~~~~ call doInBackground()}
My point is that when AsyncTask.execute() is called, onPreExecute() is called, then doInBackground(), finally onPostExecute(). I couldn't find any code in library that actually connects these together. All I could find is this:
#MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
#MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
Here when AsyncTask.execute() is called, onPreExecute() is called. But without any connection to doInBackground the task works just fine. I feel like I'm missing some fundamental logic or process of java or android. Plz, help me with this unsolved question in mind. Sample code is shown below. Thank you in advance.
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected String[] doInBackground(String... params) {
/* If there's no zip code, there's nothing to look up. */
if (params.length == 0) {
return null;
}
String location = params[0];
URL weatherRequestUrl = NetworkUtils.buildUrl(location);
try {
String jsonWeatherResponse = NetworkUtils
.getResponseFromHttpUrl(weatherRequestUrl);
String[] simpleJsonWeatherData = OpenWeatherJsonUtils
.getSimpleWeatherStringsFromJson(MainActivity.this, jsonWeatherResponse);
return simpleJsonWeatherData;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(String[] weatherData) {
// COMPLETED (19) As soon as the data is finished loading, hide the loading indicator
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (weatherData != null) {
// COMPLETED (11) If the weather data was not null, make sure the data view is visible
showWeatherDataView();
/*
* Iterate through the array and append the Strings to the TextView. The reason why we add
* the "\n\n\n" after the String is to give visual separation between each String in the
* TextView. Later, we'll learn about a better way to display lists of data.
*/
for (String weatherString : weatherData) {
mWeatherTextView.append((weatherString) + "\n\n\n");
}
} else {
// COMPLETED (10) If the weather data was null, show the error message
showErrorMessage();
}
I guess you shouldn't waste time on AsyncTask since it is deprecated.
Instead you should focus on coroutines, recommended by google here , or some other state of the art framework to achive what you want (e.g. rx java)
Yes, you are correct. The logic is onPreExecute() -> doInBackground() -> onPostExecute()
Synchronous VS asynchronous
You can read this article for a better understanding even though it's using Javascript to explain it.
I am trying to build a Rest client with Retrofit 2. This is the first time using this library.
Most of the examples that I have seen normally use a callback function in Android activity or view.
http://www.vogella.com/tutorials/Retrofit/article.html
https://github.com/MeetMe/TwitchTvClient/tree/master/src/com/wdonahue/twitchtvclient
I was wondering if, in the code below, one could return an object of type Appver instead of void?
Thank you!
public void GetAppver()
{
Call<Appver> call = endPoint.GetAppver();
call.enqueue(new Callback<Appver>()
{
#Override
public void onResponse(Call<Appver> call, Response<Appver> response)
{
if (response.isSuccessful())
{
Appver appver = response.body();
}
}
#Override
public void onFailure(Call<Appver> call, Throwable t) { }
});
}
I guess you want to have Appver because you need to use this object to possibly poulate the UI for instance inside a RecyclerView, in this case I guess you cannot avoid to not use void, because you are extending the library. But for sure you can use Dagger2 or a Singleton although there are some contraindications to maintain an instance of Appver so that you can use it in an Adapter for instance
Also in real life is rarely used Retrofit2 in this way, usually you implement it with RXJava2 or with Google Architecture components as ViewModel,LiveData and LifeCycle
You can call Retrofit service methods synchronously.
public AppVer GetAppVer() {
Call<AppVer> call = endPoint.GetAppver();
Response<AppVer> response;
try {
response = call.execute();
} catch (IOException e) {
// Handle network communication errors here
}
if (!response.isSuccessful()) {
// Handle REST service errors here
}
return response.body();
}
However, as you know, you can't do network communication on the main thread in Android. You have to wrap the call in e.g. a Thread, AsyncTask or Service.
Have a look at the following links how to structure your app.
Android Architecture Blueprints: https://github.com/googlesamples/android-architecture
Android Architecture Components: https://developer.android.com/topic/libraries/architecture
So I have been trying to return the content grabbed from httpResponse from a class, however, im not very successful at the moment.
String requestContent = null;
Net.HttpRequest httpRequest;
httpRequest = new Net.HttpRequest(Net.HttpMethods.GET);
httpRequest.setUrl("https://api.parse.com/1/classes/gamerooms/");
System.out.println(Parse.getRestAPIKey() + Parse.getApplicationId());
httpRequest.setHeader("X-Parse-Application-Id", Parse.getApplicationId());
httpRequest.setHeader("X-Parse-REST-API-Key", Parse.getRestAPIKey());
httpRequest.setContent(requestContent);
Gdx.net.sendHttpRequest(httpRequest, new Net.HttpResponseListener() {
#Override
public void handleHttpResponse(Net.HttpResponse httpResponse) {
content = httpResponse.getResultAsString();
}
#Override
public void failed(Throwable t) {
}
#Override
public void cancelled() {
}
});
return content;
}
When I return content, it is empty but when i print the content in handleHttpResponse, i can see it there. Any solutions?
The problem is, that it is handled like a Thread. So when you're returning the content, the answer maybe not already arrived. So you must handle the result in the handleHttpResponse method. If you don't want all the code in that method, you could also call a function.
Also because you're in a Thread I think you should call Gdx.app.postRunnable(Runnable runnable) if you want to change something in the code, which you shouldn't while you are in the render method or need OpenGL context. The Runnable will be called directly before the render method. Threading libGdx
I am building an android library.
The main class includes methods like connect,getUserSession .Workflow includes few steps-
Step 1 :
In getUserSession method. I need to send a Http POST request to external api and
recieve the response data(sessionKey,id,name etc). It is like an authentication method.
Step 2 :
In connect method. It uses the response data from Step 1 then I need to connect to websocket server recieve the response data(userdetails,profilepic etc).
Step3 :
Pass the response data from Step 2 in Activity.
I want to be step 1 and step 2 to be synchrounous because step 2 won't work without step 1. And i dont want to block the app while processing.After doing some research i found this can be done using AsyncTask class. But it seems i cannot return values from doInBackground and onPostExecute methods. How to do this task?
You have to set listener (interface) for first AsyncTask Please try below code
interface AsyncTaskListener{
public void onTaskCompleted(Object<Type> value);
}
public class DemoAsyncTask extends AsyncTask<String,Void,Void>{
AsyncTaskListener listener;
public DemoAsyncTask(AsyncTaskListener listener){
this.listener = listener;
}
#Override
protected String doInBackground(Void... params) {
///do some task
return someResult;
}
#Override
protected void onPostExecute(String result) {
listener.onTaskCompleted(result);
}
//Calling Async task from activity or fragment
DemoAsyncTask task = new DemoAsyncTask(new AsyncTaskListener(){
#Override
public void on onTaskCompleted(Object<Type> value);{
//do your second step here
})
};
task .execute();
I've just gotten into android development, and while trying to create a login form i ran into some problems.
What I want to do is enter username and password and press login, when the login button is pushed I want it to do a JSON request with the account information to my server and get a response with whether or not the user is allowed to log in. If the user is allowed, I want to change to a new view.
My code receives the JSON information correctly, but from what I've understood the UI-code (pushing a new activity) should be done in onPostExecute(). My problem is that onPostExecute is never run, I've looked at other ppl with the same problem, but their solutions hasn't worked for me. What they have said is that i need to have an #Override before onPostExecute, but when I add that i get the compilation error that "the method does not override method from its superclass".
I've read solutions from people having that problem as well, and from what I have read the problem is that the method onPostExecute has to have the same parameters as the result parameter from doInBackground(). My problem is that I feel I already do, and when I try to look in what the superclass has (that is AsyncTask.java) it says that the method onPostExecute() looks like:
protected void onPostExecute(Result result) {
}
But I have no idea what class Result belongs to..
networkingTask is run using this line:
new networkingTask().execute(url);
If anyone could help me I'd be eternally grateful! :)
This is what my code looks like
private class networkingTask extends AsyncTask {
Context context;
private networkingTask(Context context) {
this.context = context.getApplicationContext();
}
public networkingTask() {
}
#Override
protected JSONObject doInBackground(Object... params) {
try {
String urlString = (String) params[0];
System.out.println(urlString);
// Creating JSON Parser instance
JSONParser jParser = new JSONParser();
// getting JSON string from URL
JSONObject json;
json = jParser.getJSONFromUrl(urlString);
String responseLogged = json.getString("logged");
System.out.println("can we log in?: "+ responseLogged);
return json;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(JSONObject result) {
String responseLogged = "";
try {
responseLogged = result.getString("logged");
} catch (JSONException e) {
e.printStackTrace();
}
if(responseLogged.equals("true")){ //Login = true
Intent intent = new Intent(context, ShowListActivity.class);
intent.putExtra(EXTRA_JSON_OBJECT, result.toString());
startActivity(intent);
} else{ //Login = false
System.out.println("wrong password");
}
return;
}
}
In your line:
private class networkingTask extends AsyncTask
just change it to:
private class networkingTask extends AsyncTask<String, Void, JSONObject>
while String is the place for you to pass in the parameters, in your case it is url, the second parameter Void is for showing progress and the last one is the processed result to be passed from doInBackground to onPostExecute
For further explanation & info, please refer to Android Developers: AsyncTask
I think you may need to fill out the generic types for your AsyncTask. See the "Usage" section in the AsyncTask documentation.
Your class signature should look something like this:
private class networkingTask extends AsyncTask<Object, Void, JSONObject>
The types in the brackets here correspond to the argument types for doInBackground, onProgressUpdate, and onPostExecute, respectively, and are necessary if you're going to override these methods such that they are different from the generic method signatures.
Also, as a side note, it's a common convention in Java/Android to use upper CamelCase to start a class name. I'd also change the name of your class to "NetworkingTask" to help other developers looking at your code to better understand it.
The signatures don't match. You're attempting to override:
protected void onPostExecute(Result result)
with the signature
protected void onPostExecute(JSONObject result)
...which doesn't exist in the superclass.