建议适配器空指针异常当我在搜索视图中写作时



当我在搜索编辑文本上写作时,为了显示建议,我的应用程序会显示一个 FC。之前工作顺利。

我已经委托了映射控制器类中的函数。在我的活动中有以下方法:

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);
}

在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
}

在清单中:

    <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>

我的内容提供商:

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;
    }   
}

我的行布局:

<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>

我的可搜索 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"/>

我的日志猫:

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)

终于我发现了问题。搜索视图依赖于"按钮重力"工具栏的属性。在 Android 支持库 v21.0.2 中,此属性已删除。几天前,我更改了 android 库的版本,它显示此属性冲突,然后我删除了它。但我从没想过这会与SearchView有关。

我恢复了以前版本的 appcompat-v7 (21.0.0) 并正常工作。此外,我还必须从依赖项树中排除 appcompat-v7。

如果我找到更新的解决方案,我将更新此答案。

最新更新