I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {
Related
I am writing Espresso Test. Here is the test case
OnClick of Fab, the app launches QuizActivity.
Let me explain to you little about my app.
So the app requirement was -
There is JSON file in assets folder
I have to parse it and store the data in database
On Main Activity load this data from database into recyclerview. There is Fab button, on click of it app pass a random list of data (which I have loaded in recyclerview) to QuizActivity
Here is how I did coding -
In MainActivity's onCreate() used AsyncTask to parse and insert data into database only once.
Once data is available, loaded it in recyclerview via AsyncTaskLoader
set Onclick listener on Fab. and passed required data to QuizActivity.
Below is my test
#RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
/* #Rule
public IntentsTestRule<MainActivity> intentsTestRule =
new IntentsTestRule<MainActivity>(MainActivity.class);
*/
#Rule
public ActivityTestRule<MainActivity> intentsTestRule =
new ActivityTestRule<MainActivity>(MainActivity.class,false,true);
#Test
public void fabTest(){
onView(withId(R.id.fab)).perform(click());
//Check if the text_question textview is displayed
onView(withId(R.id.text_question)).check(matches(isDisplayed()));
}
/* #Test
public void clickFloatingActionButton() {
onView(withId(R.id.fab))
.perform(click());
intended(hasComponent(new ComponentName(getTargetContext(), QuizActivity.class)));
}*/
}
My approach is -
Find Fab
Perform click
Check if the text_question textview is displayed. Note this textview is on QuizActivity.
After I run the test I am getting
java.lang.RuntimeException: Could not launch intent Intent {
act=android.intent.action.MAIN flg=0x14000000
cmp=my_package_name/.MainActivity } within 45 seconds. Perhaps the
main thread has not gone idle within a reasonable amount of time?
There could be an animation or something constantly repainting the
screen. Or the activity is doing network calls on creation? See the
threaddump logs. For your reference the last time the event queue was
idle before your activity launch request was 1505287862579 and now the
last time the queue went idle was: 1505287862579. If these numbers are
the same your activity might be hogging the event queue.
PS - I have turned off all the animations. I don't have progress bar in code.
Also one more note , if I comment out the AsyncTask, AsyncTaskLoader, RecyclerView part in onCreate() method then the test is passing.
I suspect that it might be causing due to background task.
Anyone faced similar problem? Please let me know if you know the solution. I am struggling from two days. I searched for similar threads on stackoverflow but nothing worked for me.
I finally got the solution!
Actually, the culprit was custom view in my adapter.
Espresso waits until the AsyncTask or AsyncTaskLoader loads the data, but it looks like custom view causing this problem as stated in the exception :
the main thread has not gone idle within a reasonable amount of time?
There could be an animation or something constantly repainting the
screen.
Anyways to overcome this problem, what I need to do is -
"If the test is running set the visibility of Custom view to GONE"
How would you do that?
private AtomicBoolean isTestRunning;
public synchronized boolean isTestRunning () {
if (null == isTestRunning) {
boolean istest;
try {
Class.forName ("Full path of your TestName"); // for e.g. com.example.MyTest
istest = true;
} catch (ClassNotFoundException e) {
istest = false;
}
isTestRunning = new AtomicBoolean (istest);
}
return isRunningTest.get ();
}
Now here I am using Recyclerview so in ViewHolder,
public InsectHolder(View itemView)
{
super(itemView);
customView = (DangerLevelView) itemView.findViewById(R.id.danger_level_tv);
if(isRunningTest()) {
customView.setVisibility(View.GONE);
}
}
And yay! your test will be passed.
Hope someone finds it helpful!
Please let me know if you have any questions in comment section below!
This is my first Android application and I am finding troubles with while loop, I am trying to use a while loop on my Android application but the application freezes.
What I'm trying to do is track the user location (using onlocationChanged) and keep querying on the location until the query returns a result. It's a GIS application so I am going to describe the application behavior:
the application keeps tracking the user position using a listener "onLocationChangedListener" and store it in a variable "myPosition". I am using a boolean"noResults=true". I will use a method "query(myPosition)" in the while loop, this method has a callback that when a result is found, and changes a boolean "noResults" to false. the loop will keep on until "noResults" is false (that means query's callback changed the boolean's value)
, here's what I did:
while(noResults)
{
//myPosition keeps changing
query(myPosition);
//query has a callback that when a result is found it changes noResults to false
}
I resolved the problem using a "Handler" that query the Feature Layer every 5 seconds, this stops the main thread from generating application not responding error:
Handler m_handler=new Handler();
Runnable m_runnable;
m_runnable = new Runnable(){
public void run() {
//query code here
m_handler.postDelayed(m_runnable, 5000);
}
};
m_handler.postDelayed(m_runnable, 0);
running while loop codes on the main thread freezes the UI, and makes all other processes pause making your app unresponsive use
Threads..
also note that the while loop you are running is running on a default Thread termed as the ui thread so in short run while loops on separate threads..
eg..
new Thread(new Runnable() {
#Override
public void run() {
// Your hard while loop here
//get whatever you want and update your ui with ui communication methods.
}
).start();
for ui communicating methods
View.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "updated ui", Toast.LENGTH_LONG).show();
}
});
the view could be any views you are updating..
also like #TehCoder said you could use asynctask but asynctask is not meant for long workaflow work there are 3 of them but i can't recall the last one
Maybe you should use an AsyncTask? I'm not quite sure what your problem is tho.
Loop is not a problem in android (or any language).
There are two scenario might be reason for your freezing,
If you run network call in api, android throw error and crashes. You have to do network related calls in Aysnc Task ot threading
Use try throw catch and exception cases to avoid app crashing and better coding skill.
I am using an AsynchTask to host a simulator that runs indefinelly and posts the results after each simulation step.
Limiting the simulation loop in background at a maximum of 25Hz, and only calling a javascript function with the results, it works "fine".
Apart from updating a webgl model in a browser, what looks fast enough, I have two more things to update from the Android UI: the FPS indicator and the panel with TextViews representing some of the values. If we forget about the FPS:
The onProgressUpdate() function is already limited to be called at 25Hz, to refresh the model. Now I use another time variable to limit, inside this method, the call to another method that updates the UI panel textViews. It is limited to 1Hz, less than what I actually wanted but fast enough for the kind of information. The method is as clean as possible, all the views are previously loaded to a variable that I keep to not load them every time.
What is the effect: looks like updating 5 textViews takes like one second where all the UI freezes, the touch moves are very very laggy...
I decreased the priority of the background task with:
#Override
protected Boolean doInBackground(ModelSimulation... params) {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
...
And used Thread.yield() at the end of the doInBackground method. This improves the behavior to what I explained, without these commands, the behavior is even worst.
My questions are:
-Can I reduce even more the priority if instead of using a background task I use a handler and my own Thread?
-Will a service improve the behavior of the UI?
-Why updating 5 textViews takes so long compared with calling a javascript function that finally will have to use the gpu to change the webgl model?
-Is Android not prepared in any sens to do dynamic applications? How applications like the ones to test sensors update so fast the UI? because there are not standar components like the textViews? (like browser going faster than a textView)
Note: even reducing the refreshing limitations, it produce a laggy effect every time the HUD is updated. In fact I talk about 5 textViews but only updating the FPS indicator produces the same pause. Looks like the only fact of having to switch to the UI thread already consumes this time.
Edit 1:
#Override
protected Boolean doInBackground(ModelSimulation... params) {
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
if(simulator.getSimulatorStatus().equals(SimulatorStatus.Connected)){
try {
while (true){
//TODO Propagate
long dur = (System.nanoTime()-time_tmp_data);
if(dur<Parameters.Simulator.min_hud_model_refreshing_interval_ns){
try {
long sleep_dur = (Parameters.Simulator.min_hud_model_refreshing_interval_ns-(System.nanoTime()-time_tmp_data))/1000000;
if(sleep_dur>0){
Thread.sleep(sleep_dur);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
time_tmp_data = System.nanoTime();
SpacecraftState sstate = propagate();
int progress = (int)((extrapDate.durationFrom(finalDate)/mission.sim_duration)*100);
if(sstate!=null){
SimResults results = new SimResults(sstate, progress);
simulator.getSimulationResults().updateSimulation(results.spacecraftState, results.sim_progress);
publishProgress();
}
if(isCancelled())
break;
Thread.yield();
}
} catch (OrekitException e) {
// TODO Auto-generated catch block
e.printStackTrace();
simulator.showMessage(simulator.getContext().getString(R.string.sim_orekit_prop_error)+": "+e.getMessage());
}
}
return true;
}
#Override
protected void onProgressUpdate(Void... values) {
//Update model by push
simulator.getSimulationResults().pushSimulationModel();
//Update GUI HUD
if(time_tmp_gui==0 || (System.nanoTime()-time_tmp_gui)>Parameters.Simulator.min_hud_panel_refreshing_interval_ns){
time_tmp_gui = System.nanoTime();
simulator.getSimulationResults().updateHUD();
}
}
If I comment the line simulator.getSimulationResults().updateHUD(); or directly the contents of the method, it works "fine". And this method is only changing some textviews text:
public synchronized void updateHUD(){
//Log.d("Sim",System.currentTimeMillis()+": "+"pre update gui 1");
activity.runOnUiThread( new Runnable() {
#SuppressLint("ResourceAsColor")
public void run() {
if(view != null){
if(panel_time != null)
panel_time.setText(info.time.replace("T", " "));
if(panel_progress != null)
panel_progress.setProgress(info.progress);
if(panel_vel != null){
panel_vel.setText("Vel. "+String.format("%.2f", info.velocity)+" Km/s");
if(info.velocity>config.limit_velocity)
panel_vel.setTextColor(activity.getResources().getColor(R.color.panel_limit));
else
panel_vel.setTextColor(activity.getResources().getColor(R.color.panel_value));
}
if(panel_accel != null){
panel_accel.setText("Accel. "+String.format("%.2f", info.acceleration)+" Km/s2");
if(info.acceleration>config.limit_acceleration)
panel_accel.setTextColor(activity.getResources().getColor(R.color.panel_limit));
else
panel_accel.setTextColor(activity.getResources().getColor(R.color.panel_value));
}
if(panel_radium != null)
panel_radium.setText("Orbit radium: "+String.format("%.1f", info.orbit_radium)+" Km");
if(panel_mass != null)
panel_mass.setText("Mass: "+String.format("%.1f", info.mass)+" Kg");
if(panel_roll != null)
panel_roll.setText("Rol: "+String.format("%.1f", (180*info.roll/Math.PI))+"º");
if(panel_pitch != null)
panel_pitch.setText("Pitch: "+String.format("%.1f", (180*info.pitch/Math.PI))+"º");
if(panel_yaw != null)
panel_yaw.setText("Yaw: "+String.format("%.1f", (180*info.yaw/Math.PI))+"º");
}
}
});
//Log.d("Sim",System.currentTimeMillis()+": "+"post update gui 1");
}
Edit 2: I can actually remove the runOnUiThread since it is already at that thread, but the effect is the same, this is not the problem.
Edit 3: I tried to comment all the lines of the method updateHUD() and leave only these two:
if(panel_time != null)
panel_time.setText(info.time.replace("T", " "));
The effect is almost the same, if I touch any textView, the animation goes by steps like periodically freezing
Edit 4:
I noticed that the process inside the AsyncTask was taking longer than the available step time so it was never sleeping. I established a safe guard time of 10ms that is slept even if the simulation step is longer than the available time. So, I have minimum 10ms free of each 100ms. The efect stills the same. I am updating at 25Hz the browser and 1Hz a single textview text. If I disable the textview update, the webgl model animates smoothly. On the other hand, if I enable the textview update too, every time the text is updated, there are some miliseconds where the browser animation and its response to touches are blocked. This effect gets worst if I increase the task priority. I tried setting a huge guard of 500ms but the freezing effect stills appearing. I am using XWalkView, can it be something blocking the interaction of this view when UI Thread is acting?
I can't understand why a 4 core 2 RAMgb device needs way more time to compute the same simulation than in Linux or windows desktop PC. I have 25Hz-->40ms of available time and the steps take almost 70ms. In a PC I could keep the simulation at 25Hz in real time. Is there so much shit running in background in Android compared to other OS?
There must be another issue with your code. Try posting your AsyncTask in here.
You could also try something very basic like:
Create a new Thread that loops every 25Hz and update your UI by using the post() method of your UI elements or the runInUiThread() of your Activity. See if there's any code still running inside the UI Thread, that could do heavy work, that can be done outside the UI Thread.
I tried literally everything except for the most logic thing, trying the application without the debugger connected.
The reason to have slower simulation than in a PC, to freese UI events... all because the debugger takes a lot of resources from the device. So, I guess that from this point and avobe I will have to test the application without debugger, what forces me to reboot the phone each time to avoid the "waiting for debugger to connect".
Thank to all who tried.
I could be wrong, but I think that yours problem in synchronization on simulator.getSimulationResults() object. I can't see the realization of the simulator class and realization of the object returned by getSimulationResults(), but I suppose that getSimulationResults() returns the same object every time? If so, then it can be looks like this:
In the AsyncTaks call simulator.getSimulationResults().updateSimulation(...). If this method is synchronized, then this call will be lock the SimulationResults object for AsyncTaks thread.
updateSimulation(...) returns, and publishProgress() is called, but publishProgress() is only schedule the onProgressUpdate(Void... values) in the UI thread.
The new iteration in the AsyncTaks thread can be started befor the UI thread gets the control and executes onProgressUpdate(Void... values). So, AsyncTaks thread goes to the first step.
The UI thread gets the control and executes the onProgressUpdate(Void... values) and synchronized void updateHUD() methods, but updateHUD() can't be executed, because SimulationResults object is locked by the AsyncTaks thread in the updateSimulation(...) method. So the UI thread returns the control to the OS. This may occur many times.
So, onProgressUpdate(Void... values) method and all events in the UI thread can be executed only if the UI thread gets the control in the right moment when updateSimulation(...) method is not called in the AsyncTask thread.
You can check this idea by replacing the public synchronized void update HUD() on the public void update HUD(), and write something randomly in the TextView.
In any case, the use of AsyncTask in this case is not the best idea. AsyncTask's are executed in the TheadPool, but in the Android system this pool can consist from only one thread. So, all AsyncTask's will be executed one by one in the one thread.
I am developing on a library that is somehow getting a CalledFromWrongThread Exception crash on Samsung Galaxy S1 (api v7 - android 2.1). The code is something like this:
class MyWebViewClient extends WebViewClient {
#Override
public void shouldOverrideUrlLoading(WebView view, String url) {
someListener.addToUiView();
}
}
and of course, the method that is actually throwing the error (which implements a listener callback):
View v;
public void addToUiView(){
v.addView(new TextView(context)); //<-- this line is throwing the error on rare occasions
}
I'm skipping some code in between, but i'm not doing anything weird in other places. Also note: this crash only seems to have been happening a very very small % of the time. (not necessarily conclusive, as not everyone reports their data).
has anyone else come across this?? Is WebCore threading messing things up?
Now I haven't actually tested this but I am going to answer to the best of my knowledge. That said, my instinct is telling me that you are only seeing the error intermittently because web requests from a WebView (browser) happen with varying levels of asynchronicity and probably utilize a thread pool to accomplish this. Basically, sometimes it requests resources in parallel and sometimes it doesn't. Worse yet you might be seeing this error on only a single device because OEMs optimize OS level code (like the WebView internals) based on their preferences and opinions (especially Samsung). Either way the real problem is that you are doing something "UI related" in a place that is definitely not guaranteed to be "UI friendly"... That is, anywhere where you are getting a subsystem callback.
The solution to your problem is much more simpler than the explanation: just use your context (that I am assuming is an Activity)..
Activitys have a built in function called runOnUiThread(Runnable) that will guard the code inside the runnable from running on the wrong thread. Basically, your problem is really common and android has a built-in solution. runOnUiThread will only add overhead if required, in other words if your thread is the UI thread, it will just run the Runnable, if it isn't it uses the correct Handler (the one associated with the UI thread) to run the Runnable.
Here is what it should look like:
View v;
public void addToUiView() {
final Activity activity = (Activity) context;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
v.addView(new TextView(activity));
}
});
}
i coded that up right inside the SO window so my apologies for any egregious errors, I hope that helps, and let me know if you need more info or of this doesn't solve your problem -ck
I've created an AsyncTask that loads messaging history from a database and then shows it on the device screen:
private void loadHistoryFromDB(Date lastUpdateDate)
{
final class DBAsyncTask extends AsyncTask<Void, Void, List<XMPPMessage>>
{
#Override
protected List<XMPPMessage> doInBackground(Void... arg0)
{
List<XMPPMessage> messages = null;
try
{
messages = PersistenceManager.getXMPPMessagesFromDB(userInfo, 0, messagingActivity);
}
catch (SQLException e)
{
e.printStackTrace();
}
catch (LetsDatabaseException e)
{
e.printStackTrace();
}
return messages;
}
It seems to work fine, but after being executed, it leaves 2 running threads and I can't finish the activity because of that. How can I fix it?
As long as your tasks are executing properly (exits from onPostExecute), this shouldn't be something you have to worry about. Once executed, AsyncTask thread(s) will stick around for possible reuse in the form of a thread pool or single thread, depending on platform version. This is normal behaviour - they will eventually be cleaned-up/reused.
First off, make sure you are calling super.doInBackGround() at the top of your overridden method call.
If that isn't it, it's likely because you are maintaining the connecting to the database.
That is, you still have a lock established on the database.
See if you can explicitly unlock the database, that may fix your problem.
You could put it in the onPostExecute() method.
This problem is most likely due to confusion surrounding the cancel method of AsyncTask.
You need to break down your background task into loopable segments, then Before each loop iteration starts doing your task,you need to check if the task is cancelled and if it is you need to break the loop. There doesn't seem to be any other way to stop an AsyncTask from executing.
I've posted a detailed guide to this problem with code examples here:
http://tpbapp.com/android-development/android-asynctask-stop-running-cancel-method/