My goal:
Implementing search within an application.
How it should work:
I have multiple activities which have a SearchView within their Action Bar (or Toolbar as they now call it), and a dedicated Search activity. I want to be able to input text in the SearchView, receive suggestions while i am inputting text and when i send the search to launch the dedicated activity and do a proper listing of the results.
What i have done so far:
I have gone with the SearchView with ContentAdapter method as suggested here. I have managed to have the SearchView in every activity, when i press go on the keyboard i am taken to the dedicated Search activity and the query is displayed (going to implement the effective search later). So far so good.
The problem:
I have attempted to create a custom ContentProvider to provide some mock-up suggestions but i am unable to make it work. I define within it a custom String[], and then in the query method match my search with the elements in said string. The cursor is registered, and the query method fires when i am writing text but no results are displayed in the non-dedicated activities. In the dedicated Search activity i am shown an empty list-view and receive an "error changing cursor and caching columns" IllegalStateException
I am having trouble finding any information as everyone seems to use the ContentProvider with a local database. I however intend in the future to receive my information from a REST API in the query method and return the cursor using the received values (as in this example)
I would greatly appreciate any advice in this matter. As I am not sure what code to provide, I will provide it on request.
Fixed it...
The problem was that I was creating my MatrixCursor in onCreate.
The solution is to declare and instantiate the cursor in the query method.
Side note:
As it turns out, in the columns String[] that you pass to the MatrixCursor's constructor you need to specify the values using the SearchManager constants (ie SearchManager.SUGGEST_COLUMN_TEXT_1), otherwise the text will not be displayed within the suggestion view if you use the default view and adapter.
I hope this helps someone.
Related
My project uses the SQLiteCursorLoader library from commonsguy to load data from a database into a ListView. Among that data is a simple boolean (as so far as SQLite supports booleans... that is, a number that only ever is 0 or 1) that tells the state of a checkbox. If I change the state of a checkbox in a list and then scroll the item off the list, the list item returns to the state it has when the cursor was passed in, despite the fact that the underlying database has changed. If I change the state of a bunch of checkboxes and then activate the list's MultiChoiceMode, all the items displayed will revert back to the state they were in when the cursor was originally passed in, despite the fact that the underlying database has changed.
Is there a way to refresh the cursor? Cursor.requery() is deprecated, and I don't want to have to create a new Cursor each time a checkbox is checked, which happens a lot. I'm also unsure of how calling restartLoader() several times would work, performance-wise, especially since I use onLoadFinish() to perform some animations.
Is there a way to refresh the cursor?
Call restartLoader() to have it reload the data.
I don't want to have to create a new Cursor each time a checkbox is checked, which happens a lot
Used properly, a ListView maintains the checked state for you. You would do this via android:choiceMode="multipleChoice" and row Views that implement Checkable. The objective is to not modify the database until the user has indicated they are done messing with the checklist by one means or another (e.g., "Save" action bar item).
I'm also unsure of how calling restartLoader() several times would work, performance-wise, especially since I use onLoadFinish() to perform some animations.
Don't call it several times. Ideally, call it zero times, by not updating the database until the user is done, at which point you are probably transitioning to some other portion of your UI. Or, call it just once per requested database I/O (e.g., at the point of clicking "Save"). Or, switch from using a CursorAdapter to something else, such as an ArrayAdapter on a set of POJOs you populate from the Cursor, so that the in-memory representation is modifiable in addition to being separately persistable.
I have a question around ListActivities, put into an example for hopefully more clarity. ;)
My application has a TitleListActivity which shows the published titles of a particular author. This list might contain one or more titles depending on the author. When there is only one title in the list i want to immediately start the TitleViewActivity for the particular title rather than showing the boring list with one title. I assume pretty common thing, just havent found any explanation on it so far.
Easy approach would be to check before calling the TitleListActivity how many titles there are for this author and start the respective activity. As the TitleListActivity call can happen from different parts of the application I would like to centralize the logic which decides what Activity to call.
My question is what is the best practice to achieve this. Can this logic be added to the TitleListActivity in my example efficiently. All the history back button logic etc should work of course.
Any suggestion highly appreciated
Thanks
martin
I would probably make a Activity launcher class/controller with a static method for launching the TitleList or Title. Would be something like ActivityLauncher.lauchAuthorActivity(context, auther) and that function would decide on what activity to launch.
Better use Intent.putExtra() instead of static method or class.
You must have already been using something like a AuthorId to get respective author's Titles.
Just use 1 more attribute TitleCount
intent.putExtra("TitleCount", n);
check it in TitleListActivity, and if its 1 finish() TitleListActivity in the 1st line of onCreate and open the Title Page.
If you are getting all the data of Titles(including the Title count) in the TitleListActivity check the Array/ArrayList size which has these titles.
First some background.
In my edit item activity I have added search functionality to change of one of the item's data fields. (Its manufacturer and make). Since the user can select from quite a large amount of items, we have decided to use search with suggestions to change the manufacturer/model.
Using the normal Android search, from the edit activity I can override the onSearchRequested() method and add the current item's ID as part of the extra data. The actual updating of the data item, is done in the search activity. (I know, not the best idea, but my edit activity doesn't know what the user did in the search activity.)
This works fine for a simple search, but I can't seem to find a place to inject this context data (the item's id) for Search Suggestions.
I have read through the android docs and the closest I have come across is SUGGEST_COLUMN_INTENT_EXTRA_DATA column for the resultant row in my suggestion, but since my search content provider also doesn't have any context of what item I am editing, it doesn't seem like it will solve my problem. The Intent is still launched from the suggestion by the Android system, and I can't seem to get the required context info added to it.
Is this even possible given that search suggestions seems to be geared towards context-less global searches i.e. Android's quick search?
For completeness sake: we are targeting platforms less than Android 3.0, so the functionality of SearchView is not available.
Good news: the Intent that the suggestions launch directly is the same one that the activity sets up in the call to 'onSearchRequested()'. Any context info can be set there. Can anyone find a reference to this in the docs?
I'm doing my first app, a RSS Feed application, for learning the multiple technologies associated, like xml, parsing, connecting to the internet, getting the information, processing it, etc.
I've decided to use the newest Android elements, such as the Action Bar and Fragments. So I've done an action bar with a few options, like Refresh (which refreshes the RSS list), Preferences, About and Exit. The main issue is with the Refresh.
I'm pressing Refresh and the option creates an object which will get the XML, which should return the information for the newsList Fragment. But I can't pass the information to the fragment, but I also can't Toast the xml information to the screen, so I cannot test if I'm getting everything correctly.
My programming background is not in Java, I'm used to Web Developing (PHP) and scripting (Shell) so I guess I'm missing some basic stuff, which I apologize in advance.
Can anybody at least give me some hints, in order for me to know what to search and get back in the right path?
Thanks a lot!
So you have the class that handles the downloading/parsing of the RSS feed, but you don't know how to pass the processed feed-info back to the ListFragment right?
There're multiple ways to solve this. You could use the callback pattern for your rss-retrieving class for example. So the Activity starts off this rss-retrieving object asynchronously, and registers itself as a listener of this object. When the rss-stuff is done, the object notifies your Activity about this through the listener-interface.
In response, the Activity can get a reference for the ListFragment (using the FragmentManager) and call a method on it that refreshes the list, passing in the parsed RSS-info as a parameter.
I am still searching for the best solution howto use a layout with a menu and a toolbar and inflate or start activities in android. My question may sound confusing, but im trying to explain it in an example.
Lets say im programming an android app (surprise.. i really do)
My app can do following:
User can log in [3] or register [2]. If he logs in, a new activity starts and his dashboard will be shown. If he registers: an activity for the registrationprocess starts.
Registrationprocess: user puts in his desired username and password and presses a button to accept. His data will be formvalidated and if valid, a new activity starts where he can choose his settings. Backbutton works and data can be passed to the new activity. After the last registrationwindow data will be saved and dashboard started. Starting new Activities is fun!
Now THATS where it gets complicated. Dasboard has an 'actionbar'(top) and a 'toolbar' (bottom, like tabs). So everything should be viewed in the middle part of the viewport(from now called main view). No more activity switching :(, tho.
Currently each tabclick removes all views from the main view and adds its new view. Look great, can be animated and works like a charm. Except: its currently not dynamic.
So... i don't know how to solve it the best way. For example: i fetch data from a webservice, create a listview out of it and it's extending listactivity. This activity i can't start but this data need to be put into the main view. How can i do it the best way?
And is it efficient?
I'm practicing and it's actually my first small discussion i want to start. So... FIGHT! ;)
UPDATE:
I've seen an interesting way to start activities and get results.
Launching activity through intents
. Is it possible to insert new/ update views after activity started? I would then generate my results in a separate activity. Update the view. Return back to 'dashboard' and load the view that was just updated. Possible? Or inefficient? And how can i update a view out of another activity? There is so much i need to learn :/
UPDATE2:
A good example of an app that has done it: Google+
Too bad i don't have their sourcecode ;)
UPDATE3:
What is best?
load a new activity, disable animation and set selected toolbox tab +
disable backbutton functionality
startActionForResults, fetch results and update current view (still don't really know how that would be possible)
viewFlipper onflip changing+updating data in flipped view.
I still don't know any efficient solution. Or am i missing something essential? I've just finished my ListActivity to fetch data from my webservice. But it still runs in a separate activity. How can i implement it into my "main view" now? Ofcourse... i could set a list my custom adapter. But currently im updating and fetching data from the server when i create the listactivity.
Im afraid this could be the only answer i'll get: Embed external Intent in main Activity
UPDATE4: I'm trying something.
Based on nininho's answer (thank you!) im trying the following approach:
Start Dashboardactivity and create a ViewFlipper.
Each Toolbarclick represents a certain ViewFlipper page.
Each Page has a Listadapter implemented and shows different results (different webservice queries). (ListView, GridView, with profileimage, without profileimage)
On Toolbarclick start AsyncTask or Service and notify List in current Page that data has changed. (ofcourse IF data has changed). Switch to page that was clicked.
Implement updatefeature. On scroll to bottom of list = fetch more data and add it. Update other lists automatically after 5min. or update list on update-button click.
PROs so far: Backbutton standalone for whole activity. Page-flip-animation possible. Async updating of lists and still possible to switch to another list.
CONs: ... someone has any? What about efficiency of such an approach? Does the ViewFlipper carry all the information so the performance would go down or does the viewflipper recycle its Views (like ListView)?
UPDATE5:
If i have some time i will make everything here more read- and discussable. Don't be mad at me for reading my rubbish ;)
From what I understand you want your app to start, fetch some data from the internet and after show this data on the main screen.
I don't see the need of a second activity to fetch the data because from your explanation you want to use it only to fetch the data, so the best approach would be:
Create one Activity (your dashboard)
Start an AsyncTask or Service on the background to fetch the data.
When the fetch ends, notify the activity that it ended.
Change your dashboard to show the list (you can use a ViewSwitcher if you want some animation or just create a layout with the list invisible and then change to visible).
ps: you can use a ListView outside of a ListActivity, just create a ListAdapter to create the ListView items and add this as the adapter for the ListView.