In this topic:
About task onPostExecute
I asked about onPostExecute to dismiss a process, the friend #inner_class7 give me the way to resolve the error, but the friend #Doug Stevenson said that using this way the code will blocking the uithread, I tested and this is true, my uithraed was blocked. So He said that I need to use onPostExecute to get the result. I read about and created a code and I would like suggestion about.
I changed the code and do it:
protected ArrayList<String> doInBackground(String... params) {
try {
final String POST_PARAMS = params[1];
URL obj = new URL(params[0]);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
// For POST only - START
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(POST_PARAMS.getBytes());
os.flush();
os.close();
// For POST only - END
int responseCode = con.getResponseCode();
System.out.println("POST Response Code :: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { //success
BufferedReader in = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
System.out.println(response.toString());
JSONArray myListsAll= new JSONArray(response.toString());
for(int i=0;i<myListsAll.length();i++){
JSONObject jsonObject = myListsAll.getJSONObject(i);
this.stringArray.add(jsonObject.toString());
}
} else {
System.out.println("POST request not worked");
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return this.stringArray;
}
#Override
protected void onPostExecute(ArrayList<String> result)
{
this.obj.setFeedsData(result);
if(setProgress){ progress.dismiss(); }
}
So call in my mainactivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
String[] itensUrl = {links.feedsList(),"iduser=2&offset=0"};
new JsonRequest(this,this,true).execute(itensUrl);
}
public void setFeedsData(ArrayList<String> obj){
createListView(obj);
}
So what Do you think about? This way that a use is a good way?
What you have should be working just fine. You are correctly executing and parsing the results of the request off the UI thread. However, there are a couple minor things you can do to make it clearer.
stringArray looks like a field on the AsyncTask. This is not necessary the way you have the AsyncTask defined since you are already passing the stringArray directly into the onPostExecute() method. You should instead declare stringArray directly in the doInBackground() method.
Other thing I noticed is it looks like you might be keeping a reference to your Activity in the AsyncTask based on what you are doing in onPostExecute(). You are calling this.obj.setFeedsData(result);. If your AsyncTask is an inner class of the Activity using it you can call setFeedsData(result); directly instead.
If your AsyncTask is not an inner class it is usually best to pass the results back to the object interested in them through an interface in case you need to reuse the AsyncTask elsewhere.
Related
I am totally new to android and trying to develop a basic application. I have used the default Navigation Drawer Activity from android while creating the project.
Basically, I am getting an exception when I am making an HTTP get req upon a button click. I have created a button that is all working fine. The button is created inside the HomeFragment.java.
Here is the code -
final Button button = root.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// new ApiCall("637", "22-05-2021", textView).start();
try {
// String finalUrl = address+"district_id="+this.district_id+"&date="+this.date;
URL url = new URL("https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/findByDistrict/?district_id=637&date=22-05-2021");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "PostmanRuntime/7.26.10");
con.setRequestProperty("Accept-Language", "en_US");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
//Exception
BufferedReader in = new BufferedReader(new InputStreamReader( con.getInputStream())); // here exception coming////////////////////
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
} catch(MalformedURLException e) {
System.out.println("Malformed URL: " + e.getMessage());
textView.setText("Malformed");
} catch(IOException e) {
System.out.println("IOException: " + e.getMessage());
textView.setText("Exception");
}
catch (Exception e){
textView.setText("Exception");
e.printStackTrace();
}
}
});
This code of calling HTTP get req is all working fine when I do it purely in java in IntelliJ Idea.
I don't know why am I getting exceptions here.
Let me know
Thanks,
Akhi
As #Bhardwaj suggested, you can't make network calls in the main thread in Android. Create a background thread like this:
class RetrieveRemoteData extends AsyncTask<String, Void, YourResponseModelClass> {
private Exception exception;
protected YourResponseModelClass doInBackground(String... urls) {
// new ApiCall("637", "22-05-2021", textView).start();
try {
// String finalUrl = address+"district_id="+this.district_id+"&date="+this.date;
URL url = new URL("https://cdn-api.co-vin.in/api/v2/appointment/sessions/public/findByDistrict/?district_id=637&date=22-05-2021");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "PostmanRuntime/7.26.10");
con.setRequestProperty("Accept-Language", "en_US");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
//Exception
BufferedReader in = new BufferedReader(new InputStreamReader( con.getInputStream())); // here exception coming////////////////////
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
in.close();
} catch(MalformedURLException e) {
System.out.println("Malformed URL: " + e.getMessage());
textView.setText("Malformed");
} catch(IOException e) {
System.out.println("IOException: " + e.getMessage());
textView.setText("Exception");
}
catch (Exception e){
textView.setText("Exception");
e.printStackTrace();
}
}
}
protected void onPostExecute(YourResponseModelClass responseObject) {
// write your code here what happens after getting response or exception
}
}
You can refer to this, this has a lot of detailed steps for your use case.
Additionally, try to include more details to your question like what exceptions are you getting to be more descriptive about your issues so that the contributors understand your question better and suggest you accurate solutions.
I have adopted the code in this Stack Overflow answer to successfully POST JSON from my Android app to a Python/Django server. Here is my (very close) adaptation of the POST code:
// In my activity's onCreate method
try {
JSONObject obj = new JSONObject(strJSON);
new postJSON().execute("https://www.placeholder.com/generate_json", obj.toString());
} catch (Throwable t) {
Log.e("JSON Error", "Could not parse malformed JSON: " + strJSON);
}
// Outside onCreate
private class postJSON extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String data = "";
HttpURLConnection httpURLConnection = null;
try {
httpURLConnection = (HttpURLConnection) new URL(params[0]).openConnection();
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(httpURLConnection.getOutputStream());
wr.writeBytes("PostData=" + params[1]);
wr.flush();
wr.close();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(in);
int inputStreamData = inputStreamReader.read();
while (inputStreamData != -1) {
char current = (char) inputStreamData;
inputStreamData = inputStreamReader.read();
data += current;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
return data;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.e("TAG", result);
}
}
I now want to access the HttpResponse returned by the server, which I think is contained in data (but I'm not sure about this). If data does contain the HttpResponse, I would like to print it in a Toast.
Does data already contain the HttpResponse from the server or do I need to take additional steps to get it from InputStream? If it is already there, where should I put my Toast.makeText code to print the HttpResponse (i.e. data) in a Toast?
The variable data is a String containing the response body from the server and will be available to you on your UI thread as the variable result in the method onPostExecute
There are many patterns for getting the result from an async task. Here is one simple way to do it, try this approach to get a toast.
Write your execution of the task as such:
// In your activity's onCreate method
try {
JSONObject obj = new JSONObject(strJSON);
new postJSON() {
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
}
}.execute("https://www.placeholder.com/generate_json", obj.toString());
} catch (Throwable t) {
Log.e("JSON Error", "Could not parse malformed JSON: " + strJSON);
}
I'm actually srugling with my application using HttpUrlConnection, I tried the simplest code found on the internet and still got a FatalShutDown in the logcat and I don't understand the problem.
Here is the code :
try {
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
response_textview.setText(total.toString());
urlConnection.disconnect();
}
catch (MalformedURLException e){
response_textview.setText(e.getMessage());
}
catch (IOException e){
response_textview.setText(e.getMessage());
}
And I got this in the logcat :
Thanks
Wrap your code with Asynktask doInBackground() method.
You need to make request in new thread. Probably, your code (it is only try catch) is running on main thread. This operation is denied. Try to use e.g. Thread.class to make request in new thread.
You shouldn't perform network operation on main thread. Use AsyncTask.
1. Create AsyncTask object and move your code into doInBackground method as mentioned below:
AsyncTask task = new AsyncTask<Void,String,String>(){
#Override
protected String doInBackground(Void... params) {
// perform your network operation here and return response
try {
URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader r = new BufferedReader(new InputStreamReader(in));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line).append('\n');
}
urlConnection.disconnect();
}
catch (MalformedURLException e){
return e.getMessage();
}
catch (IOException e){
return e.getMessage();
}
return total.toString();
}
protected void onPostExecute(String response){
// response returned by doInBackGround() will be received
// by onPostExecute(String response)
response_textview.setText(response);
}
};
2. Execute task
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
I've class with methods
class Wrapper {
public static String AuthIn(String Login, String Password){
String response = HTTPRequest.POST(client, GetAuthUrl(), RequestBuilder.AuthInVk(login, password));
System.out.println(response);
}
public static String GetInfoUser(){
String response = HTTPRequest.GET(client, "http://site1.com");
System.out.println(response);
}
}
When i call this methods in MainActivity class and get error message "Main thread ..... etc"
How write Wrapper class in AsyncTask ?
Here is a nice example taken from codexpedia, for more details please check their site.
public class MainActivity extends AppCompatActivity {
TextView tvWeatherJson;
Button btnFetchWeather;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvWeatherJson = (TextView) findViewById(R.id.tv_weather_json);
btnFetchWeather = (Button) findViewById(R.id.btn_fetch_weather);
btnFetchWeather.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new FetchWeatherData().execute();
}
});
}
private class FetchWeatherData extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... params) {
// These two need to be declared outside the try/catch
// so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7&appid=2de143494c0b295cca9337e1e96b00e0");
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
return forecastJsonStr;
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
tvWeatherJson.setText(s);
Log.i("json", s);
}
}
}
If you want to pass data into the async task doInBackground or onPostExcute and more check this stackoverflow comment : what-arguments-are-passed-into-asynctaskarg1-arg2-arg3
Keep in mind that your AsyncTask won't stop even when the activity has destroyed. A better way to create a network call from an activity is with an Handler Or just use an asyncHttp client lib such as ok-http , google volley :)
You always must perform network request form other thread than UI thread. So you can create abstarct class (network dispatcher) which extend AsyncTask or Thread or Runnable and add abstarct method which will be called in run/doInBackground/etc. Next implement abstarct method in your method. But it a little improvement to your boilerplate code. Also you can use JavaRx (AndroidRx) to perform networking method. Also you can use Retrofit with JavaRx.
EDIT
I see you edit your question. If you want use AsyncTask you should implement it and perform request in doInBackgroud
I want to start programming Android apps that can communicate with a server to receive/send data and store it on the server.
I have been reading about this and I think I only need to send the data to the server with POST request (perhaps a XML file since I may need to send images), then parse the XML on the server side, and do whatever I need.
To start I'm just trying to send some text through my app.
This is my Post class, for the AsyncTask use:
public class Post extends AsyncTask<String, Void, Boolean> {
Context context;
String response;
public Post (Context ctx){
context = ctx;
}
#Override
protected Boolean doInBackground(String... params) {
URL url;
HttpURLConnection conn;
try {
url = new URL("http://192.168.1.40/index.php");
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "text/xml; charset=\"utf-8\"");
conn.setDoInput(true);
conn.setDoOutput(false);
conn.connect();
String body = "<test>\"some testing\"</test>";
//Send POST
OutputStreamWriter output = new OutputStreamWriter(conn.getOutputStream(),"UTF8");
output.write(body);
output.flush();
output.close();
//Get response
String line = "";
InputStream is = conn.getInputStream();
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) sb.append(line);
response = sb.toString();
br.close();
is.close();
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public String getResponse(String s)
{
}
Using a button to send the request:
public class MainActivity extends ActionBarActivity {
Context ctx;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ctx = this;
Button b = new Button(this);
b.setText("Send POST");
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Post p = new Post(ctx);
p.execute();
while(p.getStatus() != AsyncTask.Status.FINISHED);
Toast.makeText(ctx,p.getResponse(),Toast.LENGTH_LONG).show();
}
});
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
params.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
addContentView(b,params);
}
And this is my server side php code:
<?php print_r($_POST);?>
I know there are a lot of posts about this stuff, I went through many of them but I can't figure out this problem.
The HttpURLConnection response code is 200 which means HTTP_OK.
In the index.php page the only output is: "Array ()".
When I debug, the response string is also "Array ()", the problem is that the status of the AsyncTask is "RUNNING" all the time.
P.S - I'm using wampserver as webserver
Thanks in advance.
EDIT: I followed Pawel advice and tried this before the Toast:
while(p.getStatus() != AsyncTask.Status.FINISHED);
The app crashed, so I guess it never gets the FINISHED status.
Also tried the AsyncTask.get() method, like this:
try {
Toast.makeText(ctx, p.get().toString(), Toast.LENGTH_LONG).show();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
Got a "false" in the Toast text wich means my p.doInBackground() completed the execution. Why do I still don't have any results?
LAST EDIT: I'm not giving up yet! After a lot of debugging and frustration I think I have found the problem. It was the PHP code! I was expecting it to show me in the browser the post request but It does not work that way apparently.
I changed it to this:
<?php file_put_contents('test.txt', file_get_contents('php://input')); ?>
Now I can see the file with the content.
My only problem with this is that if I remove the code to read the response from the server, it does not create the file. Is there something wrong or it's just normal behavior?
You should read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You know that Post is Asynchronous operation since it extends AsyncTask ? Which means that it can be completed after your invoke Toast.makeText(ctx,p.getResponse(),Toast.LENGTH_LONG).show();
Small hint:
Check in above linked documentation about methods:
public final Result get () and public final AsyncTask.Status getStatus ().
Now you should have your results availabe when it is done.