Reputation: 1233
When I'm writing on search edittext, at moment to show suggestions my app show a FC. Before worked smoothly.
I have delegated the functions in the map's controller class. In my Activity have the next methods:
private void handleIntent(Intent intent) {
if (intent.getAction() == null) {
return;
}
if (intent.getAction().equals(Intent.ACTION_SEARCH)) {
((DayRentController) mapFragment.getMapController()).doSearch(intent.getStringExtra(SearchManager.QUERY));
} else if (intent.getAction().equals(Intent.ACTION_VIEW)) {
((DayRentController) mapFragment.getMapController()).getPlace(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleIntent(intent);
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return ((DayRentController) mapFragment.getMapController()).onCreateLoader(i, bundle);
}
@Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
((DayRentController) mapFragment.getMapController()).onLoadFinished(cursorLoader, cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
((DayRentController) mapFragment.getMapController()).onLoaderReset(cursorLoader);
}
in DayRentController:
@Override
public android.support.v4.content.Loader onCreateLoader(int id, Bundle bundle) {
CursorLoader cLoader = null;
if (id == 0)
cLoader = new CursorLoader(getActivity().getBaseContext(), PlaceProvider.SEARCH_URI, null, null, new String[]{bundle.getString("query")}, null);
else if (id == 1)
cLoader = new CursorLoader(getActivity().getBaseContext(), PlaceProvider.DETAILS_URI, null, null, new String[]{bundle.getString("query")}, null);
return cLoader;
}
@Override
public void onLoadFinished(android.support.v4.content.Loader loader, Cursor o) {
showLocations(o);
}
@Override
public void onLoaderReset(android.support.v4.content.Loader loader) {
}
public void doSearch(String query) {
Bundle data = new Bundle();
data.putString("query", query);
getActivity().getSupportLoaderManager().restartLoader(0, data, this);
}
public void getPlace(String query) {
Bundle data = new Bundle();
data.putString("query", query);
getActivity().getSupportLoaderManager().restartLoader(1, data, this);
}
private void showLocations(Cursor c) {
//Add markers to map
}
In Manifest:
<activity
android:name=".BuscapakingActivity"
android:configChanges="screenLayout|screenSize|orientation"
android:label="@string/title_activity_buscapaking"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<!-- Points to searchable activity -->
<meta-data
android:name="android.app.default_searchable"
android:value=".MainActivity" />
<!-- Points to searchable meta data -->
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
My Content provider:
package com.buscaparking.client.utils.geocoding;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
public class PlaceProvider extends ContentProvider {
public static final String AUTHORITY = "com.buscaparking.client.PlaceProvider";
public static final Uri SEARCH_URI = Uri.parse("content://"+AUTHORITY+"/search");
public static final Uri DETAILS_URI = Uri.parse("content://"+AUTHORITY+"/details");
private static final int SEARCH = 1;
private static final int SUGGESTIONS = 2;
private static final int DETAILS = 3;
// Obtain browser key from https://code.google.com/apis/console
String mKey = "key="+Constants.MYKEY;
// Defines a set of uris allowed with this content provider
private static final UriMatcher mUriMatcher = buildUriMatcher();
private static UriMatcher buildUriMatcher() {
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// URI for "Go" button
uriMatcher.addURI(AUTHORITY, "search", SEARCH );
// URI for suggestions in Search Dialog
uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,SUGGESTIONS);
// URI for Details
uriMatcher.addURI(AUTHORITY, "details",DETAILS);
return uriMatcher;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
Cursor c = null;
PlaceJSONParser parser = new PlaceJSONParser();
PlaceDetailsJSONParser detailsParser = new PlaceDetailsJSONParser();
String jsonString = "";
String jsonPlaceDetails = "";
List<HashMap<String, String>> list = null;
List<HashMap<String, String>> detailsList = null;
MatrixCursor mCursor = null;
switch(mUriMatcher.match(uri)){
case SEARCH:
// Defining a cursor object with columns description, lat and lng
mCursor = new MatrixCursor(new String[] { "description","lat","lng" });
// Create a parser object to parse places in JSON format
parser = new PlaceJSONParser();
// Create a parser object to parse place details in JSON format
detailsParser = new PlaceDetailsJSONParser();
// Get Places from Google Places API
jsonString = getPlaces(selectionArgs);
try {
// Parse the places ( JSON => List )
list = parser.parse(new JSONObject(jsonString));
// Finding latitude and longitude for each places using Google Places Details API
for(int i=0;i<list.size();i++){
HashMap<String, String> hMap = (HashMap<String, String>) list.get(i);
detailsParser =new PlaceDetailsJSONParser();
// Get Place details
jsonPlaceDetails = getPlaceDetails(hMap.get("reference"));
// Parse the details ( JSON => List )
detailsList = detailsParser.parse(new JSONObject(jsonPlaceDetails));
// Creating cursor object with places
for(int j=0;j<detailsList.size();j++){
HashMap<String, String> hMapDetails = detailsList.get(j);
// Adding place details to cursor
mCursor.addRow(new String[]{ hMap.get("description") , hMapDetails.get("lat") , hMapDetails.get("lng") });
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c = mCursor;
break;
case SUGGESTIONS :
// Defining a cursor object with columns id, SUGGEST_COLUMN_TEXT_1, SUGGEST_COLUMN_INTENT_EXTRA_DATA
mCursor = new MatrixCursor(new String[] { "_id", SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA } );
// Creating a parser object to parse places in JSON format
parser = new PlaceJSONParser();
// Get Places from Google Places API
jsonString = getPlaces(selectionArgs);
try {
// Parse the places ( JSON => List )
list = parser.parse(new JSONObject(jsonString));
// Creating cursor object with places
for(int i=0;i<list.size();i++){
HashMap<String, String> hMap = (HashMap<String, String>) list.get(i);
// Adding place details to cursor
mCursor.addRow(new String[] { Integer.toString(i), hMap.get("description"), hMap.get("reference") });
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c = mCursor;
break;
case DETAILS :
// Defining a cursor object with columns description, lat and lng
mCursor = new MatrixCursor(new String[] { "description","lat","lng" });
detailsParser = new PlaceDetailsJSONParser();
jsonPlaceDetails = getPlaceDetails(selectionArgs[0]);
try {
detailsList = detailsParser.parse(new JSONObject(jsonPlaceDetails));
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int j=0;j<detailsList.size();j++){
HashMap<String, String> hMapDetails = detailsList.get(j);
mCursor.addRow(new String[]{ hMapDetails.get("formatted_address") , hMapDetails.get("lat") , hMapDetails.get("lng") });
}
c = mCursor;
break;
}
return c;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
return false;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
/** A method to download json data from url */
private String downloadUrl(String strUrl) throws IOException{
String data = "";
InputStream iStream = null;
HttpURLConnection urlConnection = null;
try{
URL url = new URL(strUrl);
// Creating an http connection to communicate with url
urlConnection = (HttpURLConnection) url.openConnection();
// Connecting to url
urlConnection.connect();
// Reading data from url
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
StringBuffer sb = new StringBuffer();
String line = "";
while( ( line = br.readLine()) != null){
sb.append(line);
}
data = sb.toString();
br.close();
}catch(Exception e){
Log.d("Exception while downloading url", e.toString());
}finally{
iStream.close();
urlConnection.disconnect();
}
return data;
}
private String getPlaceDetailsUrl(String ref){
// reference of place
String reference = "reference="+ref;
// Sensor enabled
String sensor = "sensor=false";
// Building the parameters to the web service
String parameters = reference+"&"+sensor+"&"+mKey;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/place/details/"+output+"?"+parameters;
return url;
}
private String getPlacesUrl(String qry){
try {
qry = "input=" + URLEncoder.encode(qry, "utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
// Sensor enabled
String sensor = "sensor=false";
// place type to be searched
String types = "types=geocode";
// Building the parameters to the web service
String parameters = qry+"&"+types+"&"+sensor+"&"+mKey;
// Output format
String output = "json";
// Building the url to the web service
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/"+output+"?"+parameters;
return url;
}
private String getPlaces(String[] params){
// For storing data from web service
String data = "";
String url = getPlacesUrl(params[0]);
try{
// Fetching the data from web service in background
data = downloadUrl(url);
}catch(Exception e){
Log.d("Background Task",e.toString());
}
return data;
}
private String getPlaceDetails(String reference){
String data = "";
String url = getPlaceDetailsUrl(reference);
try {
data = downloadUrl(url);
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
My Row Layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingLeft="@dimen/abc_dropdownitem_text_padding_left"
android:paddingRight="4dip"
android:layout_width="match_parent"
android:layout_height="48dp" >
<TextView android:id="@android:id/text1"
style="?android:attr/dropDownItemStyle"
android:textAppearance="?attr/textAppearanceSearchResultTitle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@android:id/icon1"
android:layout_toLeftOf="@android:id/icon2"
android:layout_above="@android:id/text2"
android:textColor="#fff"
android:background="@color/theme_default_primary_dark"/>
</RelativeLayout>
My Searchable XML:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:hint="Buscar"
android:searchSettingsDescription="Buscar Lugar"
android:searchSuggestAuthority="com.buscaparking.client.PlaceProvider"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSuggestSelection=" ?"
android:searchSuggestThreshold="2"/>
My logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference
at android.support.v7.widget.SuggestionsAdapter.newView(SuggestionsAdapter.java:249)
at android.support.v7.widget.SuggestionsAdapter.getView(SuggestionsAdapter.java:453)
at android.widget.AbsListView.obtainView(AbsListView.java:2346)
at android.widget.ListPopupWindow$DropDownListView.obtainView(ListPopupWindow.java:1684)
at android.widget.ListView.measureHeightOfChildren(ListView.java:1270)
at android.widget.ListPopupWindow.buildDropDown(ListPopupWindow.java:1181)
at android.widget.ListPopupWindow.show(ListPopupWindow.java:568)
at android.widget.AutoCompleteTextView.showDropDown(AutoCompleteTextView.java:1099)
at android.widget.AutoCompleteTextView.updateDropDownForFilter(AutoCompleteTextView.java:974)
at android.widget.AutoCompleteTextView.onFilterComplete(AutoCompleteTextView.java:956)
at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:285)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5255)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:898)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:693)
Upvotes: 1
Views: 810
Reputation: 1233
Finally I found the problem. SearchView depend of 'buttonGravity' Toolbar's attribute. In Android Support Library v21.0.2, this attribute was deleted. Some days ago, I changed the versions of android libraries and it showed this attribute as conflicting, then I remove this. But I never thought this would be related to SearchView.
I restored previous version of appcompat-v7 (21.0.0) and works. Also I had to exclude appcompat-v7 from the dependencies tree.
If I found an updated solution, I will update this answer.
Upvotes: 1