I'm currently working on a android app in which I use asynctasks to carry out json rest request. I've got this working fine. I have also got a progress dialog being made visible on the preexecute then dismissing it on the postexecute all working fine. see code below.
#Override
protected void onPreExecute(){
Variables var = Variables.getInstance();
Variables.getInstance().showPd(ProgressDialog.show(Variables.getInstance().getContext(), var.getValue("loggingin_text"), var.getValue("pleasewait"), true, false));
}
protected void onPostExecute( JSONObject[] loginresponse ){
Variables.getInstance().dismisspd();
try {
JSONObject responseheader = loginresponse[0].getJSONObject("commonInputParameters");
if (responseheader.getString("status").equals("SUCCESS")) {
Variables.getInstance().setUsername( loginresponse[1].getString("username") );
Variables.getInstance().setSessiontoken(responseheader.getString("userSessionToken"));
delegate.onRequestCompletion( true );
} else {
delegate.onRequestCompletion(false);
}
}catch (JSONException je ) {
this.cancel( true );
}
}
final Button _loginBTN = ( Button ) findViewById(R.id.loginBTN );
_loginBTN.setText( vars.getValue( "loginbtn_text" ) );
_loginBTN.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Functions functions = Functions.getInstance();
if( functions.isNetworkAvailable(getApplicationContext())) {
if (functions.fullypopulated(new Object[]{_username, _password})) {
LoginRequest login = new LoginRequest(new responseInterface() {
#Override
public void onRequestCompletion(boolean successfulRequest) {
Variables.getInstance().dismisspd();
if ( !successfulRequest ) {
functions.showDialog(Variables.getInstance().getValue("login_err"), findViewById(R.id.input_username));
functions.clearEditText(new EditText[]{_username, _password});
functions.setError(new EditText[]{_username, _password});
} else {
Intent intent = new Intent(getApplicationContext(), NavigationHandler.class);
startActivity(intent);
finish();
}
}
#Override
public void onRequestCompletion(String requestResponse) {}
#Override
public void onRequestCompletion(int requestResponse) {}
#Override
public void onRequestCompletion(float requestResponse) {}
});
Map<String, String> loginDetails = new HashMap<String, String>();
loginDetails.put("username", _username.getText().toString());
loginDetails.put("password", _password.getText().toString());
login.execute(loginDetails);
} else {
functions.showDialog(Variables.getInstance().getValue("no_details"), findViewById(R.id.input_username));
functions.clearEditText(new EditText[]{_username, _password});
functions.setError(new EditText[]{_username, _password});
}
}
else {
functions.showDialog(Variables.getInstance().getValue("no_network"), findViewById(R.id.input_username));
}
}
});
The problem is that when I try to work in a time out into the async task the progress dialog shows but not until after it has completed and at which point I can't remove it.
This is how I'm trying to run it with a time out.
try{
login.execute(loginDetails).get( 5000, TimeUnit.MILLISECONDS );
}catch (InterruptedException ie ){
}catch (ExecutionException ee){
}catch (TimeoutException te ){
login.cancel(true);
}
Yes I know the catches are empty right now.
UPDATE:
Never mind looking at the get function again, it actually blocks the UI thread that is why the Progress Dialog isn't showing until the ASyncTask has completed. Is there anyway to implement a timeout feature?
Cancelling a task
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns.
From http://developer.android.com/reference/android/os/AsyncTask.html
Mind the bold pieces ... as to my understanding, you should dismiss the Dialog in onCancelled() in case of Timeout.
Related
I have a function that requests data from an api and fills an array list.
Then i use the data from the arraylist in a textView. The problem that occurs is that the function takes time to load the data and the code in which i set the text view gets executed before the arraylist is populated resulting in a crash...I have used Countdown latch to tackle this problem but it isnt working
i have used it wrong most probably.
apirequest function
private void RequestDataFromApi() {
DotaAPIEndpoints textApiService= API_Client.getClient().create(DotaAPIEndpoints.class);
Call<List<Heroes>> call2 =textApiService.getHeroes();
call2.enqueue(new Callback<List<Heroes>>() {
#Override
public void onResponse(Call<List<Heroes>> call, Response<List<Heroes>> response) {
hero_list.clear();
hero_list.addAll(response.body());
}
#Override
public void onFailure(Call<List<Heroes>> call, Throwable t) {
Toast.makeText(MainActivity.this, "hero_list call failed!", Toast.LENGTH_SHORT).show();
}
});
requestLatch.countDown();
}
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
requestLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
textt.setText(hero_list.get(0).getHeroImg());
}
});
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
requestLatch.await();
You cannot call await on the UI thread. Calling await at this point in the above code is telling the UI thread to wait - if the UI thread is waiting, it cannot draw the screen updates, so the system will crash with an Activity Not Responding error.
Perhaps this helps, this is a way to safely allow the button to be clicked and not crash if the data has not loaded yet. (No need for a CountdownLatch at all)
setText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(hero_list.isEmpty()) {
Toast.makeText(MainActivity.this, "List not ready", Toast.LENGTH_SHORT).show();
return;
}
textt.setText(hero_list.get(0).getHeroImg());
}
});
I am making an app to do something in webview automatically.
I want to make a pause between two lines inside (for-loop) until page finished loading without using Thread.sleep because it freezing my application.
this is my code:
webview.loadUrl("http://**********");
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
for(int i=1;i<10;i++){
evaluateJavascript( "document.getElementById('select').value=" + i)
evaluateJavascript("document.getElementById('Search').click();")
//wait until finished loading
while( isloading() ){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
evaluateJavascript( "document.getElementById('any_select').value=5")
.
.
.
.
}
public boolean isloading(){
boolean isloading;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webview.evaluateJavascript("(function() { return document.getElementById(\"Loading\").style.display; })();", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
if(s.equals("none")){
isloading=false;
}else{
isloading=true;
}
}
});
}
if(isloading=true)return true;
if(isloading=false)return false;
}
If you don't want to use Thread.sleep then the alternative is to use AsyncTask in your application.
You can do your loading task in doInBackground() method of AsyncTask and call it using new AsyncTaskClass.execute();
You can go through it from here : http://developer.android.com/reference/android/os/AsyncTask.html
You can do something similar (instead of AsyncTask):
Edit:
Timer timer = new Timer();
while( isloading() ){
try {
timer.schedule( new TimerTask(){
public void run() {
//
}
}, delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
If you want to achieve, what i understand, that once your second line is called you want to stop there and when after 1000 ms you want to continue. You can do one thing, copy all the code after your second line and put that in run method of below code:
new Handler().postDelayed(new Runnable()
{
#Override
public void run() {
}
}, 1000);
It will execute you code after 1000ms
If you want to execute sequentially actions happening on UIThread and in backgrounds threads you should be looking for the Bolt Library by Parse/Facebook.
It apply Javascript promises to Android application.
You can go through it from here : https://github.com/BoltsFramework/Bolts-Android
I have placed the parse method inside onCreate method. But my problem is how to show the Android Loading... Dialog??
Parse.initialize(this, "a", "b");
ParseQuery query = new ParseQuery("Category");
query.findInBackground(new FindCallback() {
#Override
public void done(List<ParseObject> catObjects, ParseException arg1) {
Log.d("Catlength", String.valueOf(catObjects.size()));
for(int i =0; i<catObjects.size(); i++){
Log.d("lengthName"+String.valueOf(i), String.valueOf(catObjects.get(i).getInt("Id")));
Category category = new Category();
category.Name= catObjects.get(i).getString("CatName");
category.id= catObjects.get(i).getInt("Id");
categories.add(category);
}
if(categories.size()>0){
setListAdapter(new CategoryArrayAdapter(CategoryListActivity.this, R.layout.row_category, categories));
}
else{
Toast.makeText(CategoryListActivity.this, "Our servers are busy. Hit refresh..", 3000).show();
}
}
});
Everything works fine in the above code but I couldn't figure out how to show the Dialog.
I'm unable to use AsycTask also as parse sdk invokes its own thread in the background and before the findInBackground execution finishes, the doInBackground completes the Asyc thread. That's why I invoked it in the main thread.
As the result I always get no results in my ArrayList.
Can someone please enlighten me.
I was in the same situation regarding the progress dialog, tried a few tricks and finally just declared a ProgressDialog class member:
protected ProgressDialog proDialog;
then created two methods:
protected void startLoading() {
proDialog = new ProgressDialog(this);
proDialog.setMessage("loading...");
proDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
proDialog.setCancelable(false);
proDialog.show();
}
protected void stopLoading() {
proDialog.dismiss();
proDialog = null;
}
and called startLoading() before the background operation and stopLoading()
inside the background operation after I got the the results.
startLoading();
ParseUser.logInInBackground(userName.getText().toString(), hashedPass, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.d(Constants.TAG, "User Loged in.");
ParseManager.sCurrentUser = user;
stopLoading();
finish();
} else {
stopLoading();
invalidCreds();
}
}
});
if you want to use AsyncTask don't call findInBackground() you can use find().
you can check it out in the api https://parse.com/docs/android/api/com/parse/ParseQuery.html#find()
hope this helps.
It's easy to get the progress of both uploads and downloads using ParseFile by passing a ProgressCallback to saveInBackground and getDataInBackground. For example:
byte[] data = "Working at Parse is great!".getBytes();
ParseFile file = new ParseFile("resume.txt", data);
file.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
// Handle success or failure here ...
}
}, new ProgressCallback() {
public void done(Integer percentDone) {
// Update your progress spinner here. percentDone will be between 0 and 100.
}
});
I couldn't think of a way to form my title to make my issue obvious, so here goes:
I'm a little over my head with diving into AsyncTask for the first time. I currently have an app that simply sends a tweet. To do this it must kick out to a WebView for Twitter authorization, which comes back to onNewIntent().
What I'm trying to do is throw up a simple Spinner ProgressDialog while it's connecting to the site/performing the AccessToken work, and then again while it's sending the tweet. I've only just discovered that I will need a new thread for the progress bar. Or rather, that I should be doing my "time-intensive work" in it's own separate thread to make using a ProgressDialog viable. My question is this: How can I have my progress spinner in the foreground while my authorization code works in the background, and eventually opens the WebView and comes back, and ultimately starts everything over at onResume()?
I'm sure I'm probably not doing everything else in the most proper fashion. I'm new to Android, but not to Java. I've put in my create- and dismissDialog(int) calls about where they should be, procedurally. As-is, everything otherwise works the way it should, but obviously my dialogs are simply not able show themselves.
I'm thinking I should basically put my entire authorize() and tweet() methods into their own AsyncTask. I'm just not sure how to go about that, especially since authorize() (or more specifically, loginToTwitter()) needs to end up saving the data it gets from the browser to shared preferences after it comes back to onNewIntent().
Thanks for any insights,
== Matt
public class IntegrateTwitter extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
super.onResume();
mPrefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
mTwitter = new TwitterFactory().getInstance();
mTwitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
if(authorize()) {
tweet();
returnToMM();
}
}
private boolean authorize() {
Log.i(LOG_TAG, "Authorizing...");
showDialog(PD_AUTHORIZING);
boolean result = false;
if(responseExistsAndValid()) {
saveResponseToAccessToken();
}
if(isAuthorized()) {
Log.i(LOG_TAG, "Prefs have AccessToken, grabbing it...");
if(getAccessTokenFromPrefs()) {
Toast.makeText(IntegrateTwitter.this, "Authorized.", Toast.LENGTH_SHORT).show();
result = true;
}
}
else {
Log.i(LOG_TAG, "Prefs don't have AccessToken.");
if(!responseStringExists()) {
Log.i(LOG_TAG, "No response exists either, starting Twitter login process...");
Toast.makeText(IntegrateTwitter.this, "Authorizing...", Toast.LENGTH_SHORT).show();
// Here is where it kicks out to the browser for authentication
loginToTwitter();
}
else {
Toast.makeText(IntegrateTwitter.this, "Authorization failed.", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, "Response exists, so it must have failed once already, skipping Twitter login process.");
returnToMM();
}
}
deleteResponseFromPrefs();
dismissDialog(PD_AUTHORIZING);
return result;
}
private void tweet() {
showDialog(PD_TWEETING);
try {
Date testDate = new Date();
String testDateString = DateFormat.format("yyyy-MM-dd # hh:mm:ss", testDate.getTime()).toString();
mTwitter.updateStatus(testDateString + " Test Tweet");
Toast.makeText(this, "Tweet successful!", Toast.LENGTH_SHORT).show();
}
catch (TwitterException e) {
Toast.makeText(this, "Tweet error.", Toast.LENGTH_SHORT).show();
Log.i(LOG_TAG, e.getMessage());
Log.i(LOG_TAG, Arrays.toString(e.getStackTrace()));
}
dismissDialog(PD_TWEETING);
}
// A bunch of support methods
// ...
}
Try this.....
I think you know that if we are not using AsyncTask, we can always use Thread along with Handler, to Post the work done on Non-UI thread to UI thread.
AsyncTask is provided by android to sync the UI and Non-UI work seamlessly.
I got this example by searching on Google, but changed it the way you wanted it to be.
Here it will Count till 50... and until it does it will keep displaying the ProgressDialog.
Please see the log while the program is executing to see the count increasing till 50.
public class AsyncTaskExampleActivity extends Activity
{
protected TextView _percentField;
protected Button _cancelButton;
protected InitTask _initTask;
ProgressDialog pd;
#Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate(savedInstanceState);
setContentView( R.layout.main );
_percentField = ( TextView ) findViewById( R.id.percent_field );
_cancelButton = ( Button ) findViewById( R.id.cancel_button );
_cancelButton.setOnClickListener( new CancelButtonListener() );
_initTask = new InitTask();
pd = ProgressDialog.show(AsyncTaskExampleActivity.this, "Loading", "Please Wait");
_initTask.execute( this );
}
protected class CancelButtonListener implements View.OnClickListener
{
public void onClick(View v) {
_initTask.cancel(true);
}
}
/**
* sub-class of AsyncTask
*/
protected class InitTask extends AsyncTask<Context, Integer, String>
{
// -- run intensive processes here
// -- notice that the datatype of the first param in the class definition matches the param passed to this method
// -- and that the datatype of the last param in the class definition matches the return type of this method
#Override
protected String doInBackground( Context... params )
{
//-- on every iteration
//-- runs a while loop that causes the thread to sleep for 50 milliseconds
//-- publishes the progress - calls the onProgressUpdate handler defined below
//-- and increments the counter variable i by one
int i = 0;
while( i <= 50 )
{
try{
Thread.sleep( 50 );
publishProgress( i );
i++;
} catch( Exception e ){
Log.i("makemachine", e.getMessage() );
}
}
pd.dismiss();
return "COMPLETE!";
}
// -- gets called just before thread begins
#Override
protected void onPreExecute()
{
Log.i( "makemachine", "onPreExecute()" );
super.onPreExecute();
}
// -- called from the publish progress
// -- notice that the datatype of the second param gets passed to this method
#Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
Log.i( "makemachine", "onProgressUpdate(): " + String.valueOf( values[0] ) );
_percentField.setText( ( values[0] * 2 ) + "%");
_percentField.setTextSize( values[0] );
}
// -- called if the cancel button is pressed
#Override
protected void onCancelled()
{
super.onCancelled();
Log.i( "makemachine", "onCancelled()" );
_percentField.setText( "Cancelled!" );
_percentField.setTextColor( 0xFFFF0000 );
}
// -- called as soon as doInBackground method completes
// -- notice that the third param gets passed to this method
#Override
protected void onPostExecute( String result )
{
super.onPostExecute(result);
Log.i( "makemachine", "onPostExecute(): " + result );
_percentField.setText( result );
_percentField.setTextColor( 0xFF69adea );
_cancelButton.setVisibility( View.INVISIBLE );
}
}
}
I try to use this code to prevent multi-click in ImageView but it doesn't help.
Boolean isClicked = false;
#Override
public void onClick(View v)
{
if (v == imgClick && !isClicked)
{
//lock the image
isClicked = true;
Log.d(TAG, "button click");
try
{
//I try to do some thing and then release the image view
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
isClicked = false;
}
}
In the log cat, I can see 5 lines "button click" when I click on ImageView for 5 times as quickly as possible. I can see the log cat print the first line, wait for a while (2 seconds) and then print the next line. I think when I click the ImageView, the fired event is moved to queue in order, isn't it?. So how can I stop that?
I also try to use setEnable() or setClickable() instead of isClicked variable but it doesn't work too.
Just try this working code
Boolean canClick = true; //make global variable
Handler myHandler = new Handler();
#Override
public void onClick(View v)
{
if (canClick)
{
canClick= false; //lock the image
myHandler.postDelayed(mMyRunnable, 2000);
//perform your action here
}
}
/* give some delay..*/
private Runnable mMyRunnable = new Runnable()
{
#Override
public void run()
{
canClick = true;
myHandler.removeMessages(0);
}
};
Instead of sleeping in 2 seconds, I use some task like doSomeThing() method (has accessed UI thread), and I don't know when it completed. So how can I try your way?
//I referred this android link. You can handle thread more efficiently but i hope below code will work for you..
//you try this and
Boolean canClick = true; //make global variable
public void onClick(View v) {
if(canClick){
new DownloadImageTask().execute();
}
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
Log.d("MSG","Clicked");
canClick =false;
//perform your long operation here
return null;
}
protected void onPostExecute(Bitmap result) {
canClick =true;
}
}
You could keep track of the last consumed click upon your View, and based on it either perform the necessary actions, or simply return:
private long calcTime;
private boolean isClickedLately(final long millisToWait)
{
if (System.currentTimeMillis() - calcTime < millisToWait)
return true;
return false;
}
#Override
public void onClick(View v)
{
if (isClickedLately(2000))
return;
calcTime = System.currentTimeMillis();
Log.d(TAG, "consuming button click");
// perform the necessary actions
}
With the millisToWait parameter you can adjust the threshold of "waiting", but if you know that you want to wait exactly 2 seconds between two consecutive clicks, you can eliminate it.
This way you don't have to deal with Threads, which is good, since it's not a great idea to make the gui thread wait.