I have a general scenario, but couldn't make out how to handle it.
I have a ListView with each item having different clickable views. Of which 1 is add as friend button beside the user name in the item.
So, in the ListViewAdapter's getView() i implemented onClick for this button this way.
onClick(){
//make the button invisible, for UX
//change the value of is_friend = 1, in the Adapter ArrayList, which will be helpful when listView is scrolled and getView is called again, to make it visible or invisible.
//Send the info to the server as an AsyncTask
}
This works fine.
Problem:
instead of clicking the add as friend button, I can click the user name go to his profile and click the add as friend button in that Activity.
Now when i comeback to the ListView, the add as friend button is still visible, because the adapter ArrayList has old data taken from server and i am not even changing them.
I thought of StartActivityForResult when user name is clicked. But i might not comeback to the ListView as soon as i click add as friend, there are lot of other actions on a user's profile.
A familiar case easily handled by many apps. Any idea on how this is done?
Thank You
EDIT:
Though the answers given below work. They are not the best way to do.
So, a better way might be to make a call to a static method of the listViewAdapter to update that value only in its ArrayList??
The comment of gsingh2011 is valid. However, I am guessing that your remark will be something like "I populate the ArrayList by querying the server and I don't want to do that to often".
More generally speaking, the comment of gsingh can be translated to this: you should base your adapter and 'ViewProfileActivity' on the same data. You can do this by sharing the ArrayList between the two (as a static, or a public member or whatever you want). When you then change something from your 'ViewProfileActivity', your ListView will automatically update once you switch back to it (because getView() will be called on its adapter again, which will generate a view based on the new data).
The text above is an answer to your question, but let me just add some other remarks:
you say you are sending info to a server in an asynctask. You should change this to using an (Intent)Service for that. You don't have any guarantees that your data will be fully sent when your Activity is put in the background. If you delegate this server synchronization to a Service, it will make sure your process is kept around long enough for your send to finish.
once you have that service, that would be a nice place to put your "shared data" as discussed above. You could also use a small database for that and let the service only handle the synchronization between your local database and the remote server. Then you have something that is beginning to look like a REST implementation, where your device is caching remote data locally, but in the end is only visualizing the state of the remote server. You can look up an excellent google i/o presentation on dealing with REST servers. This presentation is also nice if you are not interested in the REST part, because (maybe more importantly) it shows you what things you have to take into account when you want to have guarantee of successful persistence of data.
Related
I'm working on my first app that uses RecyclerView and while I am making great progress, I strongly suspect that my design needs some changes.
I've asked in several places over recent weeks for complete examples of a RecyclerView that read, update, insert and delete and have come up empty so I'm guessing my way along based on various passing remarks. First, let me explain concisely how I have designed this app. I imagine this will make my mistakes self-evident.
My RecyclerView is based around sales in the small company where I work. Each sale consists of a client code, an order number, an order date, a number of tickets sold, and a seller name. My design uses a listener to react to a FAB (FloatingActionBar) and, if pressed, goes to an Add activity that prompts the user for the information needed to create a new sale. No information is passed to this activity because none is needed. The Add activity validates the data and, when the user presses an Add button, that new data is passed back to my main activity. The main activity inserts a row into a remote MySQL table via a PHP script invoked from an AsyncTask in my app. Upon returning from the database, if the insert worked (it could fail if it was a duplicate record), I add the information to my ArrayList and notifyItemInserted in the onPostExecute() method. That all seems to work okay although I always get two copies of the new sale in the RecyclerView. The next time the screen refreshes though - when I do another Add, Update or Remove - the duplicate sale disappears.
Each item in my RecyclerView contains all of the information for one sale, plus two clickable images, one intended for Editing (it's a blue pencil), and one intended for Remove (it's a red garbage can). If the user wants to edit that sale, he clicks on the blue pencil; if he wants to delete it, he clicks on the red garbage can. I use listeners to determine which image got clicked.
When someone clicks on the Edit graphic, I launch an Edit activity, passing the information from the existing sale to that activity. The activity displays the information and the user can modify any of the five fields. All changes are validated and, if all the validations are successful, the changed information is passed back to the Main activity which updates the existing row in the database in the doInBackground() method of an AsyncTask. If the update is successful, I try to change the information in my ArrayList and notifyItemChanged in onPostExecute(). That always fails.
When someone clicks on the Remove graphic, I launch a Remove activity, passing the information from the existing sale to that activity. The activity displays the information and the user can only press Remove to confirm that the sale should be removed or press Cancel to abort the removal. If Remove was pressed, the information from the sale is passed back to MainActivity which removes the existing row in the database in the doInBackground() method of an AsyncTask. If the database delete is successful, I try to delete the item from the ArrayList and then notifyItemRemoved in onPostExecute(). That always fails.
As you can see, the Edit and Remove both fail every time. The reason is that there is an indexOutOfBoundsException with respect to the position used in attempting to modify or remove the item from the ArrayList.
Now that I've set out an understanding of the situation, I can ask my specific questions:
Is it reasonable/appropriate to use Activities to do the work I've described for Add, Edit and Remove processes in the first place or would I be better making them fragments?
Is it appropriate to be doing the database activity and the adjustment of the ArrayList in the main activity or should I be letting the Add, Edit, and Remove activities (or fragments if that's better) do the work?
I think my fundamental problem is that my code can't "see" everything it needs to see at the point where it is doing its work. I think I need to redesign things a bit to make the app work better.
RecyclerView seems to be pretty fundamental so I want to make sure I write everything correctly. In fact, given the absence of good examples that show a RecyclerView that has all the functionality I'm describing, I'd like to write a tutorial or make a video series showing my finished app with all the critical parts explained so that others can learn from it.
I have a list of orders in one fragment. In a second fragment, I display the detail of the order, and I use a third fragment to display the buttons that change the status of the order.
In the list, each order is displayed with a background color that indicates its status, for example green for a completed delivery.
When in landscape mode, both the detail and list are shown. In portrait mode I use two separate activities.
This all works fine, up until I change the status of an order. I can't find a way to get the list to update.
As I understand it, what needs to happen is the adapter needs to have its notifyDateChanged() method called. I've tried calling it directly from the method that processes the button click, I've tried an asynctask, and I've tried a handler. My debug methods show that the call is happening, but the list doesn't get updated.
It's possible I'm doing something completely bone-headed, but I've double and triple checked things. I suspect there is some key element I don't understand. I hope someone else does and will tell me what I'm missing.
I had some code posted, but it was clearly wrong. Not sure what code to post, since I think this is more a conceptual than coding issue.
If you want to update a view, try to use :
Thread + Handler
AsyncTask
What I discovered, through the helpful comments of other posters, is that my problem wasn't that the adapter wasn't getting the notifyDataChanged() call on the correct thread. I put in debug code that proved that. The problem was that the background of the listview item was based on a change in the underlying data itself, so the real answer was to get the Adapter to refresh the Cursor. I made some changes. I modified the AsyncTask I was using to notify the adapter. Now the AsyncTask gets a new cursor and calls adapter.changeCursor(cursor) with the result. The AsyncTask is called from the MainActivity (which hosts both the list and detail fragments) when the status is changed. It's also called in the onResume() portion of the ListFragment code, so the list will be updated properly when coming back from the detail fragment. Works great.
I have question regarding my previous ListView activity.
I have my ListView which is continue updating using socket connection, now when I click on any of the list row i can go to my next screen now when i come back to my previous ListView screen my ListView is start updating again but i want to keep updating my ListView in a background when i am on my nextscreen.
Something like i want to keep my previous screen alive when i am on my nextscreen.
Sounds to me like your the code you are using to load the data for your ListView is tied to your Activity.
For instance you have an AsyncTask or Thread in your Activity that cointains your ListView and you use it to download data, or do whatever is needed to get the data to populate the list. I also assume you start it in one of the Activity lifecycle methods e.g. onCreate().
If that is the case then you should consider seperating the code used for getting the data for the list from your activity code.
One way to do this is to use a Service which will be able to run independantly of the rest of your application and do all the heavy lifting involed with fetching the data for your list. You can communicate with the service from anywhere in your application. The Service can save the data to a database. Then all you have to do in your Activity is query the database and populate the adapter to get the latest data without much delay.
You can read more about services here:
http://developer.android.com/reference/android/app/Service.html
You could (and probably should) do what Paul suggested or you could change to way you switch your screens by using Fragments or a ViewFlipper. This way you still run your AsyncTask or Thread while doing something else on a different page.
I would like to write an app to follow the price of lists of stocks.
There would be three activities containing lists of stocks :
myStocksActivity containing the stocks I'm interested in
searchedStocksActivity containing a list of stocks I could add in the list contained in myStocksActivity
winnersLoosersStocksActivity containing the list of stocks with the best or worst performance of the day.
I would like to persist the list of stocks in myStocksActivity, to be able to remove or add stocks from that list and to add the stocks displayed in searchedStocksActivity or winnersLoosersStocksActivity to myStocksActivity.
Another challenge : the price of the stocks should be updated every X minutes depending on the settings of app. The prices should only be updated when the app is running and should only update the prices of the list I'm currently looking at.
For the moment, my architecture isn't great : almost all the logic is contained in myStocksActivity and I know it's not a good thing.
I was thinking about moving the update of the stock list to a service, but I don't want this service to run when the application is not running.
What do you think ? Is my problem clear ? Thank you !
If I was you I would try and design(and build) a domain model first. This should end up being a set of classes which allows you to do everything you want with your stocks, independently of the a UI. You should also build in data persistence directly into these classes (i suggest using SQLite for this bit).
Then once you have a working model, build the UI on top of that. The MVP design pattern works pretty well with android.
Implement your activities as Views, these should both present data, and captures UI events and delegate these events to to Presenter instances, which then communicate/manipulate the model, and updates the Views accordingly. For example,
MyStocksView could present the user with a list of stocks, and the latest movements of stock price (or whatever). The MyStocksView contains the actual widgets that make up the user interface, and also acts as event listener and handler for various UI events (like when the user click a button). It should also contain a instance of a MyStocksPresenter class.
Once the user clicks the button, lets say, "remove stock", the event handler of MyStocksView then fires a method in the presenter instance for example, presenter.removeStock(id) , this method then updates the model (removes it from the in-memory data structures and database) and finally, if everything was successful, updates the View. It basically works as a middle man between the presentation layer, and the data-model.
In regards to the automatic updates every X minutes, I would handle this with a AsyncTask, there's not really much point in using a service if you only want this to happen while you app is running.
Whenever you main activity gets paused (or destroyed), call StopService(blabla);.
That way you can keep it as a service, and it won't run in the background.
Create a class for a stock, and store the update logic in there
I would put the handler - what holds instances of the stock-class and loops over a set to tell them to update - either in its own class purely with static methods and variables, or also in the stock class with static methods/etc.
The service then contains timing information, and calls the static update() method
The activity that displays stocks starts/stops the service with onCreate/onDestroy or onUpdate/onPause (I think it's update; the on that happens each time the Activity is brought to the forefront)
Same activity tells the handler class which ones to load, and uses its list for the display.
One other thing: I'd suggest against using a service. Use an AsyncTask. Services actually do run on the UI thread, so if there's a long-running loop during the update, the UI will freeze. AsyncTask starts a thread and will not block the UI.
I have a ListActivity which lists a bunch of "things." If you click on one of these "things," you're taken to another ListActivity which lists a bunch of "stuff" for that "thing."
Say I want to give the user the ability to edit the name of some of the "stuff"; or even delete some of the "stuff." At what point should I actually perform that action on my database?
Ex: If a row of "stuff" gets deleted, should the database be updated before I return my user to the list of "things?" Or should the user return to the list of "things" and then the database is updated? Or does it not matter?
Mind you the database updating will likely happen in a service (I'll also be calling a web service to update the cloud).
I would do the database transaction after the user is finished messing with it, only because I would want to give them some way to undo an accidental deletion before committing it to the database.
Edit: See jball's answer. He understood you better than I did.
It depends on what is important in your application. If it's important that a user never thinks a child is deleted when it fails to delete, you should wait to get a response from the server before displaying the new list of children to the user.
However, if deletion confirmation is not so important and application responsiveness is critical, update the user's display and then do the deletion asynchronously behind the scenes.
You should definitly update the child activity as soon as the action is commited. That way you will not have inconsistencies. Updating many changes to child activity when returning to parent, while exiting is risky, because if the network loses connection, you may not have all the changes fully committed. This could lead to database inconsistencies.