I need to display "Wait a moment..." message via Toast while the app tries to fetch some data from the internet that can take couples of seconds depending on the internet connection and the load on the server.
the http connection is made through a AsyncTask.
What I am doing is that I display the message by : "Toast.makeText" method, then I enter a "while" loop that breaks when the execute method of the AsyncTask finishes, then I display some results on the Activity.
The problem is that the Toast dosen't appear until the while loop breaks!
I tried to replace the Toast with displaying the message in TextView with setText , but the same happened, the message displayed after the while loop breaks!
any thoughts? My Code looks like this:
waitToast = Toast.makeText(this,R.string.WaitText, Toast.LENGTH_SHORT);
waitToast.show();
.........
.........
new DownloadFilesTask().execute();
dataRetrieved = false;
while (!dataRetrieved){ }
........
And in the doInBackground:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
InputStream in = null;
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setConnectTimeout(4000);
in = urlConnection.getInputStream();
in = new BufferedInputStream(urlConnection.getInputStream());
url_input = readStream(in);
........
catch (Exception e) {
e.printStackTrace();
}
finally{
dataRetrieved = true;
urlConnection.disconnect();
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Do not do this. You are blocking the ui thread with your while loop. That's why your Toast does not show up.
Remove your while and override onPostExecute() in your AsyncTask. This methods runs on the Ui thread, unlike doInbackground so you can update Activity UI.
use this method in asynktask:
#Override
protected void onPreExecute() {
super.onPreExecute();
// Show Toast
Toast.makeText(context,"text",Toast.LENGTH_LONG).show();
}
And remember "onPostExecute" and "onPreExecute" Can Change UI , Don't Change UI At "doInBackground" .
Related
I would like to explain the situation to introduce you into my problem. I have an AsyncTask on Android which tries to connect to a database through jdbc driver. On my doInBackground, I have the following instruction:
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
The problem comes when I try to cancel the AsyncTask and that the task is trying to execute the previous instruction.
I want the user to have the option of cancelling the AsyncTask and immediately execute it again to connect to another database. When I cancel the first AsyncTask and I start another one, until the first task achieves to get the connection and finish his doInBackground method, the second task can't get its own connection.
After this complicated explanation, I think that it is not possible for the DriverManager to execute getConnection while another instance is executing the same method.
What I want to achieve is: once the user cancels the first AsyncTask, abort the execution of DriverManager.getConnection(), in order to allow a second task to execute this instruction as soon as possible, without making the user to wait until doInBackground finishes on first task.
I copy part of my code:
class DBConnectionTask extends AsyncTask <ConnectionInfo,Void,Void>{//connection using JDBC driver
private ConnectionInfo connInfo;
private Connection conn;
private Statement st;
private Activity activity;
GlobalData g;
String url;
ProgressDialog loadingCircle;
public DBConnectionTask(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute(){
loadingCircle=ProgressDialog.show(activity,"","Trying to connect, please wait...",false);
loadingCircle.setCancelable(true);
loadingCircle.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
// actually could set running = false; right here, but I'll
// stick to contract.
cancel(true); //cancela asynctask y no hace el onPostExecute
}
});
}
protected Void doInBackground(ConnectionInfo... params) {
connInfo = params[0];
connect();
return null;
}
And the connect() method
protected void connect(){
try
{
//part of the code here is ommited
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
System.out.println("Acaba doInBackGround " + connInfo.getAlias());
//st = conn.createStatement();
Intent intent = new Intent(activity, SqlMenu.class);
activity.startActivity(intent);
}
catch (SQLException e)
{
System.err.println(e);
cancel(true);
}
catch (Exception e)
{
System.err.println(e);
cancel(true);
}
finally {
loadingCircle.dismiss();//loadingCircle.dismiss();
}
}
I want to make the task cancelled interrupt its attempt to connect to database just at the moment the user cancels the task.
you can not interrupt this DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword()); statement as it is predefined method and you don't have any control over it. But you can do interrupt at some points where predefined methods are getting finished.
See comments following in your edited code:
protected void connect(){
try
{
//part of the code here is ommited
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
conn = DriverManager.getConnection(url, connInfo.getUserName(), connInfo.getPassword());
System.out.println("Acaba doInBackGround " + connInfo.getAlias());
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
// query data from database .
// if you are going to use a loop to extract data form cursor, same condition can be used in that loop also.
// so whenever ayncTask is cancelled it can be interrupted.
if(isCancelled())
{
return; // return control if ayncTask is cancelled.
}
Intent intent = new Intent(activity, SqlMenu.class);
activity.startActivity(intent);
}
catch (SQLException e)
{
System.err.println(e);
cancel(true);
}
catch (Exception e)
{
System.err.println(e);
cancel(true);
}
finally {
loadingCircle.dismiss();//loadingCircle.dismiss();
}
}
In the ViewPager+Fragment by FragmentPagerAdapter mode. I want to known How to load data for Internet.
I want to implement:
1.Only select the current pager can to load data
2.Only performing the load data once to every pager
I search the some Answers:
userd the callBack method,I see the lifecyle. It Callback after onCreate. After that dont callBack. if load data
so fast . onCreateVie and onActivityCreate don't callBack. View not find. so this method
not improper.
boolean isFist
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isFist&&isVisibleToUser){
// int this load data
}
}
so,who can give me good Solutions? Please Forgive my broken English.
This example, shows how to use AsyncTask:
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
So:
onPreExecute - Runs on UI Thread. (do nothing, or put a progress dialog)
doInBackground - Runs on Background Thread. (download data here)
onPostExecute - Runs on UI Thread, recevies the doInBackground results. (show/update data here)
Note: Right now I do not have time to put this example in the context of your specific question, but AsyncTask is your best option.
EXAMPLE:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
new LoadJsonTask().execute("http://example.com/data.json");
}
private class LoadJsonTask extends AsyncTask<String, Integer, String > {
ProgressDialog dialog ;
protected void onPreExecute (){
// this happens on UI Thread
// dialog, of course, is optional.
dialog = ProgressDialog.show(getActivity() ,"Wait a moment", "Downloading...");
}
protected String doInBackground (String... params){
// this happens on background...
InputStream input = null;
HttpURLConnection connection = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
// expect HTTP 200 OK
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
// download the file
input = connection.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
result.append(line);
}
return result.toString();
} catch (Exception e) {
// handle exceptions :p
return null;
} finally {
// cleanup here
}
}
protected void onPostExecute(String results){
// Do something with results
dialog.dismiss();
}
}
}
I'm developing an android application , my problem is that I can't execute my asyntask class after clicking on a button but it works normally when I called it in my program
I have in logcat the error : "Only the original thread that created a view hierarchy can touch its views.”
here is my class :
ts.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
jr=2;
emp trs=new emp();
trs.execute();
}
});
emp t=new emp();
t.execute();
private class emp extends AsyncTask<Void,Void,Void>{
#Override
protected Void doInBackground(Void... params) {
try{
url = new URL("....");
HttpURLConnection httpconn = (HttpURLConnection)url.openConnection();
httpconn.connect();
if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK){
BufferedReader input = new BufferedReader(new InputStreamReader(httpconn.getInputStream()),8192);
while ((line = input.readLine()) != null) {
ja = new JSONArray(line);}
for (int i = 0; i < ja.length(); i++) {
JSONObject jo = null;j=0;
jo = (JSONObject) ja.getJSONObject(i);
ch = jo.getString("bgcolor");
ch1=jo.getString("duree_heure");
ch2=jo.getString("debut_heure");
ch4=jo.getString("matiere");
j=Integer.parseInt(ch2);
ch2=trans(j,ch1);
ch5=jo.getString("idsalle");
ch6=salle(ch5);
addvi(v,ch,ch6,ch2,ch4);
}
input.close();
}
}catch (JSONException e){
System.out.print("vérifier !");e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
return null;
}
}
so can anyone helps me please ?
It's caused by the fact that when you are inside doInBackground you are inside another thread too and since it's forbidden to edit/remove/etc views create from another thread (in this case UI thread) it throw this error.
Since you didn't posted the full code, the only thing which could case this problem is addvi(v,ch,ch6,ch2,ch4); so you should use runOnUiThread method of Activity to execute the method from the main thread.
But you should rethink your logic to work better with Asynctask methods onPreExecute / onPostExecute which is used to work with UI and are called and execute in the main thread (UI thread).
P.S To work better with the methods i said above, you should know what means the three generic in the extendsAsyncTask<Params, Progress, Result>
The three types used by an asynchronous task are the following:
Params, the type of the parameters sent to the task upon execution.
Progress, the type of the progress units published during the background computation.
Result, the type of the result of the background computation.
Edit: As other noticed in comments you have onProgressUpdate too which is invoked by you from doBackground method using publishProgress
you cannot touch or modify view in the doInBackground function of asynctask all UI work need to be done on UI thread or main thread.I think you are doing some UI work so do it in onPostExecute() method
#Override
protected InputStream doInBackground(String... url){
try {
InputStream stream = downloadXml(url[0]);
new ParseXml(stream); //for testing porpuses: outputs ok to logcat
return stream;
} catch (IOException e) {
Log.d("dbg","exception");
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(InputStream result) {
if (result != null) {
new ParseXml(result); //crashes the app
}
Log.d("dbg","postexecute triggered ok");
}
Code is pretty self explanatory i think, i tried changing the passing type to just Object and type casted it where needed but it didn't worked either.
Is there anything undocumented in sdk that i should know of ?
obviously, Crash.. You are doing lengthy (also may be network related) operation in MainUI Thread. as onPostExecute() of AsyncTask runs on In MainUI Thread only. So always keep it in doInBackground().
This code line new ParseXml(result); should be in doInBackground() of AsyncTask.
Update:
So complete the Parsing of XML in doInBackground() and only pass the result in onPostExecute() if only you want to reflect the updation on Application UI.
When my users click the login button I want to hit my webservice. I have the following code to do so.
public void onClick(final View view) {
String orgKey = inputCompany.getText().toString();
new getAppInfo().execute("http://example.webservice.com");
Here is my getAppInfo
private class getAppInfo extends AsyncTask<String, Void, String> {
/** The system calls this to perform work in a worker thread and
* delivers it the parameters given to AsyncTask.execute() */
#Override
protected String doInBackground(String... urls) {
String xml = null;
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urls[0]);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
xml = EntityUtils.toString(httpEntity);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// return XML
return xml;
}
/** The system calls this to perform work in the UI thread and delivers
* the result from doInBackground() */
#Override
protected void onPostExecute(String result) {
Document doc = GetDomElement(result); // getting DOM element
NodeList nl = doc.getElementsByTagName("details");
getChildElements(nl);
}
The doBackground is running but the onPostExecute is not. I have moved it out of the on click and it has worked but I need it inside the onClick.
How can I get it to run the onPostExecute inside my onClick?
The syntax is correct you might be getting an exception in the background process, stopping the background thread. put a log statement at the end of your doInBackground or add a catch (Throwable t) to your try.
Have faith - it WILL be called as long as doInBackground completes successfully.
As an aside, you should do your DOM parse in the background as well - at the moment you are doing it in the UI thread which may cause ANR popups.
First, a general pointer - class names in Java are conventionally capitalized CamelCase, method names are lowercase camelCase.
On to your question - are you by any chance exiting the Activity or closing the Dialog that spawned the task? If it works outside that onclick handler, my guess is that something is destroying the Handler object that the AsyncTask is trying to execute that method on.
Try posting a Runnable (which executes the AsyncTask) on the current Activity's Handler.
onPostExecute will always be called once doInBackground is completed. Try to Log something in onPostExecute to confirm this behavior.
add a general catch statement in your doInBackground method.
catch(Exception e){
e.printStackTrace();
}