Does ActionBarSherlock 4.2 support search suggestions for a SearchView?

我的未来我决定 提交于 2019-12-03 08:17:50

It doesn't. But I have found a way to make it query your ContentProvider. I looked into the source of SuggestionsAdapter from API 17 where the query executes and got an idea of replacing this method. Also I found that ActionbarSherlock's SuggestionsAdapter does not use your SearchableInfo.

Edit com.actionbarsherlock.widget.SuggestionsAdapter in your ActionBarSherlock project:

Add a line

private SearchableInfo searchable;

in constructor, add

this.searchable = mSearchable;

Replace getSuggestions method with this one:

public Cursor getSuggestions(String query, int limit) {

    if (searchable == null) {
        return null;
    }

    String authority = searchable.getSuggestAuthority();
    if (authority == null) {
        return null;
    }

    Uri.Builder uriBuilder = new Uri.Builder()
            .scheme(ContentResolver.SCHEME_CONTENT)
            .authority(authority)
            .query("")  // TODO: Remove, workaround for a bug in Uri.writeToParcel()
            .fragment("");  // TODO: Remove, workaround for a bug in Uri.writeToParcel()

    // if content path provided, insert it now
    final String contentPath = searchable.getSuggestPath();
    if (contentPath != null) {
        uriBuilder.appendEncodedPath(contentPath);
    }

    // append standard suggestion query path
    uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);

    // get the query selection, may be null
    String selection = searchable.getSuggestSelection();
    // inject query, either as selection args or inline
    String[] selArgs = null;
    if (selection != null) {    // use selection if provided
        selArgs = new String[] { query };
    } else {                    // no selection, use REST pattern
        uriBuilder.appendPath(query);
    }

    if (limit > 0) {
        uriBuilder.appendQueryParameter("limit", String.valueOf(limit));
    }

    Uri uri = uriBuilder.build();

    // finally, make the query
    return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
}

Now it queries my ContentProvider but crashes with default adapter saying that no layout_height loading some xml file from support library. So you have to use custom SuggestionsAdapter. This is what worked for me:

import com.actionbarsherlock.widget.SearchView;

import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public final class DrugsSearchAdapter extends CursorAdapter
{
    private static final int QUERY_LIMIT = 50;

    private LayoutInflater inflater;
    private SearchView searchView;
    private SearchableInfo searchable;

    public DrugsSearchAdapter(Context context, SearchableInfo info, SearchView searchView)
    {
        super(context, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        this.searchable = info;
        this.searchView = searchView;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public void bindView(View v, Context context, Cursor c)
    {
        String name = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1));
        TextView namet = (TextView) v.findViewById(R.id.list_item_drug_name);
        namet.setText(name);

        String man = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2));
        TextView manuf = (TextView) v.findViewById(R.id.list_item_drug_manufacturer);
        manuf.setText(man);
    }

    @Override
    public View newView(Context arg0, Cursor arg1, ViewGroup arg2)
    {
        return this.inflater.inflate(R.layout.list_item_drug_search, null);
    }

    /**
     * Use the search suggestions provider to obtain a live cursor.  This will be called
     * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
     * The results will be processed in the UI thread and changeCursor() will be called.
     */
    @Override
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
        String query = (constraint == null) ? "" : constraint.toString();
        /**
         * for in app search we show the progress spinner until the cursor is returned with
         * the results.
         */
        Cursor cursor = null;
        if (searchView.getVisibility() != View.VISIBLE
                || searchView.getWindowVisibility() != View.VISIBLE) {
            return null;
        }
        try {
            cursor = getSuggestions(searchable, query, QUERY_LIMIT);
            // trigger fill window so the spinner stays up until the results are copied over and
            // closer to being ready
            if (cursor != null) {
                cursor.getCount();
                return cursor;
            }
        } catch (RuntimeException e) {
        }
        // If cursor is null or an exception was thrown, stop the spinner and return null.
        // changeCursor doesn't get called if cursor is null
        return null;
    }

    public Cursor getSuggestions(SearchableInfo searchable, String query, int limit) {

        if (searchable == null) {
            return null;
        }

        String authority = searchable.getSuggestAuthority();
        if (authority == null) {
            return null;
        }

        Uri.Builder uriBuilder = new Uri.Builder()
                .scheme(ContentResolver.SCHEME_CONTENT)
                .authority(authority)
                .query("") 
                .fragment(""); 

        // if content path provided, insert it now
        final String contentPath = searchable.getSuggestPath();
        if (contentPath != null) {
            uriBuilder.appendEncodedPath(contentPath);
        }

        // append standard suggestion query path
        uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);

        // get the query selection, may be null
        String selection = searchable.getSuggestSelection();
        // inject query, either as selection args or inline
        String[] selArgs = null;
        if (selection != null) {    // use selection if provided
            selArgs = new String[] { query };
        } else {                    // no selection, use REST pattern
            uriBuilder.appendPath(query);
        }

        if (limit > 0) {
            uriBuilder.appendQueryParameter("limit", String.valueOf(limit));
        }

        Uri uri = uriBuilder.build();

        // finally, make the query
        return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
    }

}

And set this adapter in SearchView

searchView.setSuggestionsAdapter(new DrugsSearchAdapter(this, searchManager.getSearchableInfo(getComponentName()), searchView));

I'm the one that opened the github issue for this. It is working on the dev branch. The current version (4.2) doesn't have the fix. It was completely fixed by this commit, but I would suggest just checking out the dev branch and trying it.

I don't know if I'm wrong here or I changed something on accident, but the above answer does not work and the ActionBarSherlock SuggestionsAdapter does not work. All I get are null pointers in runQueryOnBackgroundThread. It never goes into bindView etc. either, yet it manages to display suggestion results. I think android.app.SearchManager is somehow overriding ABS with getSuggestions() but I'm not sure. I'm still trying things out...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!