My initial question was: Android GraphView project get freeze with real time updates. In this one I was asking about possible concurrency in UI thread of 3 plots. On memory allocation plot it looks like this:
I was receiving data directly from my ProcessThread in main activity and pass it using onEventMainThread from EventBus library back to the GraphFragment. All the data that is passed comes from ProcessThread which gathers data from Bluetooth listening service and then proceeds it to get meaningful numbers.
My idea was to test if this same will happen with test thread that only generates data and sends it to onEventMainThread. Because this also produces some errors I was forced to ask another question: Difficulty in understanding complex multi threading in Android app. After some time I've received great answer from #AsifMujteba explaining that my test thread is simply too fast.
Knowing that I was able to return to my main problem and my real thread to check if all the timings are correct. As I've said there is a lot going on so being to fast is not a problem (however, I've added this same mechanize to test if data isn't send to fast). I would be more concern about to slow work of this thread.
My current onEventMainThread looks like that:
public void onEventMainThread(float[] data) {
mSeries1.appendData(new DataPoint(counter,data[0]),true,100);
mSeries1.appendData(new DataPoint(counter,data[1]),true,100);
mSeries1.appendData(new DataPoint(counter,data[2]),true,100);
counter++;
}
Unfortunately when I've returned to the beginning the problem emerged again. After a lot of testing I am able to say that data looks like is being send correctly. I've checked it with two markers:
public void onEventMainThread(float[] data) {
Log.d("LOG","marker1");
mSeries1.appendData(new DataPoint(counter,data[0]),true,100);
mSeries1.appendData(new DataPoint(counter,data[1]),true,100);
mSeries1.appendData(new DataPoint(counter,data[2]),true,100);
counter++;
Log.d("LOG","marker2");
}
Logcat messages are appearing correctly. Unfortunately the error appears even though the sending looks this same as in my test thread:
if((System.currentTimeMillis()-start)>10) {
values[0] = (float) getRandom();
values[1] = (float) getRandom();
values[2] = (float) getRandom();
EventBus.getDefault().post(values);
start = System.currentTimeMillis();
}
What's more I am sure that the data is correctly send all the time because when I've tested another fragment with OpenGL visualization everything works.
So to sum everything up:
When sending values to the fragment using EventBus from one (very simple) thread everything works great, while sending from another (more complex) thread ends in freezing of display and showed memory allocation graph. It is important to know, that if one thread is running the second one is commented out.
Can someone please advice me what might be a problem here? Or what should I check more?
EDIT
I have done one more test with commenting out everything regarding Series data append leaving only Log.d() and no error appeared. What is interesting is that the blocking (or freezing) of graph updates doesn't affect UI itself so I can still press all the buttons and so on.
Have you tried using a Custom eventbus and not the default one?
I had a similiar problem today and i fixed that by creating a custom evenbus with a seperate ThreadPool and it worked like a charm.
Related
Since I am new to android programming, I am not sure how to write code efficiently hence the reason for this question. I am creating an app. A basic app in which the app generates 10 random math questions and evaluates it from left to right (ignoring orders of operations). E.g. 3+5/2 should equal 4 instead of 5.5.
I am getting the error Launch timeout has expired. I have researched this and found out that its because the main thread is doing too much work. How do I overcome this? My app first does alot randomizing integers, could that be the case?
This is the code. It is pretty long.
P.S. in the display method, i hrdcoded it to display the first elements just to see if it will display.
public void initAnswers(String[] questionToBeLooped){
for(int i =0; i < questionToBeLooped.length; i++){
if(mathOperations.length == 2){
runningTotal = evaluateAnswerTwoOperations(mathOperations[0], mathNumbersInIntFormat.get(0), mathNumbersInIntFormat.get(1));
}else{
int operationsCounter =0;
int numbersCounter =1;
runningTotal = mathNumbersInIntFormat.get(0);
while(mathOperations[operationsCounter] != "="){
runningTotal = evaluateAnswerTwoOperations(mathOperations[0],runningTotal,mathNumbersInIntFormat.get(numbersCounter));
}
}
answers[i] = runningTotal;
}
}
Could someone tell me how to write this efficiently and also can you provide some tips to generate fluent and efficient apps.
Not sure what in your code is the cause, but you should offload the heavy work into an AsyncTask. AsyncTask will allow you to execute code in a background thread via doInBackground and callback to the UI thread via onPostExecute. The heavy work you are doing is probably something around the looping constructs you have.
Keep in mind that you cannot modify the UI from the background, so if you need to update UI, wait until the heavy work is finished and do it in onPostExecute.
See the docs here on AsyncTask.
Also worth noting that AsyncTask has a lot of flaws, but since you are new - it is where I would recommend to start.
I am trying to incorporate Android GraphView project into my app and all the time I have some strange problem with it.
My app requires drawing graph from real time data. I have thread with all the communication that is providing the data. In main thread I am reading this data and simply use mSeries1.appendData(new DataPoint(counter,data[0]),true,100); where counter is int that is incremented after each update.
Unfortunately at some point it freeze. I've tried putting it in synchronized block or changing the line of code to mSeries1.appendData(new DataPoint(counter,counter),true,100); and still this same result.
This is how the memory looks like during app running and when it freezes:
Does anyone have any idea what might be wrong in here?
EDIT:
This is my current method for updating my graph view:
public void onEventMainThread(ReadingsUpdateData data) {
mSeries1.appendData(new DataPoint(counter,data.getData()[0]),true,100);
counter++;
}
Maybe it's too late, but I had the similar problem and finally I found that when GraphView is appended a new data of "NaN" freezes.
So check the situation in which the result will be NaN such as divide by zero or something like that.
Although you do not specify the rate at which you add points, and how long for the app runs without crashing, you should expect things to go wrong at some point (you're potentially generating an infinite number of point objects, while the memory is indeed limited).
Do you need to have all the points the app has received from the beginning drawn ? If not, you could implement a sort of circular buffer that only keeps the X last values generated by your "provider thread", and update the graph each time you receive a new value with the method
your_series.resetData( dataPoint[] my_circular_buffer_of_data_points );
This thread is quite similar to your problem, have a look at it !
I have a test case for my app which fills in the TextViews in an Activity and then simulates clicking the Save button which commits the data to a database. I repeat this several times with different data, call Instrumentation.waitForIdleSync(), and then check that the data inserted is in fact in the database. I recently ran this test three times in a row without changing or recompiling my code. The result each time was different: one test run passed and the other two test runs reported different data items missing from the database. What could cause this kind of behavior? Is it possibly due to some race condition between competing threads? How do I debug this when the outcome differs each time I run it?
Looks like a race condition.
remember in the world of threading there is no way to ensure runtime order.
I'm not an android dev so I'm only speculating but UI is only on one event thread generally so when you call the method from another thread (your test) you're probably breaking that as you're outside of the event thread.
You could try using a semaphore or more likely a lock on the resource.
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html
I (finally!) found a solution to this problem. I now call finish() on the tested Activity to make sure that all of its connections to the database are closed. This seems to ensure consistency in the data when I run the assertions.
I would suggest making a probe for the database data rather than a straight assert on it. By this I mean make a piece of code that will keep checking the database for up to a certain amount of time for a condition rather than waiting for x seconds (or idle time) then check, I am not on a proper computer so the following is only pseudo code
public static void assertDatabaseHasData(String message, String dataExpected, long maxTimeToWaitFor){
long timeToWaitUntil = System.getCurrentTimeMillis() + maxTimeToWaitFor;
boolean expectationMatched = false;
do {
if(databaseCheck() == dataExpected){
expecttionMatched == true;
}
}while(!expectationMatched && System.getCurrentTimeMillis() < timeToWaituntil);
assertTrue(message, expectationMatched);
}
When i get to a computer i will try to relook into the above and make it better (I would actually of used hamcrest rather than asserts but that is personal preference)
The test looks like that (it's ActivityInstrumentationTestCase2):
public void testItShowsThreeRows() {
activity = getActivity();
activity.runOnUiThread(new Runnable() {
public void run() {
AccountsList accountsList = new AccountsList(activity, accounts);
list.show();
}
});
ListView listView = (ListView)activity.findViewById(R.id.list);
assertEquals(3, listView.getChildCount());
}
The code I'm trying to test works. But the test fails because activity.runOnUiThread returns immediately. I can insert Thread.sleep and the test turns green but it looks kinda clumsy to me. Do I have to use some thread synchronization or may be poll for some UI element to be ready?
I tried to annotate it with #UiThreadTest but that doesn't work either. The code in list.show() populates a ListView via custom adapter and getView is called on another thread (not the one test runs on - and I have nothing to do with that, I have no threads or asynctasks, no nothing). The test fails again because it returns before UI is ready to be checked.
Calling waitForIdleSync() is better than sleeping for a fixed time.
You have to do a Thread.sleep. I don't think there's a way around this. I don't see why that's "clunky"; you're doing a test, so you have to wait for the system to show the UI element you want to test.
It seems to me, though, that you're really trying to test AccountsList or list. There's little reason to test ListView or findViewById unless you're paranoid.
You should focus on testing AccountsList and your custom adapter. You shouldn't have to use the UI to do this.
Following documentation, "One of the key parts of Espresso is its ability to synchronize all test actions. Espresso waits until the UI is idle before it moves to the next operation. Likewise, it waits for AsyncTask background operations to complete. In general, this should address the majority of test synchronizations in your application. If you have written UI tests before, you will appreciate this feature - there's no need to add waits or synchronization points to your app!
However, sometimes it is not possible to rely on automatic synchronisation, for instance when your app does background operations via non-standard means (managing threads directly or using custom Services). If you have run into a situation where you cannot rely on Espresso to automatically handle the synchronization for you, you can use idling resources and still rely on Espresso for synchronization."
You can read a full example at the testing codelab, you can also get the source code of the sample in github.
I have hundreds of CheckBox widgets in my layout and now I'm trying to invert each of them, so if it was checked it won't be checked and vice versa. Obviously such heavy work should be done in separate thread, but the problem is that all the work actually happens the UI. Part of the thread code:
for (int x = 0; x < list.getChildCount(); ++x)
{
final WListRowTarget curRow = (WListRowTarget)list.getChildAt(x);
curRow.post(new Runnable()
{
public void run()
{
try
{
curRow.getCheckBox().setChecked(!curRow.getCheckBox().isChecked());
}
catch (Exception e) {}
}
});
}
The only thing that this thread actually can do is looping through the list and posting the Runnable for every found checkbox. The problem is that all those Runnables arrive in the UI thread almost at the same time, thus they're all executed at once... The application behaves exactly like I would run the above code in the UI thread - everything freezes. A possible solution is sleeping for some miliseconds after each checkbox so the Runnable can be executed and the UI will have time to process the events... but it's more like a hack.
How can I solve this problem?
Thanks in advance,
Snowak
I have hundreds of CheckBox widgets in my layout and now I'm trying to invert each of them, so if it was checked it won't be checked and vice versa. Obviously such heavy work should be done in separate thread
No - this is fundamentally UI work, and frankly setting a bunch of flags isn't really "heavy" work. Most of the "work" involved is actually the UI repainting - which obviously does have to be done on the UI thread anyway. Creating lots of different tasks to execute on the UI thread is just giving it more work to do - just do the whole lot in one batch on the thread without trying to use different threads.
As a separate matter, I wouldn't want to use a UI with several hundred check boxes even on a desktop, let alone on a mobile - are you sure you shouldn't redesign your UI? You may find that coming up with a more elegant design removes any performance hit anyway...
Assuming you are using a listview to display all your checkboxes you don't need to use multiple threads. Store the state of the checkboxes in a data-structure and process everything using a single thread.
While doing the processing ( sounds so wrong :-) ) just show a spinner. You can then display all the checkboxes based on the state stored in the datastructure.
Okay, I've solved the problem myself. The solution is to use Object.wait() and Object.notify() in order to wait for the Object.post() to do the job. This way I don't post more events until the previous one is executed.
The code looks like:
synchronized (someObject)
{
someObject.post(new Runnable()
{
// some work here
synchronized (someObject){ someObject.notify(); }
});
someObject.wait(); // this line unlock the object
}