I'm beginner in android and trying to show toast in the async task, for that purpose I wrote this code:
public class GetReading {
public GetReading() {
}
public List<ReadingModel> Get(String TokenKey, Context adapter) throws ExecutionException, InterruptedException {
GetReadingTask params = new GetReadingTask(TokenKey, adapter);
List List_result = (List)(new GetReading.AsyncRead()).execute(new GetReadingTask[]{params}).get();
return List_result;
}
private class AsyncRead extends AsyncTask<GetReadingTask, Void, List<ReadingModel>> {
ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List x;
private AsyncRead() {
}
protected List<ReadingModel> doInBackground(GetReadingTask... getReadingTasks) {
final Context pos = getReadingTasks[0].adapter;
Handler handler = new Handler(pos.getMainLooper());
handler.post(new Runnable() {
public void run() {
Toast.makeText(pos, "Created a server socket", 1).show();
}
});
ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading taskService = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading)ServiceGenerator.createService(ir.behineh.wepapiinterface.GETREADINGINTERFACE.GetReading.class);
Call tasks = taskService.getReadings("application/x-www-form-urlencoded", "application/json", "bearer " + getReadingTasks[0].TokenKey);
try {
this.x = (ir.behineh.wepapiinterface.GETREADINGINTERFACE.ReadingModel.List)tasks.execute().body();
} catch (IOException var7) {
var7.printStackTrace();
}
return this.x;
}
}
}
and when i try to call that async task with this code:
GetReading reading=new GetReading();
List<ReadingModel> result= reading.Get("VQ",LineActivity.this);
after finishing doinbackground get the toast, but i want to show toast first to user, what happen? how can i solve that problem? thanks all.
Toasts as well as anything that has to do with the UI cannot be fired from any thread that runs in the background.
Move your code for displaying the toast to either onProgressUpdate or on onPostExecute.
All your troubles arise because you use the .get() in
execute(new GetReadingTask[]{params}).get();
Never use .get() as it kills the asynchonity of your task.
Instead: do the things you want to do with the result in onPostExecute().
Related
In my app I'm getting some TEXT from a Website by ion library and I'm using a progressBar to show the progress of downloading that data.
But my main issue is that in onComplete I implemented some methods that work with the TEXT I've got from the website these are some cyclic methdods that use lot's of for and other stuff and actually my progressBar at the beginning works properly, but when it's complete downloading the data the progressBar just sticks until all the methods are complete in onComplete().
I would that the progressBar runs anyway and doesn't get stuck without removing methods from onComplete() is it possible?
Here is my function where I use ion library that I invoke in the onClick() event:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
Ion.with(getApplicationContext())
.load("IP")
.asString()
.setCallback(new FutureCallback<String>() {
#SuppressLint("SetTextI18n")
#Override
public void onCompleted(Exception e, String result) {
htmlresultart = result;
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
});
}
If the methods called in the onCompleted() callback take too much to execute then they need to be run on a background thread. In this situation it doesn't make sense to use a callback with Ion, instead you should synchronously fetch the data and after this do all the other tasks, all on a single background thread, something like below:
private void getHTML(){
progressDialog = new SpotsDialog(MainActivity.this, R.style.Custom);
progressDialog.show();
// start a background thread
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
#Override
public void run() {
String htmlresultart = null;
try {
String htmlresultart = Ion.with(getApplicationContext())
.load("IP")
.asString()
.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
// if htmlresultart is null at this point, an exception occured and the string couldn't be fetched so you most likely should abort the following processing.
if (htmlresultart != null) {
htmlresultart = htmlresultart.replace("</td>", "\n");
getTable();
getHeader();
getBody();
progressDialog.cancel();
}
}
});
}
I'm trying to implement a basic login screen for an android app. The flow is as follows:
1) User enters login information and hits submit
2) A LoginRequest which extends AsyncTask is created and executed.
3) The doInBackground will fire some http calls to validate the user credentials
4) The onPostExecute should be getting called to set the loginResults
5) Ui thread sees the login results and continues accordingly.
I'm been simplifying the code to get to the root issue but haven't had any luck so far. Here is the simplified code that still repros the issue.
Inside my activity:
private void tryLogin(String email, String password)
{
this.showProgress(true);
LoginHelper loginHelper = new LoginHelper();
LoginResult result = loginHelper.tryLogin(email, password);
this.showProgress(false);
}
This gets called from my submit buttons on click listener.
Inside LoginHelper:
TestClass test = new TestClass();
public LoginResult tryLogin(String mobileNumber, String password, int deviceId)
{
String loginUrl = "...";
new LoginRequest(test).execute(loginUrl);
while (test.result == null)
{
try {
Thread.sleep(1000);
}
catch (Exception e)
{
//...
}
}
return test.result;
}
This will execute the AsyncTask and wait for the result being continuing.
LoginRequest:
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
TestClass test;
public LoginRequest(TestClass test)
{
this.test = test;
}
#Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1,"test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
this.test.result = result;
}
}
I run this through the debugger with breakpoints inside the doInBackground and onPostExecute. The doInBackground executes correctly and returns the LoginResult value, but the onPostExecute breakpoint never gets hit, and my code will wait in the while loop in LoginHelper.
You are basically checking the whole time the variable 'result' of your LoginRequest. But that's not, how AsyncTask works.
From Docs:
AsyncTask allows you to perform asynchronous work on your user
interface. It performs the blocking operations in a worker thread and
then publishes the results on the UI thread, without requiring you to
handle threads and/or handlers yourself.
You can do your work in doInBackground() method and the publish you results in onPostExecute().
onPostExecute runs on UI Thread, to allow you change elements, show the result or whatever you want to do. Your problem is, that you are the whole time blocking the UI Thread with your checking method in tryLogin()
So how to solve it?
Remove the checking method:
public void tryLogin(String mobileNumber, String password, int deviceId)
{
// Starts AsynTasks, handle results there
String loginUrl = "...";
new LoginRequest().execute(loginUrl);
}
in AsyncTask:
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
// Removed Constructor, if you need to pass some other variables, add it again
#Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
// Now the result arrived!
// TODO: Use the result
}
}
More Thoughts:
You probably want to store user credentials. If so, make sure the are safe. Link
You might want, depending on results, change some UI. Here's an example:
AsyncTask:
public class LoginRequest extends AsyncTask
private Activity activity;
// Constructor
public LoginRequest(Activity activity) {
this.activity = activity;
}
#Override
protected LoginResult doInBackground(String... params) {
// TODO: Change this to actual Http Request
LoginResult ret = null;
ret = new LoginResult(1, "test");
return ret;
}
#Override
protected void onPostExecute(LoginResult result) {
ActivityLogin acLogin = (ActivityLogin) activity;
if(result.equals("ok")) {
Button loginButton = (Button) acLogin.findViewById(R.id.login-button);
loginButton.setBackgroundColor(Color.GREEN);
//Finish LoginActivity
acLogin.finish();
}
else {
//TODO: Fail Handling
}
}
}
And the start it like this:
new LoginRequest(loginActivity).execute(loginUrl);
I didnt tested the code.
It's AsyncTask so it's calling the LoginRequest and while(test.result) at the same time. You got stuck in the while loop because test.result is not done returning yet. test.result is done in onPostExecute(), so if you move that while loop in that function it will work and onPostExecute() will get called. One way to solve this problem is to implement a callback interface. Put the while loop in the overrided callback method.
refer to my answer here: how to send ArrayList(Bitmap) from asyncTask to Fragment and use it in Arrayadapter
Try This
public class LoginRequest extends AsyncTask<String, Void, LoginResult>
{
TestClass test;
LoginResult ret = null;
public LoginRequest(TestClass test)
{
this.test = test;
}
#Override
protected Boolean doInBackground(String... params) {
ret = new LoginResult(1,"test");
return true;
}
#Override
protected void onPostExecute(Boolean success) {
if(success)
this.test.result = result;
}
}
Temporary solution : You can add this.test.result = result; in the doInbackground() method.
#Override
protected LoginResult doInBackground(String... params) {
LoginResult ret = null;
ret = new LoginResult(1, "test");
this.test.result = result;
return ret;
}
Please post full code to get proper solution.
I am writing here because this is my last solution of understanding this type of programming.The problem is that I got stuck on what to use to handle the connection to a server and log-in. Should I use async task, handler or thread ? I didn't find a concrete answer stating which one to use, only found that async task is used to download images or other download stuffs.
Until now I have used a thread to connect to the server. The problem I encountered was when I catch the exception ( Putting invalid username/password ) and try to log-in again. ( I needed to "close" the last thread and start one again )
After this I started to use async task but I don't really understand how it should work and I am stuck on a toast of invalid username/password.
private class connectStorage extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
api = DefaultClientFactory.create(host, getUser, getPassword);
if (api.getAuthToken().trim().length() > 3) {
//TO DO LAYOUT CHANGE;
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST", "" + e.getMessage());
}
return null;
}
Also, I am 100% sure that calling inflate in the doInBackground method won't work too ( there I wanted to change the activity ).
I am starting the async task on a button press.
When you are using asynctask
You have doInBackground and onPostExecute
So basically get a json or string or boolean as a result from doinbackground
and in onpostexecute check if the login in succesful or not if its succesful save the data from server and start an intent to go to another activity or toast the user that that user login details are wrong and try again.
So your asynctask can be an inner class of your activity class which is login and onClickSubmit button call the asynctask class and on post execute parse the json and according to the result decide what to do
Example:
public class SignInAsycTask extends AsyncTask<RequestParams, Void, String> {
#Override
protected String doInBackground(RequestParams... params) {
return new HttpManager().sendUserData(params[0]);
}
#Override
protected void onPostExecute(String result) {
String[] details = parseJsonObject(result);
if (details != null) {
user.setUser_id(Integer.valueOf(details[0]));
user.setName(details[1]);
if (details.length > 2) {
user.setProfilePic(details[2]);
}
setSharedPreferences();
startActivity(new Intent(Signin.this, MainActivity.class));
finish();
} else {
Toast.makeText(Signin.this, "please try again",
Toast.LENGTH_LONG).show();
}
}
}
public String[] parseJsonObject(String result) {
JSONObject obj = null;
try {
obj = new JSONObject(result);
if (obj.has("success")) {
if (obj.getInt("success") == 1) {
if (obj.has("user_pic")) {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"),
obj.getString("user_pic") };
} else {
return new String[] {
String.valueOf(obj.getInt("user_id")),
obj.getString("user_name"), };
}
} else {
return null;
}
} else {
return null;
}
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
here my RequestParams are just a object where I stored all the details like url parameters to send etc and the output of the doinbackground is a String and I am parsing it in my postexecute method
I'm trying to do a simple HTTP request in Android. It has to be in separate theread. But how can I operate on the view controls inside the thread?
Here's what I have now:
public void saveData(final View v)
{
Button btn = (Button) v.findViewById(R.id.button);
btn.setText("Saving...");
new Thread() {
public void run()
{
HttpURLConnection connection = null;
try {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
final String fResponse = IOUtils.toString(inputStream);
}
catch (MalformedURLException ex) {
Log.e("aaa", "Invalid URL", ex);
}
catch (IOException ex) {
Log.e("aaa", "IO Exception", ex);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
// How can I access v and btn here?
// btn.getText("Saved, thanks.");
// btn.setText("Saved, thanks.");
}
}.start();
}
To elaborate what I'm trying to achieve:
I have a text box and a button. Once the button is clicked, I want to get the text from text box, use in the URL, wich returns a value, then update the button text with this value.
Here's an example on how you could do it.
public class YourClass extends Activity {
private Button myButton;
//create an handler
private final Handler myHandler = new Handler();
final Runnable updateRunnable = new Runnable() {
public void run() {
//call the activity method that updates the UI
updateUI();
}
};
private void updateUI()
{
// ... update the UI
}
private void doSomeHardWork()
{
//update the UI using the handler and the runnable
myHandler.post(updateRunnable);
}
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
doSomeHardWork();
}).start();
}
};
}
As you can see, you need to update the UI with yet another Runnable object. This is one way of doing it.
Another option is via the runOnUiThread function
runOnUiThread(new Runnable()
{
#Override
public void run() {
updateActivity();
}
});
If you try to access your Views directly from another thread like that, you will get an exception because all UI operations must be performed on the main thread.
One method that the Android SDK provides for performing background tasks that need to update the UI is the AsyncTask.
The onPostExecute() method of an AsyncTask is called after doInBackground() returns, and is run on the UI thread.
Your AsyncTask might look something like this:
public class MyBackgroundTask extends AsyncTask<URL, Void, String> {
protected String doInBackground(URL... urls) {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
return IOUtils.toString(inputStream);
}
protected void onPostExecute(String result) {
// Call back to your Activity with the result here
}
}
I'm writting an app that uses WebServices to retrieve data. Initially I had a private AsyncTask class for each activity that needed data from the WebService. But I've decided to make the code simpler by creating AsyncTask as a public class. All works fine, but my problem is when I want to access the retrieved data from the AsyncTask.
For example this is my AsyncTask class.
public class RestServiceTask extends AsyncTask<RestRequest, Integer, Integer> {
/** progress dialog to show user that the backup is processing. */
private ProgressDialog dialog;
private RestResponse response;
private Context context;
public RestServiceTask(Context context) {
this.context = context;
//...Show Dialog
}
protected Integer doInBackground(RestRequest... requests) {
int status = RestServiceCaller.RET_SUCCESS;
try {
response = new RestServiceCaller().execute(requests[0]);
} catch(Exception e) {
//TODO comprobar tipo error
status = RestServiceCaller.RET_ERR_WEBSERVICE;
e.printStackTrace();
}
return status;
}
protected void onPreExecute() {
response = null;
}
protected void onPostExecute(Integer result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
switch (result) {
case RestServiceCaller.RET_ERR_NETWORK:
Toast.makeText(
context,
context.getResources().getString(
R.string.msg_error_network_unavailable),
Toast.LENGTH_LONG).show();
break;
case RestServiceCaller.RET_ERR_WEBSERVICE:
Toast.makeText(
context,
context.getResources().getString(
R.string.msg_error_webservice), Toast.LENGTH_LONG)
.show();
break;
default:
break;
}
}
public RestResponse getResponse() throws InterruptedException {
return response;
}
}
RestServiceCaller, RestRequest and RestResponse are clasess that I've created.
I'm using the task like this:
RestRequest request = new JSONRestRequest();
request.setMethod(RestRequest.GET_METHOD);
request.setURL(Global.WS_USER);
HashMap<String, Object> content = new HashMap<String, Object>() {
{
put(Global.KEY_USERNAME, username.getText().toString());
}
};
request.setContent(content);
RestServiceTask task = new RestServiceTask(context);
task.execute(request);
This code works fine and is calling the web service correctly, my problem is when I want access to the response. In the AsyncTask I've created the method getResponse but when I use it, it returns a null object because the AsyncTask is still in progress, so this code doesn't work:
//....
task.execute(request);
RestResponse r = new RestResponse();
r = task.getResponse();
r will be a null pointer because AsyncTask is still downloading data.
I've try using this code in the getResponse function, but it doesn't work:
public RestResponse getResponse() throws InterruptedException {
while (getStatus() != AsyncTask.Status.FINISHED);
return response;
}
I thought that with the while loop the thread will wait until the AsyncTask finishes, but what I achieved was an infinite loop.
So my question is, how could I wait until AsyncTask finishes so the getResponse method will return the correct result?
The best solution is use of the onPostExecute method, but because AsyncTask is used by many activities I have no clue what to do.
try creating a callback interface. The answer to this async task question Common class for AsyncTask in Android? gives a good explanation for it.