I would like to have an application which either loads or saves data through a HTTP request, however the data must interact with the UI thread. Ideally, I would like a single thread to use an IF statement on a message to determine if the request is to "load" or "save".
What would be the simplest way of doing this with the smallest amount of code?
Also, do instances of Handlers run on individual threads?
EDIT: This is the code I am using now:
Handler doStuff = new Handler(){
#Override
public void handleMessage(Message msg){
if(msg.what == 1){
// Load all the information.
// Get the ID from sharedPrefs
SharedPreferences details= getSharedPreferences("details", 0);
String ID = patDetails.getString("id", "error");
// Load up the ID from HTTP
String patInfo = httpInc.getURLContent("info.php?no="+AES.encrypt("387gk3hjbo8sgslksjho87s", ID));
// Separate all the details
patientInfo = patInfo.split("~");
}
if(msg.what == 2){
// Save the data
}
}
};
Eclipse halts the debugging and displays, "Source not found" for StrictMode.class
I suppose it's because it's using the Main thread to access the internet although it's running in individual threads.
Any idea.
Handlers do run on individual threads. Check that link. You should also check out AsyncTask.
I would propose submitting the jobs as Runnable to a single-threaded ExecutorService:
public class SomeClass {
private ExecutorService execService = Executors.newSingleThreadExecutor();
public void doSomething() {
final String someUiData = // retrieve data from UI
execService.submit(new Runnable() {
#Override
public void run() {
// so something time-consuming, which will be executed asynchronously from the UI thread
// you can also access someUiData here...
}
});
}
}
This way, the UI thread will not block whereas you can easily submit a different Runnable for different operations and the ExecutorService will completely take care of keeping it async.
Edit: If you need to interact with the UI, do so before becoming asynchronous and keep the result in final variables.
Related
I'm trying to understand how threads works in java. This is a simple database request that returns a ResultSet. I'm using JavaFx.
package application;
import java.sql.ResultSet;
import java.sql.SQLException;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class Controller{
#FXML
private Button getCourseBtn;
#FXML
private TextField courseId;
#FXML
private Label courseCodeLbl;
private ModelController mController;
private void requestCourseName(){
String courseName = "";
Course c = new Course();
c.setCCode(Integer.valueOf(courseId.getText()));
mController = new ModelController(c);
try {
ResultSet rs = mController.<Course>get();
if(rs.next()){
courseCodeLbl.setText(rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// return courseName;
}
public void getCourseNameOnClick(){
try {
// courseCodeLbl.setText(requestCourseName());
Thread t = new Thread(new Runnable(){
public void run(){
requestCourseName();
}
}, "Thread A");
t.start();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This returns an exception:
Exception in thread "Thread A" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread A
How do I correctly implement threading so that every database request is executed in a second thread instead of the main thread?
I've heard of implementing Runnable but then how do I invoke different methods in run method?
Never worked with threading before but I thought it's time for it.
Threading Rules for JavaFX
There are two basic rules for threads and JavaFX:
Any code that modifies or accesses the state of a node that is part of a scene graph must be executed on the JavaFX application thread. Certain other operations (e.g. creating new Stages) are also bound by this rule.
Any code that may take a long time to run should be executed on a background thread (i.e. not on the FX Application Thread).
The reason for the first rule is that, like most UI toolkits, the framework is written without any synchronization on the state of elements of the scene graph. Adding synchronization incurs a performance cost, and this turns out to be a prohibitive cost for UI toolkits. Thus only one thread can safely access this state. Since the UI thread (FX Application Thread for JavaFX) needs to access this state to render the scene, the FX Application Thread is the only thread on which you can access "live" scene graph state. In JavaFX 8 and later, most methods subject to this rule perform checks and throw runtime exceptions if the rule is violated. (This is in contrast to Swing, where you can write "illegal" code and it may appear to run fine, but is in fact prone to random and unpredictable failure at arbitrary time.) This is the cause of the IllegalStateException you are seeing: you are calling courseCodeLbl.setText(...) from a thread other than the FX Application Thread.
The reason for the second rule is that the FX Application Thread, as well as being responsible for processing user events, is also responsible for rendering the scene. Thus if you perform a long-running operation on that thread, the UI will not be rendered until that operation is complete, and will become unresponsive to user events. While this won't generate exceptions or cause corrupt object state (as violating rule 1 will), it (at best) creates a poor user experience.
Thus if you have a long-running operation (such as accessing a database) that needs to update the UI on completion, the basic plan is to perform the long-running operation in a background thread, returning the results of the operation when it is complete, and then schedule an update to the UI on the UI (FX Application) thread. All single-threaded UI toolkits have a mechanism to do this: in JavaFX you can do so by calling Platform.runLater(Runnable r) to execute r.run() on the FX Application Thread. (In Swing, you can call SwingUtilities.invokeLater(Runnable r) to execute r.run() on the AWT event dispatch thread.) JavaFX (see later in this answer) also provides some higher-level API for managing the communication back to the FX Application Thread.
General Good Practices for Multithreading
The best practice for working with multiple threads is to structure code that is to be executed on a "user-defined" thread as an object that is initialized with some fixed state, has a method to perform the operation, and on completion returns an object representing the result. Using immutable objects, in particular, a record, for the initialized state and computation result is highly desirable. The idea here is to eliminate the possibility of any mutable state being visible from multiple threads as far as possible. Accessing data from a database fits this idiom nicely: you can initialize your "worker" object with the parameters for the database access (search terms, etc). Perform the database query and get a result set, use the result set to populate a collection of domain objects, and return the collection at the end.
In some cases it will be necessary to share mutable state between multiple threads. When this absolutely has to be done, you need to carefully synchronize access to that state to avoid observing the state in an inconsistent state (there are other more subtle issues that need to be addressed, such as liveness of the state, etc). The strong recommendation when this is needed is to use a high-level library to manage these complexities for you.
Using the javafx.concurrent API
JavaFX provides a concurrency API that is designed for executing code in a background thread, with API specifically designed for updating the JavaFX UI on completion of (or during) the execution of that code. This API is designed to interact with the java.util.concurrent API, which provides general facilities for writing multithreaded code (but with no UI hooks). The key class in javafx.concurrent is Task, which represents a single, one-off, unit of work intended to be performed on a background thread. This class defines a single abstract method, call(), which takes no parameters, returns a result, and may throw checked exceptions. Task implements Runnable with its run() method simply invoking call(). Task also has a collection of methods which are guaranteed to update state on the FX Application Thread, such as updateProgress(...), updateMessage(...), etc. It defines some observable properties (e.g. state and value): listeners to these properties will be notified of changes on the FX Application Thread. Finally, there are some convenience methods to register handlers (setOnSucceeded(...), setOnFailed(...), etc); any handlers registered via these methods will also be invoked on the FX Application Thread.
So the general formula for retrieving data from a database is:
Create a Task to handle the call to the database.
Initialize the Task with any state that is needed to perform the database call.
Implement the task's call() method to perform the database call, returning the results of the call.
Register a handler with the task to send the results to the UI when it is complete.
Invoke the task on a background thread.
For database access, I strongly recommend encapsulating the actual database code in a separate class that knows nothing about the UI (Data Access Object design pattern). Then just have the task invoke the methods on the data access object.
So you might have a DAO class like this (note there is no UI code here):
public class WidgetDAO {
// In real life, you might want a connection pool here, though for
// desktop applications a single connection often suffices:
private Connection conn ;
public WidgetDAO() throws Exception {
conn = ... ; // initialize connection (or connection pool...)
}
public List<Widget> getWidgetsByType(String type) throws SQLException {
try (PreparedStatement pstmt = conn.prepareStatement("select * from widget where type = ?")) {
pstmt.setString(1, type);
ResultSet rs = pstmt.executeQuery();
List<Widget> widgets = new ArrayList<>();
while (rs.next()) {
Widget widget = new Widget();
widget.setName(rs.getString("name"));
widget.setNumberOfBigRedButtons(rs.getString("btnCount"));
// ...
widgets.add(widget);
}
return widgets ;
}
}
// ...
public void shutdown() throws Exception {
conn.close();
}
}
Retrieving a bunch of widgets might take a long time, so any calls from a UI class (e.g a controller class) should schedule this on a background thread. A controller class might look like this:
public class MyController {
private WidgetDAO widgetAccessor ;
// java.util.concurrent.Executor typically provides a pool of threads...
private Executor exec ;
#FXML
private TextField widgetTypeSearchField ;
#FXML
private TableView<Widget> widgetTable ;
public void initialize() throws Exception {
widgetAccessor = new WidgetDAO();
// create executor that uses daemon threads:
exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
}
// handle search button:
#FXML
public void searchWidgets() {
final String searchString = widgetTypeSearchField.getText();
Task<List<Widget>> widgetSearchTask = new Task<List<Widget>>() {
#Override
public List<Widget> call() throws Exception {
return widgetAccessor.getWidgetsByType(searchString);
}
};
widgetSearchTask.setOnFailed(e -> {
widgetSearchTask.getException().printStackTrace();
// inform user of error...
});
widgetSearchTask.setOnSucceeded(e ->
// Task.getValue() gives the value returned from call()...
widgetTable.getItems().setAll(widgetSearchTask.getValue()));
// run the task using a thread from the thread pool:
exec.execute(widgetSearchTask);
}
// ...
}
Notice how the call to the (potentially) long-running DAO method is wrapped in a Task which is run on a background thread (via the accessor) to prevent blocking the UI (rule 2 above). The update to the UI (widgetTable.setItems(...)) is actually executed back on the FX Application Thread, using the Task's convenience callback method setOnSucceeded(...) (satisfying rule 1).
In your case, the database access you are performing returns a single result, so you might have a method like
public class MyDAO {
private Connection conn ;
// constructor etc...
public Course getCourseByCode(int code) throws SQLException {
try (PreparedStatement pstmt = conn.prepareStatement("select * from course where c_code = ?")) {
pstmt.setInt(1, code);
ResultSet results = pstmt.executeQuery();
if (results.next()) {
Course course = new Course();
course.setName(results.getString("c_name"));
// etc...
return course ;
} else {
// maybe throw an exception if you want to insist course with given code exists
// or consider using Optional<Course>...
return null ;
}
}
}
// ...
}
And then your controller code would look like
final int courseCode = Integer.valueOf(courseId.getText());
Task<Course> courseTask = new Task<Course>() {
#Override
public Course call() throws Exception {
return myDAO.getCourseByCode(courseCode);
}
};
courseTask.setOnSucceeded(e -> {
Course course = courseTask.getCourse();
if (course != null) {
courseCodeLbl.setText(course.getName());
}
});
exec.execute(courseTask);
The API docs for Task have many more examples, including updating the progress property of the task (useful for progress bars..., etc.
Related
JavaFX - Background Thread for SQL Query
Sample for accessing a local database from JavaFX using concurrent tasks for database operations so that the UI remains responsive.
Exception in thread "Thread A" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread A
The exception is trying to tell you that you are trying to access JavaFX scene graph outside the JavaFX application thread. But where ??
courseCodeLbl.setText(rs.getString(1)); // <--- The culprit
If I can't do this how do I use a background thread?
The are different approaches which leads to similar solutions.
Wrap you Scene graph element with Platform.runLater
There easier and most simple way is to wrap the above line in Plaform.runLater, such that it gets executed on JavaFX Application thread.
Platform.runLater(() -> courseCodeLbl.setText(rs.getString(1)));
Use Task
The better approach to go with these scenarios is to use Task, which has specialized methods to send back updates. In the following example, I am using updateMessage to update the message. This property is bind to courseCodeLbl textProperty.
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
String courseName = "";
Course c = new Course();
c.setCCode(Integer.valueOf(courseId.getText()));
mController = new ModelController(c);
try {
ResultSet rs = mController.<Course>get();
if(rs.next()) {
// update message property
updateMessage(rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
public void getCourseNameOnClick(){
try {
Thread t = new Thread(task);
// To update the label
courseCodeLbl.textProperty.bind(task.messageProperty());
t.setDaemon(true); // Imp! missing in your code
t.start();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This has nothing to do with database. JavaFx, like pretty much all GUI libraries, requires that you only use the main UI thread to modify the GUI.
You need to pass the data from the database back to the main UI thread. Use Platform.runLater() to schedule a Runnable to be run in the main UI thread.
public void getCourseNameOnClick(){
new Thread(new Runnable(){
public void run(){
String courseName = requestCourseName();
Platform.runLater(new Runnable(){
courseCodeLbl.setText(courseName)
});
}
}, "Thread A").start();
}
Alternatively, you can use Task.
At application launch time I am making network call (resttemplate Get call) to fetch data.
Scenario is something like this,
1)Parent call which returns list of tokens(Id's)
2)Once I got list of tokens(Id's),I iterate through it make network call for each token(Id) to get Data.
What I have done so for:
1)I have used Intent service to make parent network call to get list tokens(ID's).
2)Once I got list token(Id's) I started my AsyncTask executeOnExecutor,Passing list of tokens(ID's) to asynctask through constructor and starting AsyncTask executor.
Something like this,
MyAsyncExecutorTask executorTask = new MyAsyncExecutorTask(List<Integer> of tokens);
executorTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,(Void[]) null);
And In MyAsyncExecutorTask this is what I am doing.
protected Void doInBackground(Void...params) {
//Settimg max priority
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
for (int i = 0; i < scheduleList.size(); i++) {
ScheduleImpl scheduleImpl = new ScheduleImpl();
//Making network call to get data using token
scheduleImpl.getData(scheduleList(i));
}
}
Its working as it should be.
My doubts or Questions are:
1)Am I using Async executeOnExecuter() in right way(I want to make parallel network calls).I don't see any huge performance improvement after switching from AsyncTask execute() to Async executeOnExecuter().
2)How to check how many number worker threads running.
You can make it like this:
AsyncTaskGetTokens.java
public class AsyncTaskGetTokens extends AsyncTask<Void,Integer, List<Integer>> {
private ProgressDialog pd;
private Context context;
private String dataURL;
public AsyncTaskGetTokens (Context context, Integer token)
{
this.act = act;
this.token = token;
}
protected void onPreExecute()
{
this.pd = ProgressDialog.show(context, "", "");
}
protected Integer doInBackground(Void... arg0) {
List<Integer> tokenList = new List<Integer>();
//get token list from URL here
return tokenList;
}
protected void onPostExecute(List<Integer> tokenList)
{
this.pd.dismiss();
AsyncTaskGetData.tokensDownloading = new List<AsyncTaskGetData>();
foreach(Integer token : tokenList)
{
AsyncTaskGetData.tokensDownloading.add(new AsyncTaskGetData(context, token); // here you create a list with all the tokens that will be downloaded
}
foreach(AsyncTaskGetData asynctask : AsyncTaskGetData.tokensDownloading)
{
asynctask.execute(); // here you will start downloading the data from each token
}
}
}
AsyncTaskGetData.java
public class AsyncTaskGetData extends AsyncTask<Void,Integer, Data> {
public static List<AsyncTaskGetData> tokensDownloading;
private ProgressDialog pd;
private Context context;
private Integer token;
public AsyncTaskGetData (Context context, Integer token)
{
this.context = context;
this.token = token;
}
protected void onPreExecute()
{
this.pd = ProgressDialog.show(context, "", "");
}
protected Data doInBackground(Void... arg0) {
Data data = getDataFromURL(token);
return data;
}
protected void onPostExecute(Data data)
{
//show data here
this.pd.dismiss();
}
}
1)Am I using Async executeOnExecuter() in right way(I want to make parallel network calls).I don't see any huge performance improvement after switching from AsyncTask execute() to Async executeOnExecuter().
From Android Documentation
execute:
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
Note: this function schedules the task on a queue for a single background thread or pool of threads depending on the platform version. When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. Starting HONEYCOMB, tasks are back to being executed on a single thread to avoid common application errors caused by parallel execution
executeOnExecuter
Executes the task with the specified parameters. The task returns itself (this) so that the caller can keep a reference to it.
This method is typically used with THREAD_POOL_EXECUTOR to allow multiple tasks to run in parallel on a pool of threads managed by AsyncTask, however you can also use your own Executor for custom behavior.
Warning: Allowing multiple tasks to run in parallel from a thread pool is generally not what one wants, because the order of their operation is not defined. For example, if these tasks are used to modify any state in common (such as writing a file due to a button click), there are no guarantees on the order of the modifications. Without careful work it is possible in rare cases for the newer version of the data to be over-written by an older one, leading to obscure data loss and stability issues. Such changes are best executed in serial; to guarantee such work is serialized regardless of platform version you can use this function with SERIAL_EXECUTOR.
The question isn't about the performance improvement necessarily. When you run as executeOnExecuter, there is no guarantee that the calls will return in the order you made them. An execute method will schedule the task in a queue for a single background thread.
2)How to check how many number worker threads running.
You have the ability to define your own work queue, so if the question is how many threads can you run, then refer to this post Android AsyncTask threads limits?
I'm not sure if there is an easy way to check the count of current running. If there is I'm sure someone will be comment on that. But you can keep references to each task and check its status.
I'm using ListenableFuture from Guava, and one nice thing about them is that one pass Executor to the Futures.addCallback method, that is, ask to execute the callback on a given thread/executor.
In my Android application, I want to be able to start the asynchronous execution based on ListenableFuture in the UI thread, and schedule a callback which is also executed also on the UI thread. Therefore, I'd like to somehow submit the UI thread executor to the Futures.addCallback method mentioned above. How to achieve that?
Or, in other words, I want to have an executor for the UI thread. Is it available already in Android, or, if I have to create my own, how do I do that?
EDIT: As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
I think I've see some implementation doing that. The basic Idea is roughly
class UiThreadExecutor implements Executor {
private final Handler mHandler = new Handler(Looper.getMainLooper());
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
You can delegate to run anything in the main thread by passing it to a handler for the main thread.
Edit: https://github.com/square/retrofit/blob/master/retrofit/src/main/java/retrofit/android/MainThreadExecutor.java for example
Edit2: You can configure the handler like e.g. SensorManager#registerListener(..., Handler handler) allows you to do.
class HandlerThreadExecutor implements Executor {
private final Handler mHandler;
public HandlerThreadExecutor(Handler optionalHandler) {
mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper());
}
#Override
public void execute(Runnable command) {
mHandler.post(command);
}
}
The advantage over using the current thread's looper is that it makes it explicit which Looper you use. In your solution you take the Looper of whatever thread calls new ExecuteOnCaller() - and that's often not the thread you run code in later.
I would be happy to know how to achieve the same effect without resorting to the Android-specific stuff like Handler and Looper, just with pure Java.
Looper, Handler and the message queue behind all that logic are made of mostly pure Java. The problem with a generic solution is that you can't "inject" code to run into a thread. The thread must periodically check some kind of task queue to see if there is something to run.
If you write code like
new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
System.out.println("Hello");
}
}
}).start();
Then there is no way to make that thread do anything else but constantly print "Hello". If you could do that it would be like dynamically inserting a jump to other code into the program code. That would IMO be a terrible idea.
final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
new Thread(new Runnable() {
#Override
public void run() {
try {
while (true) {
Runnable codeToRunInThisThread = queue.take();
codeToRunInThisThread.run();
}
} catch (InterruptedException ignored) {}
}
}).start();
On the other hand is a simple thread that loops forever on a queue. The thread could do other tasks in between but you have to add a manual check into the code.
And you can send it tasks via
queue.put(new Runnable() {
#Override
public void run() {
System.out.println("Hello!");
}
});
There is no special handler defined here but that's the core of what Handler & Looper do in Android. Handler in Android allows you to define a callback for a Message instead of just a Runnable.
Executors.newCachedThreadPool() and similar do roughly the same thing. There are just multiple threads waiting on code in a single queue.
As an extension to this question, is it possible to do same thing, but not just with UI thread, but with any particular thread, where the call to async method is made?
The generic answer is No. Only if there is a way to inject code to run in that thread.
Based on asnwer from #zapl, here is my implementation, which also answers the edited (extended) question: https://gist.github.com/RomanIakovlev/8540439
Figured out I'll also put it here, in case if link will rot some day:
package com.example.concurrent;
import android.os.Handler;
import android.os.Looper;
import java.util.concurrent.Executor;
/**
* When the calling thread has a Looper installed (like the UI thread), an instance of ExecuteOnCaller will submit
* Runnables into the caller thread. Otherwise it will submit the Runnables to the UI thread.
*/
public class ExecuteOnCaller implements Executor {
private static ThreadLocal<Handler> threadLocalHandler = new ThreadLocal<Handler>() {
#Override
protected Handler initialValue() {
Looper looper = Looper.myLooper();
if (looper == null)
looper = Looper.getMainLooper();
return new Handler(looper);
}
};
private final Handler handler = threadLocalHandler.get();
#Override
public void execute(Runnable command) {
handler.post(command);
}
}
My pattern to use it would be like this:
/**
* in SomeActivity.java or SomeFragment.java
*/
Futures.addCallback(myModel.asyncOperation(param), new FutureCallback<Void>() {
#Override
public void onSuccess(Void aVoid) {
// handle success
}
#Override
public void onFailure(Throwable throwable) {
// handle exception
}
}, new ExecuteOnCaller());
Use com.google.android.gms.tasks.TaskExecutors.MAIN_THREAD.
An Executor that uses the main application thread.
Source: Android docs
The tasks APIs are part of Google Play services since version 9.0.0.
For Android UI thread executor use:
ContextCompat.getMainExecutor(context)
To address your question and extended question to create an Executor that simply runs on the current thread and avoids Android classes:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
See documentation: https://developer.android.com/reference/java/util/concurrent/Executor
I'm creating a reader application. The reader identifies based on the parameters which file to read, does some processing and returns the result to the caller.
I am trying to make this multi-threaded, so that multiple requests can be processed. I thought it was simple but later realized it has some complexity. Even though i create threads using executor service, I still need to return the results back to the caller. So this means waiting for the thread to execute.
Only way i can think of is write to some common location or db and let the caller pick the result from there. Is there any approach possible?
Maybe an ExecutorCompletionService can help you. The submitted tasks are placed on a queue when completed. You can use the methods take or poll depending on if you want to wait or not for a task to be available on the completion queue.
ExecutorCompletionService javadoc
Use an ExecutorService with a thread pool of size > 1, post custom FutureTask derivatives which override the done() method to signal completion of the task to the UI:
public class MyTask extends FutureTask<MyModel> {
private final MyUI ui;
public MyTask(MyUI toUpdateWhenDone, Callable<MyModel> taskToRun) {
super(taskToRun);
ui=toUpdateWhenDone;
}
#Override
protected void done() {
try {
// retrieve computed result
final MyModel computed=get();
// trigger an UI update with the new model
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ui.setModel(computed); // set the new UI model
}
});
}
catch(InterruptedException canceled) {
// task was canceled ... handle this case here
}
catch(TimeoutException timeout) {
// task timed out (if there are any such constraints).
// will not happen if there are no constraints on when the task must complete
}
catch(ExecutionException error) {
// handle exceptions thrown during computation of the MyModel object...
// happens if the callable passed during construction of the task throws an
// exception when it's call() method is invoked.
}
}
}
EDIT: For more complex tasks which need to signal status updates, it may be a good idea to create custom SwingWorker derivatives in this manner and post those on the ExecutorService. (You should for the time being not attempt to run multiple SwingWorkers concurrently as the current SwingWorker implementation effectively does not permit it.)
I have an application the leans heavily on map functionality. From the first Activity I call the runOnFirstFix() method to load a lot of data from a database once the location of the user has been found, but I also want to be able to interrupt this runnable and stop it mid execution for when I switch activity or the user presses the button to stop it running.
myLocationOverlay.runOnFirstFix(new Runnable() {
public void run() {
mc.animateTo(myLocationOverlay.getMyLocation());
mc.setZoom(15);
userLatitude = myLocationOverlay.getMyLocation().getLatitudeE6();
userLongitude = myLocationOverlay.getMyLocation().getLongitudeE6();
userLocationAcquired = true;
loadMapData(); //Here the method is called for heavy data retrieval
}
});
How can I stop this Runnable mid execution?
You could (and probably should) use an AsyncTask
private class MapLoader extends AsyncTask<Void, Void, Data> {
#Override
protected Data doInBackground(Void... params) {
return loadMapData(); //Here the method is called for heavy data retrieval, make it return that Data
}
#Override
protected void onPostExecute(Data result) {
//do things with your mapview using the loaded Data (this is executed by the uithread)
}
}
and then in replace your other code with
final MapLoader mapLoader = new MapLoader();
myLocationOverlay.runOnFirstFix(new Runnable() {
public void run() {
mc.animateTo(myLocationOverlay.getMyLocation());
mc.setZoom(15);
userLatitude = myLocationOverlay.getMyLocation().getLatitudeE6();
userLongitude = myLocationOverlay.getMyLocation().getLongitudeE6();
userLocationAcquired = true;
mapLoader.execute();
}
});
then you should be able to cancel the running task when you no longer want it to complete using
mapLoader.cancel(true);
I hope the code compiles, I haven't tested it, but it should work :)
Just make sure that it is the ui thread that creates the MapLoader
edit: I think you need to wrap the mapLoader.execute(); call in a runOnUiThread() call in order for it to work correctly since runOnFirstFix() might spawn a new thread
use the handler object to handle this runnable.
define this runnable with the runnable object.
after that in handler you can start the cancel this runnable service
for e.g.
Handler handler = new Handler();
on startCommand()
handler.postDelayed(myRunnable,5000);
this will execute the run method of runnable after 5 sec
for cancel
handler.removeCallbacks(myRunnable);
and your runnable define like this way
private Runnable myRunnable = new Runnable(){
public void run(){
// do something here
}
}
http://developer.android.com/reference/android/os/Handler.html
http://developer.android.com/reference/java/util/logging/Handler.html
http://www.vogella.de/articles/AndroidPerformance/article.html
In Java, you can call interrupt() on a running thread which should stop the execution of given thread. But if any kind of blocking operation like wait() or join() is being performed, InterruptedException will be thrown. Even some kinds of socket-related blocking operations can lead to InterruptedIOException under Linux, or under Windows the operation still remains blocked (since Windows does not support interruptible I/O). I think you still could interrupt your runnable, just be aware that some I/O may not be interrupted until finished and if blocking, it might throw those kind of exceptions I mentioned.