カスタム検索ボックスの候補を表示しようとしていますが、表示される結果が空です。この機能を実装するために、いくつかのガイドに従いました。
- コンテンツ プロバイダーの場合: http://www.androidcompetencycenter.com/2009/01/basics-of-android-part-iv-android-content-providers/
- ABS で動作させるには: https://github.com/JakeWharton/ActionBarSherlock/pull/653/files
これにより、次のコードが生成されました。
検索ボックスの追加:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.building_search, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = new SearchView(getSupportActionBar().getThemedContext());
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setSuggestionsAdapter(new BuildingSuggestionsAdapter(this, searchManager.getSearchableInfo(getComponentName()), searchView));
return super.onCreateOptionsMenu(menu);
}
建物をデータベースに追加する:
for (Resto resto : restos) {
ContentValues values = new ContentValues();
values.put(TableBuildings.Buildings.NAME, resto.name);
values.put(TableBuildings.Buildings.DISTANCE, "3");
getContentResolver().insert(TableBuildings.Buildings.CONTENT_URI, values);
}
BuildingSuggestionAdapter:
public class BuildingSuggestionsAdapter extends CursorAdapter {
private static final int QUERY_LIMIT = 50;
private LayoutInflater inflater;
private SearchView searchView;
private SearchableInfo searchable;
public BuildingSuggestionsAdapter(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(TableBuildings.Buildings.NAME));
TextView namet = (TextView) v.findViewById(R.id.resto_search_name);
namet.setText(name);
String man = c.getString(c.getColumnIndex(TableBuildings.Buildings.DISTANCE));
TextView manuf = (TextView) v.findViewById(R.id.resto_search_distance);
manuf.setText(man);
Toast.makeText(context, name + " " + man, Toast.LENGTH_LONG).show();
}
@Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
return this.inflater.inflate(R.layout.resto_search_suggestion_view, 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);
}
}
プロバイダー:
public class BuildingSuggestionProvider extends ContentProvider {
private SQLiteDatabase sqlDB;
private DatabaseHelper dbHelper;
private static final String DATABASE_NAME = "Buildings.db";
private static final int DATABASE_VERSION = 1;
private static final String TABLE_NAME = "Buildings";
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//create table to store user names
db.execSQL("Create table " + TABLE_NAME + "( _id INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, DISTANCE TEXT);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
@Override
public int delete(Uri uri, String s, String[] as) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues contentvalues) {
// get database to insert records
sqlDB = dbHelper.getWritableDatabase();
// insert record in user table and get the row number of recently inserted record
long rowId = sqlDB.insert(TABLE_NAME, "", contentvalues);
if (rowId > 0) {
Uri rowUri = ContentUris.appendId(TableBuildings.Buildings.CONTENT_URI.buildUpon(), rowId).build();
getContext().getContentResolver().notifyChange(rowUri, null);
return rowUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
@Override
public boolean onCreate() {
dbHelper = new DatabaseHelper(getContext());
return (dbHelper == null) ? false : true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
SQLiteDatabase db = dbHelper.getReadableDatabase();
qb.setTables(TABLE_NAME);
Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
return 0;
}
}
テーブルビルディング:
import android.net.Uri;
import android.provider.BaseColumns;
public class TableBuildings {
public static final String AUTHORITY = "be.ugent.zeus.hydra.ui.map.suggestions.BuildingSuggestionProvider";
// BaseColumn contains _id.
public static final class Buildings implements BaseColumns {
public static final Uri CONTENT_URI = Uri.parse("content://be.ugent.zeus.hydra.ui.map.suggestions.BuildingSuggestionProvider");
// Table column
public static final String NAME = "NAME";
public static final String DISTANCE = "DISTANCE";
}
}
最後に、検索ボックスを定義するために使用される XML と、アプリケーションのプロバイダーに使用される xml が続きます。
<?xml version="1.0" encoding="UTF-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/resto_search_label"
android:hint="@string/resto_search_hint"
android:searchSuggestAuthority="be.ugent.zeus.hydra.ui.map.suggestions.BuildingSuggestionProvider" />
<provider
android:name=".ui.map.suggestions.BuildingSuggestionProvider"
android:authorities="be.ugent.zeus.hydra.ui.map.suggestions.BuildingSuggestionProvider" />
私が得た結果は次のとおりです。エラーはありません。検索ビューを開き、コンテンツ プロバイダーにクエリを実行します。奇妙な部分は、プロバイダーのクエリ メソッドが呼び出されることですが、アダプターからは呼び出されません。たとえば、ブレークポイントを配置しても、プログラムが停止しません。視覚的には、キーボードがポップアップしてリストが表示されますが、リストには空のアイテムしか含まれていません...
誰にもアイデアはありますか?
前もって感謝します。