Why non-ui thread can not modify view properties? - android

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.

Related

calling stage.act call in different thread a good idea in libgdx?

Will calling stage.act on a seperate thread within an infinite loop is a good idea?
Is there any pros and cons on this approach?
I've tried doing it,but im not sure if this will cause problem in the long run. it looks faster though.
From LibGDX documentation:
No class in libgdx is thread-safe unless explicitly marked as thread-safe in the class documentation.
You should never perform multi-threaded operations on anything that is
graphics or audio related, e.g. use scene2D components from multiple
threads.
From Stage api:
The Stage and its constituents (like Actors and Listeners) are not thread-safe and should only be updated and queried from a single thread (presumably the main render thread).
So how you can see, it's a bad idea.
We always write stage.act in render method and purpose of that we get time(dt) between 2 render method(Gdx.graphics.getDeltaTime()) call. You can write stage.act in your own loop. but for that you have to manage stop calling stage.act().
If you want to set same anim speed in every device then you should use
stage.act(Gdx.graphics.getDeltaTime()).

How can I move a View that was created on the UI Thread using a different Thread

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.

Can you safely call "getDrawable" or "decodeResource" on the UI thread in Android

Is it bad practice to call
getResources().getDrawable() or BitmapFactory.decodeResource()
from the UI thread on Android? I'm just wondering since I have this situation where I want to show a loding image in my view while I execute a background operation, but Im still calling either one of the above methods... almost every project I look at seems to execute either method on any thread without second thought, but I'm just looking for best practices.
Fast forward 3 years since I asked this question, and I think the short answer is "Just use Picasso or Glide". I think the long answer is "it depends". It depends on the size of the Image/drawable. For BitmapFactory#decodeResource, you should do everything you can to stay off the main thread. If I'm trying to show a placeholder image, best practice is that it should be packaged in your app with a reasonable size with fits with your design.
It will be good practice if you do any GUI updates on UI thread. Inside any thread you can run your UI thread where you can do the UI stuffs or else you can go for message handler also which will do the same for you.
Runnable run_in_ui = new Runnable() {
#Override
public void run() {
// do your UI stuffs here
}
};
runOnUiThread(run_in_ui);
Even though Vijay Sharma suggested using Picasso, I would suggest you using frescolib from Facebook. It does all possible optimizations starting from Hardware Caching ending up modifying Http requests with Pipelining concept.
Instead of doing it on your own, it is better to rely on Facebook team's work:
build.gradle:
dependencies {
// your app's other dependencies
compile 'com.facebook.fresco:fresco:0.7.0+'
}
view.xml:
<com.facebook.drawee.view.SimpleDraweeView
android:id="#+id/my_image_view"
android:layout_width="20dp"
android:layout_height="wrap_content"
fresco:viewAspectRatio="1.33"
<!-- other attributes -->
java:
mSimpleDraweeView.setImageURI(uri);
That simple!

android: My software does not work in a linear manner

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.

When testing android UI what's the proper way of waiting for UI to be ready?

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.

Categories

Resources