2

このチュートリアルに基づいて Volley を介して解析された JSON データを使用してリストをフィルタリングする際に問題が発生しています。これは、リストがGoogle アプリからの Google のシステム音声アクションのアプリ内検索インテントを介してフィルタリングされている場合です。

発生した正確な問題を以下に示します。

  1. アプリは最初はまったく実行されていません (アプリが実行中またはバックグラウンドで実行されている場合、検索は完全に機能します)。

  2. adb を介してインテントを起動します。

cd C:...\android-sdk\platform-tools
adb shell am start -a "com.google.android.gms.actions.SEARCH_ACTION" --es query "[query keyword]" -n "com.testapp/.MainActivity"

  1. 正しいアプリが開きますが、リストが空です。つまり、フィルタリングされた結果はありません。

  2. その後、アプリがクラッシュします。

以下はスタックトレースです。

02-15 17:54:03.331: D/AndroidRuntime(31982): Shutting down VM
02-15 17:54:03.341: E/AndroidRuntime(31982): FATAL EXCEPTION: main
02-15 17:54:03.341: E/AndroidRuntime(31982): Process: com.test.app, PID: 31982
02-15 17:54:03.341: E/AndroidRuntime(31982): java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
02-15 17:54:03.341: E/AndroidRuntime(31982):    at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at java.util.ArrayList.get(ArrayList.java:308)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.test.app.adapter.CustomListAdapter.getView(CustomListAdapter.java:92)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.test.app$1.onResponse(MainActivity.java:152)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.test.app$1.onResponse(MainActivity.java:1)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.android.volley.toolbox.JsonRequest.deliverResponse(JsonRequest.java:65)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.os.Handler.handleCallback(Handler.java:739)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.os.Handler.dispatchMessage(Handler.java:95)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.os.Looper.loop(Looper.java:145)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at android.app.ActivityThread.main(ActivityThread.java:6843)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at java.lang.reflect.Method.invoke(Native Method)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at java.lang.reflect.Method.invoke(Method.java:372)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
02-15 17:54:03.341: E/AndroidRuntime(31982):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

私のアプリには、リストを表示する検索可能なアクティビティである MainActivity 、モデル クラス、アダプター クラス、およびリスト項目のコントローラー クラスが含まれています (既存の Android ListView チュートリアルと同様)。

以下はコードです (一部のコードは省略されています)。

主な活動

//[…]
public class MainActivity extends AppCompatActivity {
    //[…]
    private List<Item> itemList = new ArrayList<Item>();
    public static ListView listView;
    private CustomListAdapter adapter;
    private static final String GMS_SEARCH_ACTION = "com.google.android.gms.actions.SEARCH_ACTION";
    private String qq;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //[…]
        onNewIntent(getIntent());
    }
    public void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        String action = intent.getAction();
        if (action!= null && (action.equals(Intent.ACTION_SEARCH)||action.equals(GMS_SEARCH_ACTION))) {
            qq = intent.getStringExtra(SearchManager.QUERY);
            doSearch(qq);
        }
    }
    /* FIXME - Current problem: From adb command, ListView can only be filtered successfully only if app is still running in background (i.e. onPause()). ListView filtering works ok if searching within the app. If app is not running, sending the search command causes the app to open but nothing is filtered, and then crashes shortly after.*/
    private void doSearch(String qq) {
        CharSequence query = qq.toUpperCase(Locale.getDefault());
        MainActivity.this.adapter.getFilter().filter(query);
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        // […]
        MenuItem searchItem = menu.findItem(R.id.menu_search);
        SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
        searchView.setSearchableInfo(searchableInfo);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String qq) {
                doSearch(qq);
                return false;
            }
            @Override
            public boolean onQueryTextChange(String qq) {
                doSearch(qq);
                return false;
            }
        });
        return super.onCreateOptionsMenu(menu);
    }
}

アダプタ クラス

// […]
public class CustomListAdapter extends BaseAdapter {
    private Activity activity;
    private LayoutInflater inflater;
    private List<Item> items, default_items;
    private Filter myFilter;
    ImageLoader imageLoader = AppController.getInstance().getImageLoader();
    public CustomListAdapter(Activity activity, List<Item> items) {
        this.activity = activity;
        this.items = items;
        this.default_items = items;
    }
    //[…]
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
//…
    }
    public Filter getFilter() {
        if (myFilter == null) { myFilter = new MYFilter();}
        return myFilter;
    }
    private class MYFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence query) {
            FilterResults results = new FilterResults();
            // If no filter implemented, return the whole list
            if (query == null || query.length() == 0) {
                results.values = default_ items;
                results.count = default_ items.size();
            }
            else {
                List<Item> nitems = new ArrayList<Item>();
                items = default_nitems;
                for (Item t : items) {
                    // Filter logic implemented here, items are added to nitems if it meets conditions
}
                results.values = nitems;
                results.count = nitems.size();
            }
            return results;
        }
        @Override
        protected void publishResults(CharSequence query, FilterResults results) {
            if (results.count == 0){
                items = (List<Item>) results.values;
                MainActivity.emptyView.setVisibility(View.VISIBLE);
                MainActivity.listView.setVisibility(View.GONE);
            }
            else {
                items = (List< Item >) results.values;
                MainActivity.listView.setVisibility(View.VISIBLE);
                MainActivity.emptyView.setVisibility(View.GONE);
                notifyDataSetChanged();
            }
        }
    }
}

マニフェスト

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >

    <application
        android:name=".app.AppController"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" android:allowTaskReparenting="true">

        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait"
            android:exported="true"
            android:launchMode="singleTop" >

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>

            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />

            <intent-filter>
                <action android:name="com.google.android.gms.actions.SEARCH_ACTION" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
            </intent-filter>

            <meta-data
                android:name="android.app.default_searchable"
                android:value=".MainActivity" />

        </activity>
<!-- ... -->
</application>
</manifest>

この問題を解決するための支援をいただければ幸いです。

4

1 に答える 1