I am new to android and I have a question, it looks silly but i need to know.
I was looking in a source code of an open project that was uploaded in git the app starts with an authentication activity
user enters his/her username password, and if it didn't exists in database, it will show a snack bar, but if it was exist in database the app will do this:
RunOnUiThread(() => { TransitToServiceListActivity();});
and in TransitToServiceListActivity() method, the code defines a new intent and starts navigate to the activity related to that intent.
So my question is, why in the first place we didn't start to navigate to other Activities.
why we need to do first:
RunOnUiThread(() => { TransitToServiceListActivity();});
and then star to navigate between activities?
Why not create an intent from that activity we are going to transit to, and call that activity
what problem this RunOnUiThread(() => { TransitToServiceListActivity();}); solves that we are using it?
The purpose of RunOnUiThread is to ensure that a given Runnable is executed in the UI thread.
So, the method RunOnUiThread is meant to be called when running in a different thread other than the main one, and it is required that some specific code gets executed in the main thread. Although is also perfectly valid to be called in an ambiguous code block, which could be called in both the UI thread or a background thread, for which scenario RunOnUiThread will resolve if the runnable must be executed immediately or passed to the main thread.
I am guessing that probably the code you are looking at, is performing the authentication in a background thread. If it doesn't and there is no chance that the authentication is never executed in a background thread, then there is no point to use RunOnUiThread.
Related
This is Strange, I used to do GoogleAnalytics for my Unity Projects because I had two major uses, one was to see the number of users on Screen and second for some events. I heard about Firebase and wanted to explore it, I was successful in initializing the sdk and logging different events, but now there is one major problem which I can't seem to get over. Apparently when I try to Log my Current Screen using:
Firebase.Analytics.FirebaseAnalytics.SetCurrentScreen ("MainActivity", "MainMenu");
and then read somewhere to use it like this:
FirebaseAnalytics.SetCurrentScreen ("MainActivity", "MainMenu");
both of these functions gave the same error when viewed in Monitor(ddms)
SetCurrentScreen must be called from Main Thread
Everytime I called the function this came up, I don't know why this is happening and can't find a solution for this anywhere.
The Function calling the Method is:
public void AnalyticsLogScreen() {
// Log an event with a float.
DebugLog("Logging a Screen");
Firebase.Analytics.FirebaseAnalytics.SetCurrentScreen ("MainActivity", "MainMenu");
}
It appears that you are calling SetCurrentScreen from worker thread. You can check this by looking at the name of the thread making the call or comparing the TID from the logcat to the process PID. The main thread with have name "main" and TID that matched the app PID.
Unity SetCurrentScreen is wrapped on Java FirebaseAnalytics.setCurrentScreen() method .
setCurrentScreen can only be called from the main thread.
The reason for this requirement is that Activities in Android can only be displayed displayed from the UI thread and allowing SetCurrentScreen from worker thread creates a race condition between the Activity displayed in the UI thread and the worker thread executing the call to setCurrentScreen. To avoid this race condition Firebase requires the call to setCurrentScreen to be made on the UI thread. If you still like to set the screen from worker thread you can just call runOnUiThread though this will create the race condition so some event can be attributed to the wrong screen or appear logged not on any screen.
https://developers.google.com/tag-manager/android/v4/ua#send-screen-views this is container settings. After that you can log screen :
Firebase.Analytics.FirebaseAnalytics.LogEvent("openScreen", "screenName", "main_screen");
Tag settings:
Trigger :
Varible:
Context
I need to manage the concurrency of an app. I declared a Object sync to use monitors on that object.
The main goal is that the first button, A, will execute some code, but, when reaching some points, it needs button B to be clicked to be able to continue. Something like this:
Issues
The issue is that the B button can't be clicked, I guess it's because the UI thread is stuck waiting for the code of button A to be fully executed before raising other button events.
If I execute the code in button A in a new Thread, when I try to update the View (called UI in the drawing), I get CalledFromWrongThreadException.
Edit
I solved it adding a Handler for the UI update and the already added Thread for the code in A.
Factor the code that is taking the time into a Runnable that you execute in a separate thread, but once you've started that thread, do the UI update in the original thread.
Ok first of all android is really confusing. The scenario is I have about two runnable classes which are created from a Login View and if logged in it will create another view which will have other data and even more activities can be created from there
Now I can pass the the Login view context when creating a thread for the runnable class and edit out UI elements in them like this:
((Activity)someContext).runOnUiThread(new Runnable(){
public void run()
{
TextView txtErr = (TextView) ((Activity)someContext).findViewById(R.id.errMsg);
txtErr.setText("Some message");
}
});
But the issue is there will be more activities that will be created and the runnable class is created at the time of logging in, and I can't keep passing contexts.
Is there a better way for accessing the UI elements of different activities from different threads?
P.S: the threads which will be accessing the UI elements doesn't extend Activity and are running in a separate thread.
EDIT
I think I need to make my question more clear... I am developing a client app for a messenger... The process goes this way... User clicks on login button which creates a thread in a separate class named ClientThread for handling socket connection and keeping the connection alive till the user logs out or connection drops. The ClientThread class loops till the socket is connected and whenever some data is received the data is passed to another thread in a class named ProcessDataThread which do the parsing of data and will update the UI accordingly.
Now in a response from server if the user is logged in I want to create an activity from that class and keep a context to that activity in ProcessDataThread as I will be updating UI on further responses from server. And if login fails ProcessDataThread will display a message on the main activity saying login failed, now I was able to achieve the later by passing the context from the MainActivity to the two threads when clicked on Login like this:
global_constants.clientObject = new ClientThread(this);
global_constants.clientThread = new Thread(global_constants.clientObject);
global_constants.clientThread.start();
And then from ClientThread to ProcessDataThread
global_constants.updateConversationHandler.post(new ProcessDataThread(SharedBuff, cntxt));
But how will I create more activities from a non-activity class and do all update them or find a UI element etc...
Not sure if I understand you, but it sounds like you are trying to control the view of an activity from outside of the Activity. This sounds hacky to me. I'd let each Activity manage its own UI.
A good way of doing decoupled communication between objects is the observer pattern, aka an "event bus" or "event dispatcher" system. An example of how to do this on Android is here: http://www.therealjoshua.com/2012/03/event-dispatching-sending-messages/
Basically, the code that's generating the error should dispatch a message. The Activity can listen for this message, and then update its own UI as needed.
EDIT
Thanks for the clarification. I think the observer pattern can still help here. Basically, your data processing threads shouldn't know anything about the UI. Just have them post an event for the error, optionally with additional info on the error. If you want, your event dispatcher class could even make the actual event calls on the UI thread itself using a Runnable like you showed, so that the listener can always assume that they are being called on the UI thread, if this is important for your design. This way you don't have to pass the context to the thread at all (at least not for purposes of updating the UI) - let the worker thread just be responsible for the work, and the activity can be responsible for its own UI.
Another option you could use is an android Handler (see http://developer.android.com/reference/android/os/Handler.html)
In this case, the work is still done in another thread, but the Activity receives a handleMessage callback from the thread at the appropriate time. I haven't used this myself but from the documentation it looks like it can get the job done for what you need.
In either case IMO, the responsibility for updating the UI should lie with the Activity, not the worker thread.
The concept of the application is simple: The user will interact with the interface, different messages will be sent to a remote server and the answer will show in the screen.
I have created a class called MessageInterface to deal with AsyncTask and the messages send/reception.
The data flow, since the user interacts with the interface, till he/she receive an answer, is this:
UI Element -> MessageInterface -> AsyncTask -> Android Socket -> Server
Server -> Android Socket -> AsyncTask -> MessageInterface -> ??
I have tried different solutions with ??. Calling to different MainActivty methods depending of the message received, creating a FragmentsInterface called by the MessageInterface to deal with the appropriate fragment... but none of them satisfies me.
This is my first project using sockets in Android, I have deal with sockets in other platforms (python, C, C++/Qt) and never felt so frustrated
Any suggestion for the architecture I should use?
Manuel, (I hope I got your question right)
The Async task has different methods as follows:
onPreExecute(): this run on the UI thread, you can touch any view of the main activity.
doInBackGroud(): this runs in its own thread, you CANNOT touch the views of the main activity.
onProgressUpdate(): This method runs in the UI thread, so you may touch (update) any view of the main activity, like for example show the message that has been received.
onPostExecute(): this method runs in the UI thread, you may touch any view of the main activity, but this method executes only once, when the doInbackGroud() method finishes.
With this in mind, in the doInbackGround() method you may call, whenever you want, the onProgressUpdate() method to update a TextView, Listview or whatever view you use to display the received message. You may pass a string to the onProgressUpdate or any object you prefer.
On the other hand, you can use a ConcurrentLinkedQueue to add the messages (Strings or Objects) in the UI and poll them in the doInBackGround process to send them to the server.
if you need an example of this, let me know and I'll send it to you.
Saludos.
I know it sounds crazy that someone is using runOnUiThread inside AsyncTask. Somehow, it is working for me but I wanna know if it is an acceptable and robust approach or not. Here is the scenario:
I have an app in which after successful login, user is rendered to next screen. In this new screen, 3 different methods are loading different types of data from a web server. These methods are:
getMembersForList() : It loads the list of community members and shows it in a listview.
getProfileData() : It loads the profile of logged in user and shows his name , image etc on the screen.
getNotificationCounts : It loads the count of new notifications for the user.
I applied 3 different approaches for it :
(1) Calling all 3 methods simply in onCreate i.e. no exclusive thread is being used for any of the methods . In this case , the transition from login screen to this screen becomes very slow and black screen shows up for some time before this activity shows up.
(2) Calling getMembersForList() on UI thread and the other 2 methods on exclusive threads. In this case transition becomes fast and list shows up quickly but Notification counts and username etc. don't show up because WrongThreadException occurs saying that this thread can't touch other thread's views (TextViews for username, notification count etc. which are declared globally) . The same thing happens when I start these threads from an AsyncTask as well.
(3) Calling getMembersForList() on UI thread and then starting an AsyncTask in which the other 2 methods are being called in "runOnUiThread" inside doInBackground() method. This solves both the above issues. Now the screen transition is faster and the WrongThread exception is also not occuring.
So far the approach-(3) is working good for me but I am not sure if this is the right way to do it because runOnUiThread and AsyncTask are 2 completely opposite things. Can anyone please clear my doubts about this scenario. Thanx in advance.
Yes, use-cases like this are a big reason why the runOnUiThread() method exists in the first place. The idea is you allow your background thread(s)/AsyncTask instance(s) to run your lengthy operations in the background, and then provide a simple hook that they can use to update the interface when they have the result (or at arbitrary intervals, as different pieces of the result become available).
As long as that's what you're doing, then your usage is fine. What you want to avoid doing is performing a lengthy operation on the main thread, either directly or indirectly by passing in some lengthy operation from a background thread.
Of course you don't have to do it that way if you don't want to. You could use postExecute() instead. Or you could store the result somewhere and then use any sort of message-passing API to notify the main thread that the result is ready, and so on.
I would advice to run all the 3 calls in the asyncTask, and update the UI in the postExecute() of the AsyncTask after the background taks is complete, postExecute runs on UIthread so you need not call anything explicit to run them on UIthread.