In my application I start a Register activity from the Main Activity with a button
startActivity( new Intent(getBaseContext(),Register.class));
This Register activity creates records that can be viewed in a ListActivity.
If I go to the ListActivity from the Main Activity (with another button) and decide that I want to send the data of a record from the ListActivity to the Register activity in order to edit it, there are two possibilities:
1- the Register activity has never been called
2- the Register activity is opened in the background
I have two questions:
-Calling startActivity Register.class once from Main and once from ListActivity will it make two copies of Register or one?
-When I call Register activity from ListActivity and try to pass data with a handler, the handler message arrives before the activity is opened and the data do not show in the Register screen? How can I do that? Is there a way to know from the ListActivity when the view of Register is opened?
Thanks.
Charles.
The first question has a complex answer, but shortly you can control instantiation of activities, only it has implications in flow of user interaction: see Activities and Tasks, particularly Launch modes.
For the second, I don't know what kind of data you're going to pass, but consider putting it in the intent with some Intent.putExtra() method (there are many for many types of data).
Related
Asume I have two Activities:
MainActivity: Shows a list of items that are stored in a SQLiteDB
NotificationActivity: Activity from which the user can add an item to the database.
NotificationActivity is opened when a user clicks on the notification. Next, the user adds an item to the database and the NotificationActivity is closed. How can I inform my MainActivity that an object was added?
What won't work:
I can't use a broadcastreiceiver because it is unregisterd when the activity is paused, which ofcourse happend when my NotificationActivity opens.
I can't use startActivityForResult because NotificationActivity opens from a notification.
I can't use MainActivity its onResume because I don't to update the list every time the MainActivity is resumed.
So how can I send a message/object to my MainActivity from my NotificationActivity that was opened from a notification?
Looking at the comment exchange between you and #Hulk, you have the following options:
Use a BroadcastReceiver. You say that you need to unregister the receiver to prevent "Activity has leaked IntentReceiver". Yes, you should unregister your receiver, but you don't need to do it in onPause(). You can do it in onDestroy() when your Activity is destroyed. The BroadcastReceiver can stay active listening while your Activity is alive. There is no memory leak here.
Use a static (global) variable, that is set to true when the NotificationActivity makes a change to the data. In MainActivity.onResume() you can check this variable and update the UI accordingly.
If what you are trying to achieve is update the UI in Main Activity with the new item added from the Notification Activity and you are using Cursor Loaders and Content Providers in your activities checkout the concept of Cursor.setnotificationuri()
What is cursor.setNotificationUri() used for?
If you enable Cursor.setnotificationuri() in your query api in ContentProvider, any change during update, insert or delete in Content Provider is immediately reflected into the UI.
I have following activities. 1) Main activity 2) Activity 1 3) Activity 2
This is the way Activities is connected together
Main Activity -> Activity 1 -> Activity 2(Create Background Async Task) So "Activity 1" is child activity and "Activity 2" is a subchild activity. And creating Background Async task from "Activity 2"
So Let's say I am currently on "Activity 2" screen and Backround Async task is running. Now after some failure event on "Background Async task", I want go back to "Main activity". What can be good way to do this?
Few way I am thinking is, 1) To restart the app completely 2) To create new Intent of Main activity from Background Async task just like we created "Activity 1 & 2".
I am not sure which one from this is good to use. Is there any other way to do it?
I am kind of newbie to android. I am currently using BroadcastReceiver(on Activity 1 & 2)to finish current activity when Background Async task broadcast failure event but sometimes it jump to "Main activity" and sometimes jump to "Activity 1". So not working as I am looking for.
Will you please suggest a good way to do this?
[Sorry, I had to ask this question once again. Because old question was deleted]
#Rohit, I tried way you suggested to finish Activity 1 before going to Activity2. That also works but It create one another problem.
After doing this, when I press back button it directly go to Main activity rather than Activity 1 since it no longer exist.
Is there any solution which can get this both thing working? I want to jump to Activity 1 when back button is pressed. And I want to jump to Main activity when Background Async task created from Activity 2 find problem.
[Edit]
Let me describe more specific case.
Main Activity list open Wifi access point based hardware.
When clicked on particular listed access point, It opens Login activity and ask for user id & password for hardware access. Login activity onCreate function also create TcpAsyncTask background task which will communicate with hardware(which has WiFi accesspoint feature) for authentication and data passing.
When user enter login detail and click on login button, It will create momentary background task LoginDeviceAsyncTask. This task will communicate to hardware via TcpAsyncTask created earlier to verify authentication. If authentication is successful, it will create Navigation activity using startActivityForResult.
In the Navigation activity, It list options for opening specific window e.g. Dashboard. History. When user select Dashboard from options, it creates Dashboard activity using startActivity. When user select History from options, it creates History activity using startActivity.
So if Dashboard activity is opened, it display some data periodically received from hardware using TcpAsyncTask(created earlier in Login activity)
Similarly if History activity is opened, it display some data periodically received from hardware using TcpAsyncTask(created earlier in Login activity)
Dashboard/History activity has options to move to History/Dashboard activity directly. For this it creates selected activity using startActivity and finish current activity.
Now my problem is,
Let's say I am in Dashboard activity and it is displaying data received from hardware using TcpAsyncTask. Now somehow TcpAsyncTask fails to communicate with hardware and at this point I want to move to Main activity directly.
In TcpAsyncTask, I don't have context of activity like Navigation/Dashboard/History which was created after TcpAsyncTask. May be I can get this context in TcpAsyncTask using some MainActivity variables which is updated as per create/finish. Am I correct?
I am current broadcasting to close from TcpAsyncTask and receiving broadcast message in Navigation/Dashboard/History activity using BroadcastReceiver and finish particular activity which received broadcast close message. But sometimes it jump to Main activity and sometimes it jump to Navigation activity when sendBroadcast from TcpAsyncTask to close.
Pass Context in your AsyncTask and through that you can kill your Activity 1 as well as Activity 2
((Activity)context).finish();
You can do this for both activities by passing context of both.
One possible solution is to start Activity 2 with startActivityForResult() then during its processing, you can call setResult() to indicate success or failure. In Activity 1, override onActivityResult() and detect the result of Activity 2. If Activity 2 indicates a failure, simply call finish() on Activity 1 to return to the main activity.
Firstly, remember that code being run in an inactive activity when it is not in the foreground cannot be relied upon. So you should not rely on background async task. Instead, use a Service which does the background processing; this is precisely what Services are meant to encompass (among other persistent processing). While it is quite a lot for a beginner to learn, it will save you a LOT of trouble long term, as its lifecycle is far easier to manage than complex webs of activities and their relationships and lifecycles.
You should read up on android "Back Stacks". If you finish an activity, the previous activity on the back stack will be displayed. These are like the history browsers maintain that determine how browser back-buttons to operate.
So what you need is the main activity spawning a new instance of the sub-activity. Then when the user navigates the back button, the previous activity in the back stack (your main activity) will be resumed. This will not need intents.
However, for an activity to be triggered by a background processing task, I strongly recommend using a Service and intents to co-ordinate it all.
I am not able to find best solution to the situation where child activity changes data of parent activity.
I have activity A containing a list of items. Activity A starts activity B to show details to the user. User can run action and create activity C. Activity C creates new elements for the list in activity A.
The data are held in database so there is no problem with passing the data. I'm interested only in notification.
What is best solution to notify activity A that the data have been changed?
Currently I am aware of 2 solutions:
1) Return result by activity B and C with startActivityForResult(..) and Extras. The result would contain message "datachanged" -> true / false.
I don't like this one because I am not able to send the message directly
2) Always refresh data in activity A on resume.
Isn't that waste of processing?
3) Send Intent from activity C to activity A (broadcasts)
The solution I have found which are almost certainly wrong:
4) Save in some global state
There is no global state (am I right?). We shouldn't do that as there is an extra abstraction layer (intents).
5) use getParent() to use parent activity
The parent activity may be destroyed and recreated on return
Isn't there some other more light-weighy messanger system beetween activities? Something like Handler and Messanger in Activity-Service communiction. Maybe there shouldn't be one because it's against design?
Another option is to use broadcasts or localbroadcasts in order to send notification / event from C to A.
It will look something like:
1. Activity A loads the data in onCreate.
Activity A registers a broadcast receiver to some custom action "com.mypackage.datachanged".
Activity C sends broadcast intent with the same action once it changes the data.
This way - if Activity A is still kept in memory - it's receiver will catch the event and will reload your list when needed. If activity A is killed - it will auto refresh the data automatically when it is recreated.
Some notes:
1. Do not forget to un-register the receiver in Activity A's onDestroy.
2. You can use local broadcasts instead of broadcasts. The advantage:better performance and security (your intent will never leave your app).
Sending the message through B and C with startActivityForResult is the best way to do this.
I am working on an android application, where there are 4 activities. Activity1 is main activity and there are different buttons on that activity which can open other activities. Other 3 activities can also open each other. There is a thread running in Activity1 which returns some counter. I need to show that counter on all activities.
At an specific time, the thread doesn't know which activity is at top. What is the right way to control this scenario, such that thread output should update on all activities, no matter which one is at top?
I would have that counter on a Service and I would send updates through broadcast intent.
Each Activity will register a listener to that intent on the onStart method and unregister it on onPause. This way the update will reach only the Activity that is on screen.
I'm trying to refactor/redesign an Android app. Currently, I've one UI activity (Activity 1) that creates a DataThread. This thread is responsible for network I/O and interacts (provides data) with the UI activity via a handler.
Now, I want to add another activity (a new UI screen with Video) - Activity 2. Activity 1 is still the main activity. Activity 2 will be invoked when the user clicks a button on Activity 1. Activity 2's data also comes from the DataThread.
My idea is to put the logic of my DataThread inside an Android Service (DataService). My question is - can more than on activity bind to my DataService at the same time? Is there a way to tell the service to provide data to a specific activity only?
Any other ideas are welcome?
Thanks in advance.
Definitely more than one activity can bind to your service. You will get an onBind() for each one that binds. Your service would then ideally handle the logic of interacting with multiple activities by identifying them using an ID or the intent (with your own IDs for each activities as extras) from onBind() in your service. You could then have the Service spawn off a background thread for each activity that binded to it.
I usually bind my service from the Application class and have some kind of controller class (like a "mediator" I guess...not sure how all these patterns are named) scoped in the application that handles communications between services and whatever the active Activity is.
This would involve writing your own Application class and telling the Manifest to use this one. I went into more detail on this process in a previous thread:
More efficient way of updating UI from Service than intents?
You could keep track of the "currently active" Activity by sending the Application class a reference to itself in onResume (also explained in the example above). This can be accomplished by deriving your Activities from a common base class that has a way of getting your Application class (casting from getApplicationContext), and in this base class' onResume, send a ref of itself to the application. Then, you can register activities by name with your DataServiceController, for example, and send messages to the current Activity only if it's registered with the Controller to receive them.