The following code run inside a new thread.
private class SaveUserTask extends AsyncTask<User, Void, Void> {
#Override
protected Void doInBackground(User... users) {
DatabaseHandler dbHandler = new DatabaseHandler(LoginActivity.this);
dbHandler.createUser(users[0]);
return null;
}
}
The code that construct it and run it is inside a callback method.
private class GraphCallbackHandler implements Request.GraphUserCallback {
#Override
public void onCompleted(GraphUser gUser, Response response) {
if (gUser != null) {
id = gUser.getId().trim();
DatabaseHandler dbHandler = new DatabaseHandler(
LoginActivity.this);
if (!dbHandler.isFacebookIdAlreadyStored(id)) {
SaveUserTask suTask = new SaveUserTask();
User user = new User();
user.setUsername(gUser.getUsername().trim());
user.setFacebookId(id);
if (email != null)
user.setEmail(emailStr.trim());
suTask.execute(user);
}
}
It looks as if that callback method is being called twice causing two identical rows to be inserted into the table. Is there any way to prevent this either by preventing the callback method from being called twice (which to me seems quite unlikely to achieve) or stopping the background task from running twice?
Simply do this steps:
Move your user existance check code to your doInBackground method.
set doInBackground method code synchronized by an Object LOCK.
or you can store your saved users to an object like HashSet inside memory and check existance before inserting to db.
Note that some where of working with database in cases like that must be thread safe or synchronized. Otherwise, you may have such problems like this.
I think you just have a typical race condition if onCompleted called twice in short period of time:
Happy path:
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Do insert (thread2)
Check user doesn't exist (thread1) -> do nothing
and it could work in another order, as threads work in parallel:
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Check user doesn't exist (thread1)
Launch insert in another thread (thread1)
Do insert (thread2)
Do insert (thread3)
I think the best solution is to move (or copy) the check so that the async operation should do the check to make the operation idempotent.
Related
I have a pretty standard static class extending AsyncTask as follows:
public static class MyAsyncTask extends AsyncTask<Void, Void, Response<String>>{
// Some members, including a listener
public MyAsyncTask( // some params ){
// Init
}
#Override
protected void onCancelled() {
super.onCancelled();
}
#Override
protected Response<String> doInBackground(Void... voids) {
// some background work
return response; // e.g., a Response<T> object as found in Retrofit
}
#Override
protected void onPostExecute(Response<String> response) {
// Send result params to a listener for further processing
listener.onMyAsyncTaskResult( //params );
}
}
A main method generates time-series data. The main method calls MyAsyncTask for each data point as and when it is generated by the main method. MyAsyncTask handles some network calls (e.g. using Retrofit) and other async operations that are generated for each element in the time-series. State information is to be maintained corresponding to each data point in the time-series, before and after MyAsyncTask returns.
The main method may terminate either automatically or by user input, such that the network responses for some past data in the time-series are still pending.
The main method displays a final state to the user after it is terminated. Ideally, I would like to wait for all the network responses, using which the final state may be displayed on a "best-effort" basis. But if a waitingThreshold is crossed, I would like to terminate the pending callbacks, since waiting too much after having completed an action doesn't generally make for good UX. This is the trade-off here.
Further, after the main method is terminated, it can be relaunched either automatically or by user input, in which case, the callbacks from the previous instance of the main method are no longer required. Also, for example, any additional background work (such as database writes) that happens in the callbacks become unnecessary because the final state of the previous instance of the main method has already been set.
The main method and callbacks run inside a Service.
One way to do this is to simply track the state of the main method globally, such as using boolean isMainMethodTerminated, and ignore the response in the callback if it has been terminated.
isMainMethodTerminated = false;
if(time > waitingThreshold){
// Terminate the main time-series method
isMainMethodTerminated = true;
}
...
#Override
public void onMyAsyncTaskResult( //params ){
if(!isMainMethodTerminated){
// continue using the callback
}
}
Using this method, the callbacks will still keep happening, but we just side-step the work inside the callback.
Is it better to instead call .cancel() on each instance of the pending MyAsyncTasks?
While I can use the above interception method using isMainMethodTerminated, it doesn't solve the problem very neatly.
What would be the efficient method(s) to handle the trade-off?
I am trying to read a list of integers inside of the doInBackground of AsyncTask. When I pass the list into the constructor of AsyncTask, it is full. But, by the time I get to the doInBackground function, it is empty. Any ideas?
public class floatingActionButtonClickListener implements View.OnClickListener{
#Override
public void onClick(View v) {
if(mAdapter.getDeleteModeStatus()){
// Delete items from database
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
// Turn FAB back to regular button
mFAB.setImageResource(R.drawable.baseline_add_white_48); // Turn FAB to delete button
// Disable delete mode
mAdapter.exitDeleteMode();
// Load database
new LoadDatabase().execute();
}
else{
Intent intent = new Intent(getBaseContext(), AcitivtyJournal.class);
int journalType = Constants.JOURNALTYPE_FULL;
intent.putExtra(Constants.JOURNAL_TYPE, journalType);
startActivity(intent);
}
}
}
private class DeleteDatabase extends AsyncTask <ArrayList<Integer>, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBarHolder.setVisibility(View.VISIBLE);
}
#Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> IDsToDelete = arrayLists[0];
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "JournalEntries")
.build();
for(Integer idToDelete : IDsToDelete){
db.mJournalEntriesDao().deleteCompleteJournalEntry(idToDelete);
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
mProgressBarHolder.setVisibility(View.GONE);
}
}
}
This is not how you use and AsyncTask. You need to declare the parameters and then recieve them in the callback.
Please also note that you are trying to access the same data(IDsToDelete) from two threads(Main and Background), in your way, without proper syncronization.
private class DeleteDatabase extends AsyncTask<ArrayList<Integer>, Void, Void> {
#Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> params = arrayLists[0];
// Do what you need
}
}
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
When you have multithreading you need to look for two things:
atomic execution of operations
memory visibility.
There is a shared memory and every CPU caches the data. When you create something from one thread you can't just expect that the second thread will just read it. In your case you are creating the AsyncTask and inject the params from one thread, but then you read them in doInBackground from another. In general when you go through a synchronized block or hit a volatile variable(I say in general, because I also don't fully understand how JVM works), the thread flushes it's cache to the main memory and then reads also from it. This is how the data is shared. That is why it is better to use the framework way, because the frame will take care of proper publication of your data between threads. You are ok with immutable data, but a List is not such thing. And even if you declare the reference as immutable, you might see the right object from both threads, but the data they are holding might be old.
Just to be clear. I am not saying that the previous way was not working. I am saying that it is on good will. You can't just share data betweeb threads and hope it works.
Figured it out. Posting for people in the future who may have similar questions.
Embarrasingly enough, the ArrayList<Integer> was coming empty because I was deleting it in the function mAdapter.exitDeleteMode(); after I call AsyncTask().execute().
I was not aware that when I send the list to the AsyncTask it was the exact address of the list and not just a new list (that is, until I posted the comment above, and then it clicked). I think I got that train of thinking from C++ or another language. I don't remember which.
Solution: The solution I came up with is to just move mAdapter.exitDeleteMode() into of onPostExecute()instead of having it in the onClick() method.
Another Potential Solution: I believe another solution that would work (but I did not test) would be to just insert a new ArrayList<Integer> () into the AsyncTask
I am using AsyncTask so that the function I want executes immediately and does not wait till the end to be executed..
but for some reason I don't why it executes in at the end of all process!
I looked at other solutions and found that Thread should be executed at the end but for AsyncTask it should be executed whenever it is called..
here is my code
private void LogMeIn()
{
string CheckValue;
// Here I call the AsyncTask
new GCM().execute(null,null,null);
//gcmRegID is a public variable and should has GCM value assigned to it by now, but I it is empty as GCM() has not been executed yet
//This is always return empty string
CheckValue = gcmRegID;
}
This is the AsyncTask that wait till the end to be executed
//This is the AsyncTask
private class GCM extends AsyncTask<String, String, String> {
private String resp;
private Context context;
#Override
protected String doInBackground(String... params) {
GCMHelper gcmRegistrationHelper = new GCMHelper (
getApplicationContext());
try {
gcmRegID = gcmRegistrationHelper.GCMRegister("123456789");
} catch (Exception e) {
e.printStackTrace();
}
return gcmRegID;
}
}
I tried to put the call for GCMRegister in onPreExecute but i get an error that it has to be in the main thread
it is like i am going in circles....
the call has to be in the main thread and the main thread will be executed at the end of the function...
it is like no way to get the GCM code in the middle!!!!
How can I make this AsyncTask executes when it called??
Thanks
Without seeing more of your code it's hard for me to tell but I would take a look at where you are calling LogMeIn(). Because your AsyncTask and call to execute are nested in the LogMeIn() function, it won't be called until LogMeIn() is first called.
AsyncTask goes through the following 4 steps in order after calling execute():
onPreExecute()
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
These can be added to your GCM class and used however you like. Note that you don't call them directly. AsyncTask does it automatically after calling .execute().
Only the tasks specified in doInBackground(Params...) are executed on a background thread. The rest are all done on the UI(or main) thread. I would suggest putting either a toast or a log inside onPreExecute() and in onPostExecute() to debug where/when GCM().execute is actually being called and then to tell you when the background task is complete. This will give you a better idea of what is going on.
Make sure you aren't trying to update the UI in doInBackground().
Would love to help more but we would need to see more of your code.
#Override
public void onPreExecute() {
super.onPreExecute();
Log.d("GCM", "onPreExecute: called");
}
#Override
public void onPostExecute(String resultOfDoInBackground) {
super.onPostExecute(resultOfDoInBackground);
Log.d("GCM", "onPostExecute: called");
}
AsyncTask keeps a queue of tasks and a thread pool,the thread pool execute the tasks one by one,so if you have too more tasks ,you will find it not execute your tasks immediately.
And in one process ,all your AsyncTask share one thread pool.In this case,you should make one task queue by yourself,you can just use HandleThread to execute a timely task.
Try placing your new GCM().execute(null,null,null); in the protected void onCreate(Bundle savedInstanceState) method. this way it will be called once the app is ran. This way you will have your GCM id before you get to the LogMEIn method.
Try this -
if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
new GCM().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,params);
} else {
new GCM().execute();
}
I am following tutes from codelearn, and trying create an AsyncTask which generates tweets and executes another AsyncTask to write to a cache file.
I have Thread.sleep, so the UI on first load waits until the Tweets are written to cache file. First I execute AysncTask new AsyncWriteTweets(this.parent).execute(tweets); then sleep for 10 secs.
But in logcat I can see that AsyncWriteTweets also gets executed after 10 sec sleep. Hence onPostExecute gets executed before the tweets are written to the cache file, giving a blank screen.
public class AsyncFetchTweets extends AsyncTask<Void, Void, Void> {
private TweetListActivity parent;
ArrayList<Tweet> tweets = new ArrayList<Tweet>();
ArrayList[] temp;
public AsyncFetchTweets(TweetListActivity parent){
this.parent = parent;
}
#Override
protected Void doInBackground(Void... params) {
int result = 0;
Log.d("ASync", "Calling asycn");
for (int i=0;i<4;i++){
Tweet tweet = new Tweet();
tweet.setTitle("Title Async Very New" + i);
tweet.setBody("Body text for tweet no " + i);
tweets.add(tweet);
}
new AsyncWriteTweets(this.parent).execute(tweets);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Void result){
Log.d("Async", "on Post execute");
this.parent.renderTweets();
}
}
PS: My assumption is AsyncTask should create a new thread, hence
Thread.sleep in parent should not stop child. If it is otherwise
please advise how can I overcome this issue.
This:
new AsyncWriteTweets(this.parent).execute(tweets);
is wrong, AsyncTask must be executed on UI thread and not Worker thread. You might use Handler and post runnable to execute it safely.
For reference look into Threading rules:
execute(Params...) must be invoked on the UI thread.
http://developer.android.com/reference/android/os/AsyncTask.html
another part of above link of interest is Order of execution, :
Starting with HONEYCOMB, tasks are executed on a single thread to avoid common application errors caused by parallel execution.
so your first asynctask must end before next one might start, but you migt bring back previous parallel behaviour by using executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR. Still execute must be done on UI thread.
As per documentation on execute() method, a single thread is used for all async tasks. So, if you are sleeping in your async tasks, it will affect other async tasks.
Give executeOnExecutor a try.
I work on a project that makes service for mobile apps and also
I should make a project that monitor the Mobile Project.
I want to make some reports that show how many messages come in this moment
and some other reports like that.
but I don’t want to get queries in monitoring project directly from DB.
I want to make a temporary data holder in memory and save the last 10 minutes
data on it (like a variable or a list)
but I don’t know technically how?
I use Spring and Hibernate in my project.
First of all we assume that our program tries to refresh the reports of an entity called SampleEntity every 10 minutes. This is just a simple POJO.
public class SampleEntity
{
// your fields and their getters and setters
}
Next we have a class, I call it SampleEntityDA, which queries the records we need for our reports from db. As you use hibernate you can simply return the result as java.util.List (I think this is one your main problems).
public class SampleEntityDA
{
public List<SampleEntity> queryFromDB()
{
// fetch records you need for your reports here
Session session = ...
return session.createQuery("from sampleEntity").list();
}
}
And at last...
query from db every 10 minutes...
To query from db every 10 minutes, you can simply use java.util.Timer class.
public class ReportTimer extends Observable
{
private Timer timer;
public static void main(String[] args)
{
// Your program starts from here
new ReportTimer().start();
}
private void start()
{
// schedule method of Timer class can execute a task repeatedly.
// This method accepts a TimerTask interface instance as its first parameter.I implement
// it as an anonymous class. TimerTask interface has a run method. Code in this method will execute repeatedly.
// Its second parameter is delay before task gets started to execute.
// And its third parameter is the interval between each execution(10min in your case)
timer = new Timer();
timer.schedule(
new TimerTask()
{
#Override
public void run()
{
notifyObservers(
new SampleEntityDA().queryFromDB() // 10 minutes passed from the last query, now its time to query from db again...
);
}
}, 100, 600000); // 600000ms = 10min
}
public void finish()
{
// call me whenever you get tired of refreshing reports
timer.cancel();
}
}
At last you need to update the data holder of your reports every 10min.
You can do this simply by Observer Pattern. As you know in java this is done by Observer class and Observable interface.
So 1) ReportTimer needs to extend Observer class and 2) in TimerTask we need to notify the listeners; this is done by notifyObservers method.
Our last class has duty of refreshing reports. I call it ReportGenerator. This class refreshes the reports whenever you like. It also has a java.util.List field that has the most recent data of db. ReportGenerator updates this field whenever its Observer - I mean ReportTimer - notifies it.
public class ReportGenerator implements Observer
{
List<SampleEntity> list = new ArrayList<SampleEntity>();
#Override
public void update(Observable o, Object arg)
{
// This method will automatically!?! executed whenever its observer notifies him.
// The arg parameter consists the new records. you just need to put it in the list field.
List<SampleEntity> list = (List<SampleEntity>) arg;
}
public void refreshReport()
{
// you can easily refresh a report with data in list field
}
public void refreshAnotherReport()
{
// you can easily refresh a report with data in list field
}
}
use map, hashMap, or ConcurrentHashMap.
make a crone job that update Map after ten min.
Here is a link for map, HashMap, ConcurrentHashMAP