I'm using Google Architecture Components, especially Room.
In my Dao i have this method:
#Query("SELECT COUNT(*) FROM photos")
int getPersistedPhotosSize();
And i need to execute it in my Repository to check if persisted photos size is 0.
So i gotta execute this method on background and get the value from it.
Now i perform this operation like this:
public int getNumRowsFromFeed() {
final int[] rows = new int[1];
Completable.fromAction(() -> rows[0] = photosDao.getPersistedPhotosSize())
.subscribeOn(Schedulers.io())
.blockingAwait();
return rows[0];
}
But i guess it's not the best way to do it.
So how can i get the value the right way? Especially i want to do it without RX
In your DAO the function to get the photo count doesn't use either LiveData nor RX. So instead of wrapping the code afterwards in a Completable, you can basically use any Android Async technology, like AsyncTask.
public class LoadTask extends AsyncTask<Void, Void, Integer> {
public interface Callback {
void onPhotoCount(int count);
}
private final Callback callback;
public LoadTask(Callback callback) {
this.callback = callback;
}
protected Integer doInBackground(Void... params) {
return photosDao.getPersistedPhotosSize();
}
protected void onPostExecute(Integer result) {
callback.onPhotoCount(result);
}
}
...
new LoadTask(photoCount -> {
// Do stuff with value,e.g. update ui.
}).execute();
This is basically just a proposal, of course you can use Threads, Handler as well.
P.S: From my point of view, this example shows one advantage of the Rx development. You get the callback stuff for free, without defining anything. And you can cancel the Rx chain for example due to lifecycle events. This is not implemented in this example.
Related
I'm going round in circles trying different techniques but every time hitting a different snag.
Ideally I want my code to look something like;
public class MyActivity extends AppCompatActivity {
SomeMethod();
new SomeAsyncTask().execute();
SomeOtherMethod();
new SomeOtherAsyncTask().execute();
}
But I need each method to be executed in order (and to wait for the previous to complete). Let's imagine the first AsyncTask authenticates and stores an authentication token in a static somewhere- this is then needed for the calls which follow.
My AsyncTasks have to be Async as they are communicating with an API.
I know I could use the onPostExecute() methods of the AsyncTasks but I don't like the mess this creates (having to jump around the code).
I know I could also create an interface and pass a class in to my AsyncTask but this doesn't help a great deal either (code still jumps around).
I thought I had come up with the perfect solution, calling SomeAsyncTask.execute().get() to wait until the task completes before continuing with the next line of code BUT I've hit a few issues with that today too.
Are there any other techniques I might be able to use to achieve clean code with a mix of foreground and background thread activity?
EDIT At the moment I am considering whether I can make all of my method non-async but then call them from an async- more like;
public class MyActivity extends AppCompatActivity {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground( final Void ... params ) {
SomeMethod();
SomeMethod2();
SomeOtherMethod();
SomeOtherMethod2();
return null;
}
#Override
protected void onPostExecute( final Void result ) {
// any ui stuff
}
}.execute();
}
EDIT2 Current favoured solution is;
Define a "PostExecute" interface in my AsyncTask;
public class GetMerchantDataAsync extends AsyncTask<Void, Void, Void> {
private Context mContext;
private PostExecute mDelegate;
public interface PostExecute {
void Callback();
}
public GetMerchantDataAsync(Context context, PostExecute delegate) {
mContext = context;
mDelegate = delegate;
}
#Override
protected Void doInBackground(Void... params) {
}
#Override
protected void onPostExecute(Void v){
mDelegate.Callback();
}
}
Then define an instance of the interface and pass it on the constructor;
public class StartActivity extends Activity {
private final Context context = this;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new GetMerchantDataAsync(context, getMerchantDataPostExecute).execute();
}
private GetMerchantDataAsync.PostExecute getMerchantDataPostExecute = new GetMerchantDataAsync.PostExecute() {
#Override
public void Callback() {
DoSomethingElse();
}
};
}
It's a little bit messy (not a single block of code) but it almost reads as a single block and hopefully with sensible/consistent naming will be easily readable.
There are many ways to skin this cat and a few nice async await libraries you can use, similar to Promise.
Or you can also simply do onPostExecute call backs inline if that fits your needs and call the next step onPostExecute, assuming life cycle is still valid.
However, if you want some nice clean code, you should consider Kotlin and Coroutines.
Example with Timeout, cancellation and error handling:
Notice the withTimeout and the withContext calls. Those allow you to await on the contents within before moving on. Also as an added bonus, the method here is a suspendable coroutine which means the caller can wait on it as well. You resume the caller with c.resume(returnValueType).
If you find this too complicated, then I would stick with your onPostExecute, but what most developers forget on AsyncTasks are.
AsyncTasks should be canceled if you exit the Activity typically
AsyncTasks can complete out of order if you are allowing threadpool
management
Object locks must be wrapped to ensure concurrent
modification of variables does not become a problem.
Callbacks should handle errors and not just the positive route
Timeouts have to be managed outside of the Async task adding much more bloat.
So you see, simply doing a myAsyncTask.execute{onPostExecute(value){//dostuff}}
may look like simple fast code, it is definitely prone to errors if you don't handle all the niche cases that can occur.
The Coroutines have provided nice wrappers around all of this in easy to read brackets.
private suspend fun updateConfigurationWithChanges() : Boolean = suspendCoroutine { c ->
A35Log.v(mClassTag, "updateConfigurationWithChanges")
setIsActionInProgress(true)
mSaveOrUpdateJob = launch(UI) {
try{
withTimeout(TIMEOUT_FOR_DB_INTERACTION_MS){
showProgressDialog(mClassTag, "Saving", false)
mSelectedConfiguration!!.setLastSavedDateStr(DateTimeHelper.getNowTimeStamp())
val updatedRecordCount = withContext(DefaultDispatcher){ SSDBHelper.updateConfiguration(mSelectedConfiguration!!) }
if(updatedRecordCount > 0){
showFancyToast("Successfully updated", true, FancyToast.SUCCESS)
c.resume(true)
}else{
showFancyToast("Error while updating, please try again or press back", true, FancyToast.SUCCESS)
c.resume(false)
}
}
}catch(ex: JobCancellationException){
showFancyToast("Save canceled", true, FancyToast.ERROR, "Save canceled: ${ex.message}")
c.resume(false)
}catch (ex: TimeoutCancellationException) {
showFancyToast("Timed out updating, please try again or press back", true, FancyToast.ERROR, "Timed out updating database: ${ex.message}")
c.resume(false)
}catch(ex: Exception){
showFancyToast("Error updating database, please try again or press back", true, FancyToast.ERROR, "Error updating database: ${ex.message}")
c.resume(false)
}
}
}
Of course it is still good practice to cancel if the user leaves your screen if it doesn't hurt anything.
override fun onPause() {
super.onPause()
if(mSaveOrUpdateJob != null && mSaveOrUpdateJob!!.isActive) {
A35Log.v(mClassTag, "canceling saveOrUpdate job")
mSaveOrUpdateJob?.cancel()
}
}
But at the end of the day, do what's best for your situation, if managing the asyncTask and onPostExecute works for your needs and you have all your i's dotted and your t's crossed you should be fine going that route as well.
Also just for completeness if you are wondering how to call and await this above method it would look like this.
fun myButtonClick(){
launch(UI) {
if(mIsNewConfiguration){
//save first if new
if(withContext(DefaultDispatcher){ isNewOrUnchangedName() }) {
if (withContext(DefaultDispatcher) { saveNewConfigurationToDatabase() }) {
refreshCurrentNamesList()
launchConnectAndSendToDeviceFlow()
}
}
}else {
//update first if changes made
if(withContext(DefaultDispatcher){ isNewOrUnchangedName() }) {
if(DeviceAndConfigurationHelper.hasConfigurationModelChanged(mOriginalCopyConfiguration!!, mSelectedConfiguration!!)){
if(withContext(DefaultDispatcher) { updateConfigurationWithChanges() }){
refreshCurrentNamesList()
launchConnectAndSendToDeviceFlow()
}
}else{
launchConnectAndSendToDeviceFlow()
}
}
}
}
}
Happy Coding.
I can think of two approaches, depending on your constraints you can pick any of them, one using custom async tasks:
Create a custom AsyncTask which will be inherited by all your async tasks (or it can be done inline too):
public abstract class BaseAsyncTask<T, U, V> extends AsyncTask<T, U, V> {
public interface Callback<X> {
void onComplete(X param);
}
private Callback mainCallback;
public void execute(Callback<V> callback, T... params) {
mainCallback = callback;
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
#Override
protected void onPostExecute(V v) {
super.onPostExecute(v);
if (mainCallback != null) {
mainCallback.onComplete(v);
}
}
}
This can be used like this for your case:
public static class TestThinghy {
BaseAsyncTask<String, String, String> task = new BaseAsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... strings) {
return null;
}
};
void firstFunOnMainThread() {
//....do whatever...///
}
void runEverything() {
firstFunOnMainThread();
new BaseAsyncTask<String, String, String>() {
#Override
protected String doInBackground(String... strings) {
return "testing thinghy";
}
}.execute(new Callback<String>() {
#Override
public void onComplete(String param) {
secondRunOnMainThread();
//you can start new async here, or better start it from a different methond
}
}, "the other string param");
}
void secondRunOnMainThread() {
///...whatever here
}
}
The other approach is using RxJava, it's a powerful approach that gives you a ton of ways to chain tasks like this and decide how to run them, for this approach I would let you to do some research.
I use a method for more than one time in JavaScript by using callback method because JavaScript is an async language.
Example:
function missionOne () {
sumCalculation(1, 2, function (result) {
console.log(result) // writes 3
})
}
function sumCalculation (param1, param2, callback) {
let result = param1 + param2
// The things that take long time can be done here
callback(result)
}
I wonder if there is any way to stop myself in Java?
Edit: I remove several sentences that make more complex the question.
I may be reading too much into your question, but it seems that you're looking into how to handle asynchronous code in Android. There are a couple of native options (not considering any library). I'll focus on two, but keep in mind there are other options.
AsyncTasks
From the documentation
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
Before writing one, you need to know which type of parameters it will receive, the type of progress it will publish during computation and what is its return type. These types are define via the AsyncTask generic Parameters AsyncTask<Params,Progress,Result>. If you don't need them any of them, set them to Void
Here's the basic gist of using an AsyncTask to compute the sum of two ints:
public void sumCalculation (int param1, int param2, Callback callback) {
new AsyncTask<Integer, Void, Integer>() {
#Override
public Integer doInBackground(Integer... params) {
int result = 0;
for (Integer param : params) {
result += param;
}
return result;
}
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
callback.onDone(integer);
}
}.execute(param1, param2);
}
doInBackground, as the name says, will execute a certain piece of code in a background thread. Please note that every AsyncTask will run on a ThreadPool of size 1, so they actually get in the way of other AsyncTasks.
onPostExecute brings the result back to the main thread, so you can update any UI componente. If you try to update the UI from a background thread, an exception will be thrown.
The down side of this particular example is the creation of a new AsyncTask every time that function is called.
Also you should use AsyncTask only if the task won't run for a very long time, couple of seconds at most.
Thread and Handler
Another option suggested on the documentation is using a thread and a handler to communicate between the main thread and a background thread. Although this provides greater flexibility, it also requires more responsibility as you will be responsible for managing the communication yourself, picking the right time to kill your threads and how to recover when something goes bad.
As a rule of thumb, you should only go this way if you really need the extra flexibility.
The overall idea is to create your own Handler and override its handleMessage method.
public class MyHandler {
#Override
public void handleMessage(Message inputMessage) {
int messageType = inputMessage.what;
Object extraData = inputMessage.obj;
...
}
}
public class MyTask extends Thread {
public static public int COMPUTATION_DONE = 0;
private MyHandler handler;
public MyTask(MyHandler handler) {
this.handler = handler;
}
#Override
public void run() {
//do your computation
Message message = handler.obtainMessage(COMPUTATION_DONE, your_result);
handler.sendMessage(message);
}
}
As you can see, this requiring parsing inputMessage.what and deciding what to do with it. Additionally, you need to cast inputMessage.obj to the right type and so on.
These are just two examples, but depending on what you're trying to do, you might need to dig deeper into Services or take a look at some reactive approach, such as RxJava2. However I encourage you to start with the basic before diving into something way more complicated.
Yes it is easy in Java. To take your example above you can write it in Java like this:
public static void main(String[] args) {
System.out.println(sumCalc(1,2));
}
private int sumCalc(int first, int second) {
return first + second;
}
I have implemented a way of getting the result from onPostExecute back to my main activity. I wanted to know if this is the right thing I did, is there any more chance of improving it, and if it's not the best way, what is the best way?
This is what I have done:
public class MainClass implements AsyncResponse {
private MyAsyncTask asyncTask;
public MainClass() {
asyncTask = new MyAsyncTask();
asyncTask.asyncResponse = this;
}
public void startTask( {
asyncTask.execute("string");
}
#Override
public void processDone(String res) {
// got response in MainClass from onPostExecute
}
private class MyAsyncTask extends AsyncTask<String, String, String> {
protected AsyncResponse asyncResponse = null;
#Override
protected String doInBackground(String... urls) {
return "some processed string";
}
#Override
protected void onPostExecute(String res) {
this.asyncResponse.processDone(res);
}
}
}
Here's the AsyncResponse interface:
public interface AsyncResponse {
void processDone(String res);
}
I want to know in terms of processing speed that on an average android mobile device, would this be a good approach and if not, how do I improve it to make it a good approach?
Thanks.
I always done this way and never had any issues. I would say it is the best way.
in one Line without any callback
String s= new MyAsyncTask().execute().get();
You added an unnecessary interface - and perhaps it makes your code less usable.
First, if you create the AsyncTask as a class within your Activity there is no need for the interface. You can simply do this:
#Override
protected void onPostExecute(String res) {
processDone(res);
}
The AsyncTask will execute onPostExecute on the UI thread and you can call the Activity method without the interface.
Second, if you create AsyncTask outside the Activity class (for example, in its own java file) then you can use this method, except it is not a good idea because it will hold a reference to the Activity on another thread - it's a memory leak risk.
To avoid that, your interface should be implemented in a separate class, like AsyncTaskResponse.java that is passed to the AsyncTask class.
Last, AsyncTask provides the response in the form of a String if that is sufficient. You should look at the docs on AsyncTask:
https://developer.android.com/reference/android/os/AsyncTask.html
You are wrapping the AsyncTask inside another POJO class; doing this doesn't hurt, but provides little benefit.
Consider that when the task is completed, you will want a callback notification somewhere. Your MainClass will get a callback in processDone(), but something will need to be listening to MainClass to get that notification.
Here is a pattern I always use with my AsyncTask subclasses:
public class GetDataRemoteTask extends AsyncTask<String, Void, Data> {
private static final String TAG = "GetDataRemoteTask ";
private WeakReference<GetDataResultListener> mListenerRef;
private Exception mExc;
#Override
protected Data doInBackground(String... params) {
Data result = null;
try {
result = mService.getData(params[0], params[1], params[2]);
} catch (Exception e) {
Log.e(TAG, "Error occurred getting data", e);
mExc = e;
}
return result;
}
#Override
protected void onPostExecute(Data result) {
if (mListenerRef != null) {
GetDataResultListener listener = mListenerRef.get();
if (listener != null) {
if (mExc == null) {
listener.dataReceived(result);
} else {
listener.dataException(mExc);
}
}
}
}
public void setGetDataResultListener(GetDataResultListener listener) {
if (listener == null) {
this.mListenerRef = null;
} else {
this.mListenerRef = new WeakReference<GetDataResultListener >(listener);
}
}
public static interface GetDataResultListener {
public void dataReceived(Data data);
public void dataException(Exception exc);
}
}
So to start off, here I have an interface, like you do, for connecting to the AsyncTask. But I don't wrap my AsyncTask with an implementation, I expect that I will have an Activity or a Fragment that will implement this interface. (That's why I use a WeakReference; if the Activity finishes, my AsyncTask won't keep holding on to the Activity. But that also means I can't use an anonymous class listener unless the client holds the reference for it.)
My client code will look like this:
GetDataRemoteTask task = new GetDataRemoteTask();
task.setListener(this);
task.execute(param1, param2, param3);
I also have a way to find out if there was an exception that occurred in the background task. Any background exceptions should always be reported to the client, which can decide how best to deal with the exception - for example pop up a dialog for the user, so they know the request failed.
I think that a big drawback of AsyncTask is that it doesn't have more structure around handling exceptions that occur in the background thread.
My task holds a reference to the exception, but I have also used Pair<Data, Exception> as a type parameter for return result so I don't need the exception property.
Using this pattern has helped me avoid some typical problems that occur when coding AsyncTask subclasses.
I am sorry for my bad english skills. I'm new to programming/stackoverflow and try to create a little android quiz app. This app has to connect to a php server and login/getquestion...
The simplest example is the login. The user has to type in his data and then i have to connect.
To provide that the Gui doesnt freeze i have to use asynchronous tasks.
Here the activity's code:
public void login(final String username, final String password) {
final Activity a = this;
FutureTask t = new FutureTask(new Callable() {
public Object call() {
Connection.GetInstance(a).login(username,password);
afterLoginTry(username,password);
return null;
}
});
t.run();
}
This calls a method in another class, which calls another FutureTask which calls an AsyncTask. At the end there is always an public synchronized method such as afterlogintry(). This works but it's a bit slow and i think dirty code.
My main problem is that i don't know how to give results back through different layers of classes and especially to the activity without using hotfixes all the time.
Is there any good explanation or tutorial, which describes how to design such a construct?
Thx for help
The way you can pass AsyncTask results back to other classes, is by declaring callbacks for the task, that will then report the result to a listener. Here is how it works.
First, you must declare an interface in your AsyncTask which contains a method that will send out the result of the task. So in my example task below, my result is a String. The String gets passed to onPostExecute() when the task finishes its work. I then call my callback method on a registered listener, and pass that return value on to whoever is listening for it. You register a listener by passing in an instance of your callbacks from whichever class is creating the task.
public class MyTask extends AsyncTask<String, Void, String> {
MyTaskCallback listener;
public MyTask(MyTaskCallback listener) {
this.listener = listener;
}
protected String doInBackground(String... params) {
String input = params[0];
//do work
input += "did some work on this String";
return input;
}
//When the thread finishes its work, this gets
//called on the main UI thread
protected void onPostExecute(String result) {
listener.onResultReceived(result);
}
public interface MyTaskCallback {
void onResultReceived(String result);
}
}
So next we need to register a listener for these callbacks, so when the result comes in from the task, it will get reported directly to our class. So let's say we have a simple Activity. The way we register the callbacks is to use the implements keyword on our class declaration, and then to actually implement the callback method in the class itself. We then create our task, and we pass in this which is our Activity that implements the callbacks. A simple example Activity that does this looks like this:
public class TaskActivity extends AppCompatActivity implements MyTask.MyTaskCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
//we pass in "this" because our Activity itself
//implements the callbacks below.
MyTask myTask = new MyTask(this);
myTask.execute();
}
//Here we implement our callback method, so the task
//can send its results straight through here
public void onResultReceived(String theResult) {
Log.d("TASK RESULT", "Here is our result String: "+theResult);
}
}
Now, our task has our Activity connected to it, through the callbacks we passed into it. So now when our task gets a result, we can send it directly to our listener, which is our Activity, and the result will come right through to our implemented onResultReceived method.
Callbacks are a great way to pass information around between classes while also keeping everything very separated. Hope this helps!
Let's say you're designing the threading architecture for a an app -> the primary purpose is that your app will have a lot of tasks that need something done on the background thread, and sometimes a result task on UI thread, or something not (though more times, the result needs to be run on UI thread). For simplicity, let's say the tasks will be stuff like: download a file and display a pop-up, log a user in and go to a different page, process an image and store the result in a database (popular tasks that a lot of apps do)
I've researched a lot about the nuances, but would really like a deep-dive explanation/knowledge on what kind of architecture is better, and what are the considerations.
here are the three models in consideration:
AsyncTask model: each operation (like downloading a file and displaying a pop-up) is an AsyncTask, or some derivative of a parent class that abstracts out the common functionalities.
Thread/handler model: i always create a new Handler(Looper.getMainLooper()); and each time i need to do a task, i use a thread factory to spin off the task, with the handler on UI thread (or whatever custom handler).
Service/Thread model: i use a general Service class that is in charge of operations based on some operation code. there's a bunch of ServiceTask derivative objects that do certain things, but the Service class communicates with each ServiceTask when tasks are started/done.
I'm slightly leaning towards going the whole service/threading model, just because i've read some really awkward nuances with AsyncTask/Threads:
AsyncTask has a private static handler, and if the classloader calls it at the wrong time (such as including a library that uses it before your application does) then all of your onPostExecute will happen at the wrong time since your handler was not the main handler
it's easy to forget to check a bunch of things in the onPostExecute such as if there was a config change, or your activity was destroyed, or application was backgrounded/paused when the onPostExecute is called (leading to crashes)
AsyncTask changed its serial/parallel execution behavior on different APIs
If you went with the Thread/Handler model, on older devices, thread priority is actually incredibly low. i've heard something like there was a priority scale of 1-15 such that your threads automatically get a low priority and if the system was low on resources, your threads would stop running (whereas since services are running independently of your activity the thread priority there is higher?)
What is the best way to design a robust threading architecture that doesn't easily lead to crashes/unexpected behavior while also maintaining good performance ??
Please also let me know in the comments if this question is too vague and if you need actual code (i'm afraid to post code because it would super overbloat the question length more than it already is).
I don't think you will find a one-size fits all approach here.
Downloading a file? Use DownloadManager
Logging a user in and go to next screen? Probably an AsyncTask would be best.
Process an image and store it? A Service might be a good choice here since you don't want the action to be attached to any particular Activity.
Handlers are more tricky, if they are attached to a Looper running on a background thread you need to call quit() on the Looper when you are done with it. Handlers are good when you need to delay an action, postDelayed() is great for that. They are also good when you need to communicate back to the UI thread from a background thread.
But yes you are correct that each one has pitfalls as you mentioned. Android is a complex beast and it seems they could have a done a better job preventing developers from shooting themselves in the foot, especially in regards to AsyncTask being called after an Activity is destroyed!
I was using Java's old school approach by creating a class (I called it ThreadRunner) derived from Java's Thread. A constructor looked like:
public ThreadRunner (Object [] params, AbstractCallback callBack) {...}
AbstractCallback was a class that was implemnting a single 'onCall' method and was mostly used to notify a calling party about an event such as "execution of a task is completed".
I've used it to get content from Internet and run other time consuming operations. It didn't cause any problems and worked as expected.
However, I've heard many times that AsyncTask is an Android-ish way of doing things like that. I don't know why and do not have any intention to change, since I'm preaching "don't fix it if it's not broken" approach.
I've seen also comments that you'll need to write less code with AsyncTask, but in my approach with traditional Java's Threat the amount of coding was small as well, so I queses it's just a matter of your personal preferences and experience.
In regard of your 3-rd approach - I think you should use it when write a service that runs all the time, listens on requests and never stops. When you just need to execute a single task asynchronously Java Threads or AsyncTask should be used.
I think AsyncTask is a good tool for listed purposes. But it needs to wrap AsyncTask for an easy using. My variant of such wrapping (with a progress indicator) is a following:
Main class AsyncActivity for extending it in application activities:
public abstract class AsyncActivity extends Activity{
// Поле нужно обязательно объявить как статическое!
private static AsyncConnect asyncConnect = null;
protected void runBackgroundTask(String progressInscription, RequestTask task){
asyncConnect = new AsyncConnect(this, responseListener, progressInscription, task);
asyncConnect.execute();
}
protected abstract void onBackgroundTaskEnd(boolean result);
#Override
protected void onResume(){
super.onResume();
// Перерегистрируем текущий контекст этой формы
// для корректной работы слушателя ответа с сервера
responseListener.registerCurrentContext( this );
if (asyncConnect != null){
asyncConnect.onResume(this);
}
}
#Override
protected void onPause(){
super.onPause();
if (asyncConnect != null){
asyncConnect.onPause();
}
}
/**
* Чтобы диалоги не вызывались из устаревшего контекста
* и по этой причине не исчезали при повороте экрана,
* слушателя ответа с сервера необходимо сделать статическим полем класса,
* в котором должен быть зарегистрирован текущий контекст
*/
private static final OnServerResponseListener responseListener = new OnServerResponseListener(){
private AsyncActivity context = null;
#Override
public void registerCurrentContext(AsyncActivity context){this.context = context; }
#Override
public void onResponse(boolean result){
// Если никакой контекст не был зарегистрирован, ничего не делаем
if (context == null) return;
// Освождаем статическое поле для сборщика мусора (но делать это не обязательно!)
asyncConnect = null;
// Вызываем колбэк о завершении фоновой задачи
context.onBackgroundTaskEnd(result);
}
};
}
Additional class and a pair of interfaces:
public class AsyncConnect {
private final Activity context;
private final RequestTask task;
private final String progressInscription;
private final OnServerResponseListener responseListener;
private boolean isDone = false;
private ProgressDialog progressDialog;
public AsyncConnect(Activity context, OnServerResponseListener responseListener,
String progressInscription, RequestTask task){
this.context = context;
this.task = task;
this.progressInscription = progressInscription;
this.responseListener = responseListener;
progressDialog = null;
isDone = false;
}
public void execute(){
if (isDone) return;
new ConnectTask().execute();
}
public void onPause(){
if (isDone) return;
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
}
public void onResume(Activity context){
if (isDone) return;
progressDialog = ProgressDialog.show( context, null, (CharSequence)progressInscription,
true, false);
}
private class ConnectTask extends AsyncTask<Object, Void, Boolean> {
#Override
protected void onPreExecute( ) {
super.onPreExecute();
progressDialog = ProgressDialog.show( context, null,
(CharSequence)progressInscription, true, false);
}
#Override
protected Boolean doInBackground(Object... messages) {
return task.call();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (progressDialog != null){
if (progressDialog.isShowing()){
progressDialog.dismiss();
progressDialog = null;
}
}
// Делаем невозможным повторное использование этого объекта
isDone = true;
responseListener.onResponse(result);
}
}
}
public interface OnServerResponseListener {
public void registerCurrentContext(AsyncActivity context);
public void onResponse(boolean result);
}
public interface RequestTask {
public boolean call();
}
For using AsyncActivity we only need to call runBackgroundTask and implement onBackgroundTaskEnd in the target activity. It's possible to create different kinds of AsyncTask wrappings based on this idea.
You may also check out Needle; it's an open-source, simple but powerful multithreading library for Android. With it you can say things like:
Needle.onMainThread().execute(new Runnable() {
#Override
public void run() {
// e.g. change one of the views
}
});
or
Needle.onBackgroundThread().execute(new UiRelatedTask<Integer>() {
#Override
protected Integer doWork() {
int result = 1+2;
return result;
}
#Override
protected void thenDoUiRelatedWork(Integer result) {
mSomeTextView.setText("result: " + result);
}
});
very simple API
fixed thread pool size
customizable thread pool size
supports UI interaction ("do work and then use result on UI thread")
android 1.5+
behaves the same on all platform versions
Check it out on GitHub: https://github.com/ZsoltSafrany/needle