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();
}
}
Related
I have this piece of an activity:
public class ResultActivity extends AppCompatActivity implements ResultListener {
private String code = "";
private String data = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
code = intent.getStringExtra("code");
data = intent.getStringExtra("data");
MyExternal.DecodeAndSend(this, code, data);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Where MyExternal is a class in other library.
The method DecodeAndSend is something like this:
public static boolean DecodeAndSend(ResultListener caller, String codigo, String data)
{
try {
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return true;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return false;
}
Finally, ServerConnection class implements Callable<String> so I show you the call method:
#Override
public String call() throws Exception {
Thread.sleep(2000);
return "OK";
}
The call to Thread.sleep(2000); is actually a call to a web server to send some data.
The problem is that the ResultActivity does not show its layout until the call call returns.
What is missing in this code?
DecodeAndSend is called from the main thread. It calls Future.get() which waits for the job to finish, so it's blocking the main thread. You should call this method from a background thread as well. I think it would be okay to send it to your same thread pool since it is submitted after the first job that it will wait for.
You cannot return anything about the request results from this method, because it is asynchronous.
public static void DecodeAndSend(ResultListener caller, String codigo, String data)
{
ExecutorService pool = Executors.newFixedThreadPool(1);
HashMap<String,String> arguments = new HashMap<>();
Future<String> resultado = pool.submit(new ServerConnection(caller, url, arguments));
pool.submit(new Runnable() {
public void run () {
try {
String status = resultado.get();
if (status.equals("OK"))
caller.OnSuccess();
else
caller.OnError(status);
pool.shutdown();
return;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
caller.OnError(null); // No status, only an exception
});
}
However, your ServerConnection class already takes a caller parameter, so it should probably just handle the callback itself. And depending on what you're doing in the callback, you might want to post the callback calls to the main thread.
By the way, convention in Java is to always start method names with a lower-case letter (camel case).
Feature.get() is a blocking call. The UI Thread is blocked waiting for that call to return, hence can't take care of drawing your layout. Try passing the result listener to ResultListener to the ServerConnection and use the two callbacks to update your UI accordingly
Future.get() is a blocking call - execution stops until the result arrives
The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready.
So your Activity's onCreate method calls that stuff, and then blocks until call (which is running on another thread) returns its result. So onCreate doesn't finish, and the layout doesn't complete.
If you want to use that blocking code, but after the view has laid out, I'd use another part of the Activity lifecycle like onStart (set a flag so you only run it once!). Otherwise you'll need to use some other concurrency technique to get your result and use it. It depends on what you're actually doing with the result of your call function
I implemented this class in my android code
I made the below change in the run method(replaced "true"):
#Override
public void run() {
while (!isInterrupted()) {
try {
// A blocking operation. Initiate a ChatManager instance when
// there is a new connection
pool.execute(new ChatManager(socket.accept(), handler));
Log.d(TAG, "Launching the I/O handler");
} catch (IOException e) {
try {
if (socket != null && !socket.isClosed())
socket.close();
} catch (IOException ioe) {
}
e.printStackTrace();
pool.shutdownNow();
break;
}
}
}
I want to stop this thread before I close the app. So I implemented threadName.interrupt(); method. But this doesn't interrupt the thread.
I am actually confused with the usage of thread pool executor. So I am not sure how to do this efficiently. How can I implement interrupting this thread? When interrupt method is called, I want to close the socket, shutdown the pool and stop the thread.
Thread thread = new Thread () {
boolean isRunning = true;
public void stopThread() {
isRunning = false;
}
#Override
public void run() {
while (isRunning) {
try {
// A blocking operation. Initiate a ChatManager instance when
// there is a new connection
pool.execute(new ChatManager(socket.accept(), handler));
Log.d(TAG, "Launching the I/O handler");
} catch (IOException e) {
try {
if (socket != null && !socket.isClosed())
socket.close();
} catch (IOException ioe) {
}
e.printStackTrace();
pool.shutdownNow();
break;
}
}
}
};
thread.start();
Try this code. and call thread.stopThread() whenever you want the thread to stop.
if you want close an Android thread, you can set a variable to control run(),because run() is end, the thread will be closed.
The code is something like:
final boolean istrue=true;
new Thread(new Runnable() {
#Override
public void run() {
while (istrue){
//TODO your work
}
}
}).start();
}
If you want to close the thread, you only set istrue=false
Just call shutDownNow to close the pool and try interrupt all the threads inside it. You can check the difference in this post:
shutdown() will just tell the executor service that it can't accept new tasks, but the already submitted tasks continue to run
shutdownNow() will do the same AND will try to cancel the already submitted tasks by interrupting the relevant threads. Note that if
your tasks ignore the interruption, shutdownNow will behave exactly
the same way as shutdown.
If you want to interrupt or cancel an specific thread. I suggest you to use submit with Callables, With this, you will me able to work with your Future object, then if want to cancel a task you've given an executor service, you can call cancel(true) on its associated Future. When your task detects an interrupt request, it should preserve the interrupted status by calling Thread.currentThread().interrupt().
I'm trying to update the UI multiple times in an AsyncTask.
First of all the UI should update, if a request was accepted and later it should run the publishProgress, but If I return a value in the requestAccepted method the other acceptedFiles method will never be executed, but I want it to execute and update the UI before from this task
#Override
protected Void doInBackground(FileInformationHandler... params) {
try {
handler.createSecureSocket("192.168.3.29", 7431);
ProtocolHandler phandler = new ProtocolHandler(handler.getInputStream(), handler.getOutputStream());
phandler.sendInitialisation();
ConfirmationHandler cHandler = new ConfirmationHandler(handler.getInputStream(), handler.getOutputStream());
cHandler.addListener(new ConfirmationReceivedListener() {
#Override
public void requestAccepted(boolean b) {
// Update UI without stopping the asynctask
}
#Override
public void acceptedFiles(int[] ints) {
fileSender.addListener(new ProcessListener() {
#Override
public void processChanged(int i, long l) {
publishProgress(i);
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
First of all you don't need to use an Async task if you are anyways doing the long running operation in a separate thread and have callbacks for different states.
So in your case why can't you simply so all of this in the main thread and in the callbacks just update the UI.
But if you still want to use the Async task then since the doInBackground executes in a separate thread, you can do whatever long running operation is in the method serially and keep using the publishProgress method to update the UI whenever you want. since you are using the callback interface in your case the method will return null and the control with go into the 'onPostExecute'.
IMO using a callback interface in the doInBackground method is not the right approach and defeats the purpose of asyncTask async task.
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" .
I'm new to Android development. I've be working on Swing and SWT for several years. Both Swing and SWT has a stratage to execute code in UI thread sync and async. The typical usage is doing some time-consume staff in one thread then display the result in UI thread async.
So my question is, is there similiar stratage in Android? Here is my code. Parameter runnable is some time-consume code. This method will display a waiting dialog during the execution then EXPECT to show a Toast after it is finished. But the Toast need to be show in UI thread. So how to do that?
public static void showWaitingDialog(final Activity parent, final Runnable runnable, String msg) {
if (StringUtils.isEmpty(msg)) {
msg = "processing...";
}
final ProgressDialog waitingDialog = ProgressDialog.show(parent, "Please Wait...", msg, true);
// execute in a new thread instead of UI thread
ThreadPoolUtil.execute(new Runnable() {
public void run() {
try {
// some time-consume operation
runnable.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
waitingDialog.dismiss();
}
// TODO: How to display a Toast message here? execute some code in UI Thread.
}
});
}
And is there some words about Android UI system? Such as is it Thread-Safe, how thread works together and so on. Many Thanks!
There are several ways for doing that,
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. Example for using AsyncTask
Service -
A Service is an application component representing either an
application's desire to perform a longer-running operation while not
interacting with the user or to supply functionality for other
applications to use. Example for Using Service.
IntentService -
IntentService is a base class for Services that handle asynchronous
requests (expressed as Intents) on demand. Clients send requests
through startService(Intent) calls; the service is started as needed,
handles each Intent in turn using a worker thread, and stops itself
when it runs out of work. Example for using IntentService.
You can use AsyncTask like this.
To call AsyncTask
new getAsynctask().execute("");
and here is the class for geting result.
class getAsynctask extends AsyncTask<String, Long, Integer> {
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(Pass.this, null, "Please wait...");
}
protected Integer doInBackground(String... params) {
try {
// do your coding
return null;
} catch (Exception e) {
return null;
}
}
protected void onPostExecute(Integer result) {
super.onPostExecute(result);
try {
if (loading != null && loading.isShowing())
loading.dismiss();
} catch (Throwable t) {
Log.v("this is praki", "loading.dismiss() problem", t);
}
}
}
Whenever you are working with Separate thread which is not your UI thread the best way is to use Handler. Whenever you want to intimate user from your Thread, suppose a progress then send a message to Handler to so. Inside Handler you can handle message and write a code snippet to Change anything on UI. This is the preferred way for Android. see these link1 , link2 & link3
You use this AsynTask as a inner class of your activity. In do in background do the time consuming task you want to do and then in on postexecute you can show the text message.
call this from your main activity
initTask = new InitTask();
initTask.execute(this);
protected class InitTask extends AsyncTask<Context, Integer, String> {
#Override
protected String doInBackground(Context... params) {
// Do the time comsuming task here
return "COMPLETE!";
}
// -- gets called just before thread begins
#Override
protected void 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) {
}
// -- called if the cancel button is pressed
#Override
protected void onCancelled() {
super.onCancelled();
}
// -- 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);
// Show the toast message here
}
}
Use a handler:
static final int SHOW_TOAST = 0;
public static void showWaitingDialog(final Activity parent, final Runnable runnable, String msg) {
if (StringUtils.isEmpty(msg)) {
msg = "processing...";
}
final ProgressDialog waitingDialog = ProgressDialog.show(parent, "Please Wait...", msg, true);
// execute in a new thread instead of UI thread
ThreadPoolUtil.execute(new Runnable() {
public void run() {
try {
// some time-consume operation
runnable.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
waitingDialog.dismiss();
}
handler.sendMessage(handler.obtainMessage(SHOW_TOAST));
}
});
}
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_TOAST:
//Toast here
break;
}
}
};
The Painless threading article from the android developer resources provides different alternatives depending on the specific SDK version.