How do I get a Uri to an image in my Assets that will work for the SearchManager.SUGGEST_COLUMN_ICON_1 column?

ぃ、小莉子 提交于 2019-12-18 04:55:10

问题


I have successfully integrated my app's country search into the global search facility and now I am trying to display each country's flag next to the search suggestions. Search inside my app works this way but of course I have control of the list and its view binding myself. So I know the flags are all there and I can use them in the rest of my app.

The trouble comes when I try to supply a Uri to a .gif file in my Assets. According to the search documentation the value of the column with the key SearchManager.SUGGEST_COLUMN_ICON_1 should be a Uri to the image.

Below is what the code looks like. In response to the ContentProvider method public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) I am creating a MatrixCursor that maps columns from my country database to those required by the search facility. The country names show up fine and I can select them and correctly respond in my application.

I have tried forming the Uri three different ways:

//                    String flagUri = "file:///android_asset/" + flagPath;
//                    String flagUri = "file:///assets/" + flagPath;
                    String flagUri = "android.resource://com.lesliesoftware.worldinfo.WorldInfoActivity/assets/" + flagPath;
                    columnValues.add (flagUri);

They all lead to the same thing - my application icon next to each suggestion which I can get by using a value of empty string.

Is there a Uri that will work? How can I get the country flag icon next to the search suggestions?

Thanks Ian

The full source:

private Cursor search (String query, int limit)  {
    query = query.toLowerCase ();
    String[] requestedColumns = new String[]  {
            BaseColumns._ID, 
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_ICON_1,
    };
    String[] queryColumns = new String[]  {
            WorldInfoDatabaseAdapter.KEY_ROWID, 
            WorldInfoDatabaseAdapter.KEY_COUNTRYNAME,
            WorldInfoDatabaseAdapter.KEY_COUNTRYCODE
    };

    return packageResults (query, requestedColumns, queryColumns, limit);
}


private Cursor packageResults (String query, String[] requestedColumns, String[] queryMappedColumns, int limit)  {
    if (requestedColumns.length != queryMappedColumns.length)
        throw new IllegalArgumentException ("Internal error: requested columns do not map to query columns");

    MatrixCursor results = new MatrixCursor (requestedColumns);

    //  Query the country list returns columns: KEY_ROWID, KEY_COUNTRYNAME, KEY_COUNTRYCODE
    Cursor dbResults = myDbHelper.getCountryList (query);

    //  Verify that the query columns are available
    for (int index = 0; index < queryMappedColumns.length; index++)  {
        int col = dbResults.getColumnIndex (queryMappedColumns[index]);
        if (col == -1)
            throw new IllegalArgumentException ("Internal error: requested column '" + 
                    queryMappedColumns[index] + "' was not returned from the database.");
    }

    //  Loop over the database results building up the requested results
    int rowCount = 0;
    while (dbResults.moveToNext ()  &&  rowCount < limit)  {
        Vector<String> columnValues = new Vector<String> ();
        for (int index = 0; index < requestedColumns.length; index++)  {
            if (requestedColumns[index].compareTo (SearchManager.SUGGEST_COLUMN_ICON_1) == 0)  {
                String flagPath = "flags/small/" + dbResults.getString (
                        dbResults.getColumnIndexOrThrow (queryMappedColumns[index]))
                        + "-flag.gif";
//                    String flagUri = "file:///android_asset/" + flagPath;
//                    String flagUri = "file:///assets/" + flagPath;
                String flagUri = "android.resource://com.lesliesoftware.worldinfo.WorldInfoActivity/assets/" + flagPath;
                columnValues.add (flagUri);
            }  else  {
                //  Add the mapped query column values from the database
                String colValue = dbResults.getString (dbResults.getColumnIndexOrThrow (queryMappedColumns[index]));
                columnValues.add (colValue);
            }
        }

        results.addRow (columnValues);
        rowCount++;
    }

    return results;
}

EDIT: I have tried other variations including moving the images from the assets to the raw folder. Nothing worked. Here are the uri's I tried:

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/raw/flags/small/" + 
    countryCode + "-flag.gif";

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/assets/flags/small/" + 
    countryCode + "-flag.gif";

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/assets/flags/small/" + 
    countryCode + "-flag";

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/raw/" + 
    countryCode + "-flag.gif";

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/raw/" + 
    countryCode + "-flag";

