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.
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'm currently working on an app that is composed of a background IntentService running all the time (even when activity lost focus) and a Activity (a section pager with fragments).
The background service is checking time very often and storing a large array of objects (up to 300) parsed from an xml file.
Each object represent an event with an associated startTime and when this startTime matches the current time the service has to notify the activity (if available) to display that the event is happening.
On the activity side I have fragments (tabs of the section pager) with a custom arrayAdapter to list the events into a ListView.
Right now what I'm doing is sending my object from my service with a LocalBroadcastManager. Fragments are the listening and when they receive the object they simply update their local Arraylist by replacing it and notifying the ArrayAdapter that the data set changed.
Since each fragment has to keep an arrayList to update the ArrayAdapter and then the ListView, I end up with the same object stored both inside the service's array and in one of the fragment' array. I'm wondering if there is a better way.
The question : What would be the most efficient (on memory/cpu usage and speed) way to share a large array of objects between my service and my activity ?
You could use greenrobot's EventBus. I don't think you can avoid duplicating the data. If you will use the same object instance in the Service and in the Fragments, you'll have to take care to notify the adapters each and every time, otherwise you'll get errors.
You would be better off storing the downloaded objects in a local SQLite database and only loading the minimum amount of information needed in the Fragments. This would minimize the time it takes to transfer the data from the IntentService thread to the Activity's main thread (because you wouldn't even transfer the data, just send a signal to the current Fragment that the data has been updated). A ContentObservable may also help you.
Also, you shouldn't use an IntentService for tasks that run all the time. The IntentService is intended to run a single task and finish, being started again the next time you need it to run another task. You should use a plain Service with a Thread or HandlerThread inside it. You will have better control this way, and you will also be able to run multiple tasks in parallel if you need to.
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 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.
I'm writing a simple downloader app which has two activities:
SearchActivity: shows a list of items you can download given a query. pressing an item should start downloading the item, but stay in the SearchActivity. Pressing an item currently runs an AsyncTask to handle the downloading logic
DownloadsActivity: shows a list of currently downloading items and ProgressBars (with percent) for each item.
I've set everything up except the ProgessBars. I'm wondering what is the best way to have the ProgressBars in the DownloadsActivity update correctly. Within the download AsyncTask run within the SearchActivity, how do I update the respective progressbar in DownloadsActivity if DownloadsActivity is being viewed?
You should likely use the Service component for the downloads purpose. This would allow you to run AsyncTasks (or just separate threads) from within the Service itself. Afterwards, the status of the particular download may be retrieved by any Activity by invoking some method (written by you) on the Service object which, in fact, is managing all the downloads. Oh, and in the same way you may want to start downloads.
BTW, to retrieve Service instance object from within Activity, you need to bind to the service first and then get its instance object using the IBinder interface. Further info on Services could be found here.