i have this code
TextView B = (TextView)findViewById(R.id.txtMSG);
B.setText("Loading...");
Call_My_Func();
B.setText("");
my function Call_My_Func() work for 1 minute, but i can see the message "Loading..."
is there in java for android something like Application.DoEvent() like i use in C# ?
You are not seeing the message because you're blocking the UI thread with that long running call (as you seem to know based on your DoEvent comment).
An easy way to move long running operations into another thread is Androids AsyncTask.
Related
In android, if I want to modify some view's properties in non-ui thread(e. g. setText for TextView), I have to write codes like these:
runOnUiThread(new Runnable(){
textView.setText("Hello world");
});
And in c#,i have to use a delegate,which is more complicated.
So why they(framework) don't help us to do these thing in inner code like the following?
void setText(string text){
if(isInMainThread()){
//direct set text
}else{
post(new Runnable(){
setText(text);
});
}
}
Is there any reason similiar to java thread stop method deprecated because the flow need to be controled by coder?
Thanks in advance, and forgive my poor english.
Short answer: Because of Android's single-threaded architecture, UI toolkit is not thread-safe.
Here you can find the full answer from Android's official documentation Android - Processes and Threads
When an application component starts and the application does not have any other components running, the Android system starts a new Linux process for the application with a single thread of execution. By default, all components of the same application run in the same process and thread (called the "main" thread).
Additionally:
The Andoid UI toolkit is not thread-safe. So, you must not manipulate your UI from a worker thread—you must do all manipulation to your user interface from the UI thread. Thus, there are simply two rules to Android's single thread model:
Do not block the UI thread
Do not access the Android UI toolkit from outside the UI thread
Yes, I agree, creators could do that, but probably it came from SOLID design of Android architecture.
SOLID is an acronym, which stands for 5 basic principles of object-oriented programming and design. In my opinion if view'd checked thread on which method was called, it would violate Single-responsibility principle - should view be responsible for checking which thread was used? IMHO it shouldn't. I think creators of Android would agree with me ;)
As far as I know in current architecture, when you change text by setText method, view sends notification that its state has changed and it's OS responsibility to redraw it, but to be honest I still don't know details about how it is exactly handled.
Moreover with this approach, Android creators tried to encourage application developers to think what operations are called on which thread - e.g. big computation task shouldn't be part of UI animation.
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.
So I have this view that moves throughout different views that I have. I tried moving it using a new thread but I got "Can't access View from a different thread than it was created on", so I was like, "whatever just move it to the main thread then". So, I currently have runOnUiThread(this) (The class implements Runnable).
Now, it says:
Skipped x frames! The application may be doing too much work on its main thread.
I googled for a loophole and found that I can use a Handler to do this, which I was able to follow until it was talking about implementing a task. They used a task called PhotoTask and not knowing what it was or where it came from, I just got lost.
So can somebody either explain the Task or tell me another potential way around this?
Code that's causing the error (Note there are more if statements, but they're all the same on the inside as this one:
while (lackees[i].getTileX() < lackees[i].getDestX()
&& lackees[i].getTileY() < lackees[i]
.getDestY()) {
lackees[i].setTileX(lackees[i].getTileX() + 1);
lackees[i].setTileY(lackees[i].getTileY() + 1);
getTileAt(0, lackees[i].getTileX() - 1,
lackees[i].getTileY() - 1).removeView(
lackees[i]);
getTileAt(0, lackees[i].getTileX(),
lackees[i].getTileY()).addView(lackees[i]);
Progress Update #1:
It seems that wait() is better to use then Thread.sleep() but I still get frames lost, just not as many.
Your question is not very clear.
What do you mean by "So I have this view that moves throughout different views that I have".
Handler are mainly used to communicate between 2 threads.
PhotoTask in given link is simply an object/model used to send message from 1 thread to another via Handler.
If you want to update a view, you need to do this in main/UI thread alone. If you want to do some UI update from a separate thread you need to inform the default UI thread handler by passing the operation to be done as a separate runnable instance via runOnUiThread/ view.post/ handler.post.
I can clarify on how to use shared views without using any handler or thread if this is what you need.
I have a back-end process running (AsyncTask). I am interested in printing out System.out.println(); to the screen (something like the console in Eclipse) with information so the user is informed which calculations are running in the back.
What I wish to accomplish is seeing the text running on the screen - something like a dialog on top of the currenly-in-focus activity.
Does anyone got experience with this?
Thanks, D.
I don't think you can hijack System.out.print() and send it to the screen. But you can make a TextView and send the new lines of text to it as they are ready. Something like this should work.
String outputStr = "";
//Whenever you want to add a line to the TextView do it like this:
outputStr += "\n" + [yourNewText];
mTxt.setText(outputStr);
If you were to add lots of lines in this manner would appear to the user as the same sort of situation as the eclipse console.
Since you can do this with a TextView you could then add that TextView to a custom dialog and show it to the user.
I believe you also need to be in the UI thread to update a textview. In an asynctask, you call onProgressUpdate, which is then executed in the UI thread. Otherwise, you can use view.post or you can use a Handler.
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.