The only uri that did work was if I moved a test flag into my drawable folder:

flagUriStr = "android.resource://com.lesliesoftware.worldinfo/" + 
    R.drawable.small_ca_flag;

回答1:


Sadly after much searching around I have reached the conclusion that you cannot return a uri to an image asset to the search facility. What I did instead was move my flag images to the resources (so they do not clutter up my app's resources I created a library for the flag images) and use resource uri's. So, in my provider I have code that looks like this in the loop that maps database results to search results:

            if (requestedColumns[index].compareTo (SearchManager.SUGGEST_COLUMN_ICON_1) == 0)  {
                //  Translate the country code into a flag icon uri
                String countryCode = dbResults.getString (
                        dbResults.getColumnIndexOrThrow (queryMappedColumns[index]));

                int flagImageID = FlagLookup.smallFlagResourceID (countryCode);
                String flagUriStr = "android.resource://com.lesliesoftware.worldinfo/" + flagImageID;
                columnValues.add (flagUriStr);
            }  

and look up code that looks like this:

static public int smallFlagResourceID (String countryCode)  {
    if (countryCode == null || countryCode.length () == 0)
        return R.drawable.flag_small_none;

    if (countryCode.equalsIgnoreCase ("aa"))
        return R.drawable.flag_small_aa;
    else if (countryCode.equalsIgnoreCase ("ac"))
        return R.drawable.flag_small_ac;
    else if (countryCode.equalsIgnoreCase ("ae"))
        return R.drawable.flag_small_ae;
    ...

I will just have to make sure I create a test that verifies that all countries that have flags returns the expected results.




回答2:


You first create an AssetProvider. We will later create uris that will be handled by this class.

public class AssetsProvider extends ContentProvider {

    private AssetManager assetManager;
    public static final Uri CONTENT_URI = 
            Uri.parse("content://com.example.assets");

    @Override
    public int delete(Uri arg0, String arg1, String[] arg2) { return 0; }

    @Override
    public String getType(Uri uri) { return null; }

    @Override
    public Uri insert(Uri uri, ContentValues values) { return null; }

    @Override
    public boolean onCreate() {
        assetManager = getContext().getAssets();
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { return 0; }

    @Override
    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
        String path = uri.getPath().substring(1);
        try {
            AssetFileDescriptor afd = assetManager.openFd(path);
            return afd;
        } catch (IOException e) {
            throw new FileNotFoundException("No asset found: " + uri, e);
        }
    }
}

Lot's of boilerplate in there. The essential method is of course the openAssetFile that justs translates the path of the uri passed to it into a AssetFileDescriptor. In order for Android to be able to pass URIs to this provider, remember to include this in your AndroidManifest.xml file inside the application-tag:

    <provider
        android:name=".AssetsProvider"
        android:authorities="com.example.assets" />

Now, in your search provider you can create an URI like this:

content://com.example.assets/my_folder_inside_assets/myfile.png



回答3:


I was able to refer images from drawable in SearchRecentSuggestionsProvider using following uri,

"android.resource://your.package.here/drawable/image_name



回答4:


Just wanted to add to vidstige's answer: I wanted to serve files that I had downloaded to my temporary cache directory earlier, so I can serve external image thumbnails to the SearchView suggestions from URLs in my search ContentProvider. I used this function instead:

@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
        String filename = uri.getLastPathSegment();

        try {
            File file = new File(getContext().getCacheDir(), filename);

            // image downloading has to be done in the search results provider, since it's not on the UI thread like this guy.
            //downloadAndSaveFile("http://urdomain/urfile.png", filename);

            AssetFileDescriptor afd = new AssetFileDescriptor(
                        ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY | ParcelFileDescriptor.MODE_WORLD_READABLE),
                    0, AssetFileDescriptor.UNKNOWN_LENGTH);

            return afd;
        } catch (IOException e) {
            throw new FileNotFoundException("No asset found: " + uri);
        }
    }


来源:https://stackoverflow.com/questions/4615509/how-do-i-get-a-uri-to-an-image-in-my-assets-that-will-work-for-the-searchmanager

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