I am pretty new with the concept of asynctask and i have an asynctask that gets me a json from an api with parameter an then(postexecute) puts the content inside textviews to be shown(they are set visible after setting the text), the thing is i am trying to validate that the json isnt actually empty, and with my code i actually do that, but if the parameter i use is correct, the validation still detects that its empty, if i try to get it again(by pressing the button that triggers the asynctask) after 2 or three tries it will actually get it tho, i think its because i am doing it on the background, here is the asynctask
private class ConsultarDatos extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
//working=false;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
and here is what i am trying to do
btnGenerar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new ConsultarDatos().execute("https://api-adress/file.php?DNI=" + etDNI.getText().toString());
//while(working)
//{
//}
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
});
as i commented i tried to do a while that would wait until the textsviews are all set but that just crashed my app
I resolved it, just moved the the visibility set and validation to the end of the onPostExecute and just to be sure i put the toast in the exception too just so the user gets some feedback
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
Use something like https://www.getpostman.com/ to see what the result of your API call is. Right now it seems like you don't know what you're getting back, and how consistently it comes back. You need to validate that your server is sending you back valid data.
Using a json library to parse the JSON response, such as GSON or Moshi would help you out as well. Right now you're trying to get the values based on arbitrary numbers. You could be having an exception from just one field missing, but there's not enough info to tell. Gson is fairly easy to set up in my experience: https://github.com/google/gson
Related
Aim
In a fragment, I have a search bar which looks for online news about what the user typed. I would want to display these news (title + description + date of publication + ... etc.) in the GUI, as vertical blocks.
Implementation
Explanations
In the fragment, within the search event handling, I instanciated an asynchronous task and execute it with the good URL REST API I use to do the search.
In the asynchronous task, I make use of this REST API (thanks to the URL and some required parameters as an authorization key, etc.). When my asynchronous task gets answered, it must update the fragment's GUI (i.e.: it must vertically stack GUI blocks containing the titles, descriptions, etc. of the got news).
Sources
You will find sources in the last part of this question.
My question
In the asynchronous task (more precisely: in its function that is executed after having got the answer), I don't know how to get the calling fragment. How to do this?
Sources
Fragment part
private void getAndDisplayNewsForThisKeywords(CharSequence keywords) {
keywords = Normalizer.normalize(keywords, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", "");
new NetworkUseWorldNews().execute("https://api.currentsapi.services/v1/search?keyword=" + keywords + "&language=en&country=US");
}
Asynchronous task part
public class NetworkUseWorldNews extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String[] urls) {
StringBuilder string_builder = new StringBuilder();
try {
URL url = new URL(urls[0]);
HttpsURLConnection https_url_connection = (HttpsURLConnection) url.openConnection();
https_url
_connection.setRequestMethod("GET");
https_url_connection.setDoOutput(false);
https_url_connection.setUseCaches(false);
https_url_connection.addRequestProperty("Authorization", "XXX");
InputStream input_stream = https_url_connection.getInputStream();
BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(input_stream));
String line;
while((line = buffered_reader.readLine()) != null) {
string_builder.append(line);
}
buffered_reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return string_builder.toString();
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject news_response_http_call = new JSONObject(result);
switch(news_response_http_call.getString("status")) {
case "ok":
JSONArray news = news_response_http_call.getJSONArray("news");
for(int i = 0; i < news.length(); i++) {
JSONObject a_news = news.getJSONObject(i);
String title = a_news.getString("title");
String description = a_news.getString("description");
String date_of_publication = a_news.getString("published");
String url = a_news.getString("url");
String image = a_news.getString("image");
System.out.println(title + ": " + date_of_publication + "\n" + image + "\n" + url + "\n" + description);
WorldNewsFragment world_news_fragment = ...;
}
break;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
If I am right, you want to update View of your caller Fragment. if FragmentA called service then FragmentA should be update.
However the approach you are asking is wrong. Instead of getting caller Fragment in your AsyncTask response. You should do it with Callback.
So now you will need to pass callback in AsyncTask. So instead of posting full code, here are already answers with this problem.
Finally your calling syntax will look like.
NetworkUseWorldNews task = new NetworkUseWorldNews(new OnResponseListener() {
#Override
public void onResponse(String result) {
// Either get raw response, or get response model
}
});
task.execute();
Actually I am still very unclear about your question. Let me know in comments if you have more queries.
Must checkout
Retrofit or Volley for calling Rest APIs
Gson for parsing JSON response automatically to models
I am working on an app in Android Studio that downloads a json file from a php query, however when I have managed to read the contents of the json file from android, this contents does not behave as text, because when comparing a text entered from the app against the read from the json file, it never matches despite being the same text. (Example: password text from app and the password from the json file).
Php Code:
<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);
include('functions.php');
$col=$_GET["col"];
$colbus=$_GET["colbus"];
$tabla=$_GET["nomtable"];
$todfilas=$_GET["todasf"];
$dbuser =$_GET["username"];
$dbpass=$_GET["password"];
$dbbase=$_GET["dbname"];
//echo "$todfilas <br>";
if($todfilas == 1){
$sqlt="SELECT * FROM $tabla";
}else{
$sqlt="SELECT * FROM $tabla WHERE $col='$colbus'";
}
//echo "$sqlt <br>";
if($resultset=getSQLResultSet($sqlt,$dbuser,$dbpass,$dbbase)){
while ($row = $resultset->mysqli_fetch_array(MYSQLI_NUM)){
echo json_encode($row);
}
}
?>
Code from Android Studio:
private class ConsultData extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "No es posible cargar pagina web o la direccion es invalida!";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
Log.d("Password:",ja.getString(7)+"="+logPass.getText().toString().trim());
logPass2.setText(ja.getString(7).trim());
String pass1 =logPass2.toString();
String pass0 = logPass.toString().trim();
if(pass0==pass1){
showAlertDialog("Session:","login is valid!");
} else{
showAlertDialog("Session:","password does not match!");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
I'm not sure if the way to create the json file in the php query is the problem? because I can see the contents of the json array in Android Studio, but when I compare text from json array, they do not match even if they are the same ("123" = "123").
As seeing your code you doing so many mistakes like you are getting textview value thats not right way
change code like this
String pass1 =logPass2.getText().toString();
String pass0 = logPass.getText().toString().trim();
Also comparsion of string
if(pass0.equals(pass1)){
showAlertDialog("Session:","login is valid!");
} else{
showAlertDialog("Session:","password does not match!");
}
instead of this
if(pass0==pass1){
showAlertDialog("Session:","login is valid!");
} else{
showAlertDialog("Session:","password does not match!");
}
I want something like that.i have a button and 2 textbox when user put their username and password and then click on login button then login action will be performed and then welcome the user and go to another page .my code was like that:
try {
Connection.Response res = Jsoup.connect("URL")
.data("log", "abcd", "pwd", "12345", "wp-submit", "প্রবেশ", "redirect_to", "url", "testcookie", "1")
.method(Method.POST)
.execute();
Map<String, String> cookies = res.cookies();
Document doc2 = Jsoup
.connect("new_url")
.cookies(cookies)
.get();
s = doc2.text().toString();
t.setText(s);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
t.setText("no");
}
But login action cant be successful and here it always shows "no".
How can i successfully do that???
i think it is threading problem. because your internet request is on main UI-Thread. test this:
private class AsyncExecution extends AsyncTask<Void, Void, Void>{
boolean tracker = false;
String s = "";
#Override
protected Void doInBackground(Void... params) {
try {
Connection.Response res = Jsoup.connect("http://www.kuetlive.com/wp-login.php")
.data("log", "abcd", "pwd", "12345", "wp-submit", "প্রবেশ", "redirect_to", "http://www.kuetlive.com/wp-admin/", "testcookie", "1")
.method(Method.POST)
.settimeout(60000)//time set for the connection 1 min
.execute();
Map<String, String> cookies = res.cookies();
Document doc2 = Jsoup
.connect("http://www.kuetlive.com/wp-admin/profile.php")
.cookies(cookies)
.get();
s = doc2.text().toString();
tracker = true;
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e("tag", e.toString());
tracker = false;
}
}
--- // } // --- i add this by mistake, delete this
#Override
protected void onPostExecute(Void result) {
if(tracker){
t.setText(s);
}else{
t.setText("no");
}
}
}
and call it as
new AsyncExecution().execute();
Edited:
you cannot perform an internet request on main UI-Thread. that is why u need a different thread. now u could implement a simple thread instead of AsyncTask. then why i suggest u to use AyncTask. the answer is, u cannot update your UI from a simple Thread. that is why u need AsyncTask, because AsyncTask gives u flexibility to update UI but execute your method in different Thread beside UI-Thread.
I tried to refer similar question on SO, but didn't got any help.
In my android app, I'm planning to implement Recent Quote the user has visited i.e. similar to recently visited pages on web.
Following are the steps I'm following:
1.) Whenever user opens any company view, fetch the company symbols from database
2.) Then store the current symbol along with dateTime in database.
3.) For all symbols fetched from database, Fetch their current value and %Change and display Company name, current value and %Change in a list.
The problem arises in the ASyncTask class as postExecute method doesn't allow it's return type to be any other than void.
Am I doing anything wrong?
Any help will be life saver !!!
String[] rsym,rcmp,rchg;
rdbM = new RecentDBManager(CompanyView.this);
try {
Calendar date1 = Calendar.getInstance();
SimpleDateFormat dateformatter = new SimpleDateFormat(
"dd/MM/yyyy HH:mm:ss");
String currentdate = dateformatter.format(date1.getTime());
rdbM.openDB();
//STEP 1
rsym = rdbM.getRecent_sym();
//STEP 2
rdbM.setData(currentsymbol, currentdate);
rdbM.closeDB();
} catch (Exception e) {
throw new Error(" *** ERROR in DB Access *** "+ e.toString());
}
//STEP 3
for(int i=0;i<rsym.length;i++)
{
DownloadRecentQuote quotetask = new DownloadRecentQuote();
recentquotetask
.execute(new String[] { "http://abc.com/stockquote.aspx?id="
+ rsym[i] });
//CURRENT VALUE and %CHANGE which should be returned from ASyncTask class
rcmp[i]=valuearr[0];
rchg[i]=valuearr[1];
}
list1 = new ArrayList<HashMap<String, String>>();
HashMap<String, String> addList1;
for (int i = 0; i < limit; i++)
{
addList1 = new HashMap<String, String>();
addList1.put(RecentSym_COLUMN, rsym[i]);
addList1.put(RecentCMP_COLUMN, rcmp[i]);
addList1.put(RecentChg_COLUMN, rchg[i]);
list1.add(addList1);
RecentAdapter adapter1 = new RecentAdapter(
CompanyView.this, CompanyView.this, list1);
listrecent.setAdapter(adapter1);
}
private class DownloadRecentQuote extends AsyncTask<String, Void, String> {
/* Fetching data for RecentQuote information */
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
arr1 = result.split("#");
if (arr1[0].length() != 0) {
if (arr1[0].equals("1")) {
arr = arr1[1].split(";");
//RETURN 2 STRINGS
String valuearr[];
valuearr[0] = arr[3];
valuearr[1] = arr[6].concat("%");
//return valuearr;
}
}
}
postExecute() can't return a value because who or what would it return to? Your original method that invoked the AsyncTask is gone because your AsyncTask is running in the background. It's asynchronous meaning when AsyncTask.execute() returns it's still running in the background, and hence postExecute() can't return a value because there's nothing to return it to.
Instead your AsyncTask needs a reference back to your Activity or some other object so it can post your values back to it. In your code the lines after you call execute() can't be there because your task hasn't finished. Instead you should create a method called updateSymbol( currentPrice, percentChange), move all that code below execute() in there, and in your AsyncTask you should pass a reference to the Activity. Then call updateSymbol( currentPrice, percentChange ) from the onPostExecute() method.
But, be careful if you have a reference back to an Activity it can be destroyed while your doInBackground() is running, and when postExecute() runs it should just drop the results or not attempt to update the UI. For example, the user rotates their phone causing the Activity to be destroyed. I find it best to hold a reference to the AsyncTask in the activity so it can cancel() it if the Activity is destroyed. You can call AsyncTask.cancel() then check if your task was canceled like:
public void postExecute( String result ) {
if( !isCanceled() ) {
// do your updating here
activity.setSymbol( result );
}
}
It's really easy to create a base class for all Activities so you can easily keep track of AsyncTasks running:
public class BaseActivity extends Activity {
List<AsyncTask> runningTasks;
public void onStop() {
for( AsyncTask task : runningTasks ) {
task.cancel(true);
}
}
public AsyncTask start( AsyncTask task ) {
runningTasks.add( task );
return task;
}
public void done( AsyncTask task ) {
runningTasks.remove( task );
}
}
Some quick pointers. You don't need execute( new String[] { "blah" + blah } ). Varargs in Java allow you to do this. execute( "blah" + blah ). You also are catching exceptions and continuing without really handling them. It will be hard when something really happens because your app catches them, and just continues as if nothing happened. If you get an error you might want to provide some feedback to the user and stop trying to execute that process. Stop, show an error to the user, and let them do the next thing. Move the catch blocks to the bottom of the methods.
Essentially, AsyncTask.onPostExecute() is where you do whatever you want to do after AsyncTask's doInBackground() is executed and the execution result gets returned. This should be considered the best practice.
When AsyncTask().execute() is called from the UI thread (note that this method must be called from the UI thread), the Android framework creates a worker thread and starts running whatever you wrote in AsyncTask.doInBackground() on this worker thread. At this point (after calling new AsyncTask().execute()), the UI thread continues to execute code after new AsyncTask().execute(). So now during run time, you have two threads (UI and worker thread) both running simultaneously.
But where and when does the AsyncTask execution result get returned from the worker thread back to the UI thread?
The point where your worker thread (doInBackground()) finishes and returns to the UI thread is AysncTask.onPostExecute(). This method is guaranteed to be called by the framework on the UI thread as soon as AsyncTask finishes. In other words, we don't care where and when AsyncTask.onPostExecute() gets called at run time, we just need to guarantee it will be called ultimately at some stage in the future. This is the reason why this method does not return an execution result - instead, it requires that the execution result gets passed in as the only method parameter from doInBackground().
In addition, the Android API provides a way to return an AsyncTask execution result at coding time, AsyncTask.get():
MyAsyncTask myAsyncTask = new MyAsyncTask();
// This must be called from the UI thread:
myAsyncTask.execute();
// Calling this will block UI thread execution:
ExecutionResult result = myAsyncTask.get();
Bear in mind that AsyncTask.get() will block the calling thread's execution, and you will probably get an ANR exception if you call it on the UI thread. This is the payload of using AsyncTask.get(), by calling it on the UI thread, you are actually making your AsyncTask (worker thread) run synchronously with UI thread (by making UI thread wait). To sum up, this is doable but not recommended.
Just for future reference, because this post is a little old:
I have created an Activity class which has an onStart() method and a separate class for the AsyncTask. Based on my test, after the doInbackground() method the result will be sent to the activity first and after that onPostExecute() will run. This is because based off of logcat, I have my first response data (sent by server) first, then this response will show again from the activity and the last the message in onPostExecute() will show.
Code for the activity:
#Override
protected void onStart() {
super.onStart();
String str = "***";
if(isConnectedToInternet()){
myAsyncTask.execute();
try {
if(myAsyncTask.get())
str = myAsyncTask.getResponseMsg();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (CancellationException e) {
e.printStackTrace();
}
}
Log.i("Data returned by server2:", str);
}
AsyncTask code:
public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
private URL url;
private HttpURLConnection conn;
private String strResponseMsg;
public MyAsyncTask(String url) throws MalformedURLException{
this.url = new URL(url);
}
#Override
protected void onPreExecute() {
Log.i("Inside AsyncTask", "myAsyncTask is abut to start...");
}
#Override
protected Boolean doInBackground(Void... params) {
boolean status = false;
try {
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(Manager.ConnTimeout);
conn.setReadTimeout(Manager.ReadTimeout);
int responseCode = conn.getResponseCode();
Log.i("Connection oppened", "Response code is:" + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
if (in != null) {
StringBuilder strBuilder = new StringBuilder();
// Read character by character
int ch = 0;
while ((ch = in.read()) != -1)
strBuilder.append((char) ch);
// Showing returned message
strResponseMsg = strBuilder.toString();
Log.i("Data returned by server:", strResponseMsg);
status = true;
}
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return status;
}
#Override
protected void onPostExecute(Boolean result) {
Log.i("Inside AsyncTask", "myAsyncTask finished its task. Returning data to caller...");
}
public String getResponseMsg(){
return strResponseMsg;
}
}
I want to show Facebook Page's Notes items with those comments and likes using Graph API.
To do that, I'm using the asyncFacebookRunner in Facebook SDK.
Steps are like this:
call asyncFacebookRunner.request to get Note Item with PageId
mAsyncRunner.request(sAPIString, new NotesRequestListener(), null);
Response has come. ( I can't highlight function call. Sorry for inconvenient to find it.)
public class NotesRequestListener implements com.facebook.android.AsyncFacebookRunner.RequestListener
{
/**
* Called when the request to get notes items has been completed.
* Retrieve and parse and display the JSON stream.
*/
#Override
public void onComplete(String response, Object state) {
// TODO Auto-generated method stub
Log.i("My_TAG", "onComplete with response, state");
try
{
// process the response here: executed in background thread
final JSONObject json = new JSONObject(response);
JSONArray arrNotesItems = json.getJSONArray("data");
int l = (arrNotesItems != null ? arrNotesItems.length() : 0);
// !!!!
// This has another request call
// !!!!
final ArrayList<WordsItem> newItems = WordsItem.getWordsItems(arrNotesItems,getActivity());
WordsActivity.this.runOnUiThread(new Runnable() {
public void run() {
wordsItems.clear();
wordsItems.addAll(newItems);
aa.notifyDataSetChanged();
}
}); // runOnUiThread
} // try
catch (JSONException e)
{
Log.i("My_TAG", "JSON Error in response");
} // catch
} // onComplete
... other override methods ...
} // Request Listener
< Another Class >
public static ArrayList<WordsItem> getWordsItems(JSONArray arrJSON, Activity activity) {
ArrayList<WordsItem> wordsItems = new ArrayList<WordsItem>();
int l = (arrJSON != null ? arrJSON.length() : 0);
try {
WordsItem newItem;
for (int i=0; i<l; i++) {
JSONObject jsonObj = arrJSON.getJSONObject(i);
String sTitle = jsonObj.getString("subject");
String sNoteID = jsonObj.getString("id");
... get another fields here ...
newItem = new WordItem(...);
// !!!!
// This has request call for comments
// !!!!
ArrayList<CommentItem> arrComment = getUserComments(sNoteID);
wordsItems.add(newItem);
}
} catch (Exception e) {
e.printStackTrace();
}
return wordsItems;
} // getWordsItems
call another asyncFacebookRunner.request to get comments of item(with NoteID)
in getUserComments
mAsyncRunner.request(sAPIString, new CommentRequestListener(), null);
Before getting comments(OnComplete in CommentRequestListener has not called), getWordsItems returns item array.
So I can't see the comments.
How can I wait to update UI till getting comments?
(It's so ironic to synchronize asynchronized calls.)
Thanks in advance.
Use facebook object which has non-asynchronous request method.
You need not implement listener method.
So, I suggest below means.
use mAsyncRunner.request for first request call.
use mFacebookRunner.request for second request call.
I hope it may help you:-)
Using FQL - Facebook Query Language you can easily get all this information about any particular note info
, Also to get likes on that and comments over it as like examples given in the links.