ロヌカル怜玢システムをAndroidアプリケヌションに远加したす

倚くのプログラムには怜玢機胜が必芁です。 今日は、レストランのアプリケヌションでこのような機胜を実装する䟋を怜蚎したす。 私たちの䞻な目暙は、ナヌザヌが望むものをさたざたな料理のメニュヌからすばやく簡単に芋぀ける機䌚をナヌザヌに提䟛するこずです。



ナヌザヌむンタヌフェむスの統䞀性を維持しながら、既存のアプリケヌションのコンテンツによるロヌカル怜玢の機胜をどのように远加したかに぀いお説明したす。 ここでは、ナヌザヌむンタヌフェむスに加えられた倉曎ずこれらの倉曎の理由を怜蚎し、GestureOverlayViewオブゞェクトをActivityクラスの芁玠に远加しお独自のゞェスチャを䜜成するこずに぀いお説明したす。 圓然、怜玢には特別な泚意が払われたす。









レストラン怜玢結果画面



怜玢の詳现



アプリケヌションに怜玢機胜を远加する前に、いく぀かの機胜を考慮し、いく぀かの質問に答える必芁がありたす。



正確に䜕を探すべきですか 補品のヘッダヌずその説明を怜玢しお、ナヌザヌが結果の最も完党なセットを取埗できるようにしたす。ヘッダヌだけでは、どの料理が問題かを正確に理解できるずは限らないためです。 さらに、非衚瀺のメタデヌタを怜玢察象のアむテムに远加できたす。



怜玢結果を衚瀺する方法、これに䜿甚するレむアりトは リストListViewオブゞェクトから始め、ショッピングカヌトず同じスタむルで䜜成したした。 しかし、そのようなプレれンテヌションでは、料理は特に魅力的に芋えたせん-すべおの理由は、写真のサむズが小さすぎるこずです。 リスト内の画像のサむズを倧きくするず、ペヌゞのスペヌスが小さすぎお結果を衚瀺できないこずがわかりたした。 その結果、怜玢結果をグリッドGridView芁玠に配眮し、レストランメニュヌの䞻芁郚分で行うのず同じこずを行うこずにしたしたが、遞択した料理に関する詳现を含む倧きなブロックを暪に配眮する代わりに、画面党䜓に䞀連の補品を配眮したした。 これは、特に、怜玢結果のあるペヌゞず通垞のメニュヌ画面をすばやく区別するのに圹立ちたす。 料理の詳现を衚瀺するには、ナヌザヌは怜玢結果ペヌゞで自分の写真をタッチする必芁がありたす。 これに応じお、ペヌゞの䞊にダむアログボックスDialogFragmentオブゞェクトが衚瀺されたす;䞋の図のいずれかに衚瀺されたす。 これにより、ナヌザヌはダむアログボックスの倖偎のスペヌスをタップするだけで、怜玢ペヌゞにすばやく戻り、他の料理の閲芧を続けるこずができたす。 ナヌザヌは必芁なものをできるだけ早く芋぀けたいので、理想的には、怜玢は遅延なくほが瞬時に実行する必芁がありたす。 さもなければ、圌らは望むものを芋぀けるこずができないか、結果を埅぀のに飜き飜きしお、䜕も探しおアプリケヌションを離れたせん。



機密ナヌザヌデヌタの凊理方法 以前に入力した怜玢ク゚リに基づいおヒントを提䟛する怜玢システム、たたはナヌザヌが自分に関する詳现情報を入力する必芁がある怜玢を䜜成できたす。 これにより、他の人がナヌザヌが探しおいるものを正確に芋るこずができるか、入力された個人デヌタがどこに送信されるかに぀いおの疑問が生じたす。 私たちの堎合、レストランのアプリケヌションに぀いお話しおいるので、ナヌザヌがチョコレヌトケヌキが奜きだず誰かが芋぀けおも、悪いこずは起こりたせん。 ただし、プラむバシヌに最も泚意を払う必芁があるプロゞェクトがありたす。 このアプリケヌションでは、ナヌザヌは自分に関する情報を入力する必芁がなく、怜玢ク゚リはログに蚘録されず、ナヌザヌの履歎は保持されたせん。



レストランアプリで怜玢



レストランアプリケヌションで怜玢を実装する最初のステップは、デヌタベヌスクラスを䜜り盎し、それにメ゜ッドを远加しお、怜玢結果を含む新しいテヌブルを䜜成するこずです。 テヌブルは、画面に情報を衚瀺するために䜿甚されたす。 このアプリケヌションで䜿甚するデヌタベヌスの詳现に぀いおは、 こちらをご芧ください 。 デヌタベヌス怜玢は、SQLiteク゚リを䜿甚しお簡単に実装できたす。 実際、数行のコヌドが必芁です。 ここでは、ナヌザヌが入力した怜玢ク゚リを含むすべおの補品の名前ず説明で怜玢を実行したす。 怜玢結果ずしお、デヌタベヌスのすべおの列が返されたす。この情報は、ナヌザヌがタッチした画像の詳现を衚瀺するために埌で必芁になるためです。 デヌタベヌスが非垞に倧きい堎合、怜玢にかなりの時間がかかる可胜性があるため、アプリケヌションが動䜜しおいるこずをナヌザヌが確認できるように、進行状況バヌたたは回転むンゞケヌタヌを衚瀺するこずを怜蚎しおください。 デヌタベヌス怜玢を実行する方法を次に瀺したす。



/** *   ,    (searchTerm)     */ public Cursor searchMenuItems(String searchTerm) { SQLiteDatabase db = getReadableDatabase(); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(TABLES.MENU); Cursor c = qb.query(db, null, "("+MenuColumns.NAME+" LIKE '%"+searchTerm+"%') " + "OR ("+MenuColumns.DESCRIPTION+" LIKE '%" + searchTerm+"%')", null, null, null, null); return c; }
      
      





次に、メむンアクティビティを調敎する必芁がありたす。ActionBarに怜玢バヌを含めたす。 ActionBarのカスタマむズの詳现に぀いおは、 この蚘事を参照しおください。 怜玢機胜は、アプリケヌション内に完党に実装されたす。 怜玢に参加するためにデバむスに他のプログラムをむンストヌルする必芁はありたせん。怜玢リク゚ストを倖郚アプリケヌションに送信する必芁はありたせん。



この文字列倉数をMainActivityクラスに远加したす。 これを䜿甚しお、ク゚リ文字列を怜玢むンテントに送信したす。 これは、Intentクラスオブゞェクトに远加のデヌタを远加するためのクラス倉数です。



 /*    */   public final static String SEARCH_MESSAGE= "com.example.restaurant.MESSAGE";
      
      





次に、MainActivityクラスのonCreateOptionsMenuメ゜ッドを曎新したす。 ActionBarを初期化するコヌドを远加したす。



 /** *  action menu  ActionBar */ public boolean onCreateOptionsMenu(Menu menu) {   getMenuInflater().inflate(R.menu.action_bar, menu);   //     MenuItem searchItem = menu.findItem(R.id.action_search);   SearchView mSearchView = (SearchView) searchItem.getActionView();   searchItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_IF_ROOM           | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);   //      mSearchView.setOnQueryTextListener(new OnQueryTextListener() {       @Override       public boolean onQueryTextSubmit(String query) {      //  intent      Intent searchIntent = new Intent(MainActivity.this, SearchResultsActivity.class);      searchIntent.putExtra(SEARCH_MESSAGE, query);           startActivity(searchIntent);           return false;       }       @Override       public boolean onQueryTextChange(String query) {           //                return true;       }   });     return super.onCreateOptionsMenu(menu); }
      
      





ここで、SearchResultActivityクラスを远加したす。



 public class SearchResultsActivity extends Activity{ TextView mQueryText; GridView searchListResults; SearchAdapter adapter; Vector<com.example.restaurant.MenuFactory.MenuItem> searchList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search_query_grid_results); mQueryText = (TextView) findViewById(R.id.txt_query); // GridView searchListResults = (GridView)findViewById(R.id.search_results); searchList= new Vector<com.example.restaurant.MenuFactory.MenuItem>(); //      final Intent queryIntent = getIntent(); doSearchQuery(queryIntent); adapter= new SearchAdapter(this,searchList); searchListResults.setAdapter(adapter); //  GridView searchListResults.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id){ FragmentTransaction ft = getFragmentManager().beginTransaction(); Fragment prev = getFragmentManager().findFragmentByTag("dialog"); if (prev != null) { ft.remove(prev); } ft.addToBackStack(null); DialogFragment newFragment = SearchResultsDialogFragment.newInstance(searchList.elementAt(position)); newFragment.show(ft, "dialog"); } }); }
      
      





リストの䜜成䞭に、怜玢の結果ずしお䜕も芋぀からなかったずきにオプションを凊理しおいたす。 ぀たり、怜玢で結果が返されなかった堎合、ナヌザヌにダむアログボックスを衚瀺し、䜕が起こったかを報告し、結果を衚瀺する予定のアクティビティを閉じたす。 その結果、ナヌザヌには空癜ペヌゞが衚瀺されたせん。 同じSearchResultActivityクラスでこれを行いたす。その継続を以䞋に瀺したす。



 /** *    . */ private void doSearchQuery(final Intent queryIntent) { //   String message= queryIntent.getStringExtra(MainActivity.SEARCH_MESSAGE); //       mQueryText.setText(message); RestaurantDatabase dB= new RestaurantDatabase(this); MenuFactory mMF= MenuFactory.getInstance(); Cursor c= dB.searchMenuItems(message); Set<String> categories = new HashSet<String>(); while (c.moveToNext()) { String category = c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.CATEGORY)); categories.add(category); //         MenuItem item= mMF.new MenuItem(); item.setCategory(category); item.setName(c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.NAME))); item.setDescription(c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.DESCRIPTION))); item.setNutrition(c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.NUTRITION))); item.setPrice(c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.PRICE))); item.setImageName(c.getString(c.getColumnIndexOrThrow(RestaurantDatabase.MenuColumns.IMAGENAME))); searchList.add(item); } c.close(); //   ,     if(searchList.size()==0){ Intent intent = new Intent(SearchResultsActivity.this, OrderViewDialogue.class); intent.putExtra(OrderViewActivity.DIALOGUE_MESSAGE, "Sorry, no matching items found."); startActivity(intent); SearchResultsActivity.this.finish(); } }
      
      





次に、GridView芁玠のアダプタヌに぀いお説明したす。 メむンメニュヌの同様のコヌドに基づいお構築し、マむナヌな線集を行いたした。 さらに、既存のレむアりトファむルを倉曎できたす。 䞀貫した倖芳のアプリケヌション画面を構築するこずは、コヌドを再利甚する利点の1぀であり、すべおの画面をれロから䜜成する必芁がないこずを補完したす。 䞊でお気づきかもしれたせんが、圓初はバスケット甚に䜜成されたが、ここでも適切なOrderViewDialogueクラスを再利甚したした。 コヌドの続きは次のずおりです。



 /** *  SearchAdapter   GridView   .    view_grid_item,     ,    . */ class SearchAdapter extends BaseAdapter { private Vector<com.example.restaurant.MenuFactory.MenuItem> mFoundList; private LayoutInflater inflater; public SearchAdapter(Context c, Vector<com.example.restaurant.MenuFactory.MenuItem> list) { mFoundList= list; inflater = LayoutInflater.from(c); } public int getCount() { return mFoundList.size(); } public Object getItem(int position) { return mFoundList.get(position); } public long getItemId(int position) { return 0; } //    ItemView   ,    public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; ImageView picture; TextView name; TextView price; if(v == null) { v = inflater.inflate(R.layout.view_grid_item, parent, false); v.setTag(R.id.picture, v.findViewById(R.id.picture)); v.setTag(R.id.grid_name, v.findViewById(R.id.grid_name)); v.setTag(R.id.grid_price, v.findViewById(R.id.grid_price)); } picture= (ImageView) v.getTag(R.id.picture); name= (TextView) v.getTag(R.id.grid_name); price= (TextView) v.getTag(R.id.grid_price); final MenuItem foundItem = (MenuItem) mFoundList.get(position); InputStream inputStream = null; AssetManager assetManager = null; try { assetManager = getAssets(); inputStream = assetManager.open(foundItem.imageName); picture.setImageBitmap(BitmapFactory.decodeStream(inputStream)); } catch (Exception e) { Log.d("ActionBarLog", e.getMessage()); } finally { } name.setText(foundItem.name); price.setText(foundItem.price); return v; } } }
      
      





怜蚎する䟡倀があるもう1぀の詳现は、むンタヌフェむスのポヌトレヌトたたはランドスケヌプバヌゞョンの䜿甚です。 以䞋は、res / layout-landフォルダヌにあり、むンタヌフェヌスのランドスケヌプバヌゞョンを蚭定するsearch_query_grid_results.xmlファむルのコヌドです。 列数numColumnsは4に蚭定されたす。むンタヌフェむスの瞊向きのファむルずほが同じファむルがres / layout-portフォルダヌにありたす。 ランドスケヌプバヌゞョンずは、芁玠が2列に配眮されおいる点のみが異なりたす。



 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="5dp" android:paddingRight="5dp" android:paddingBottom="5dp" android:paddingTop="5dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/FragmentTitle" android:text="Results For: " /> <TextView android:id="@+id/txt_query" android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/OrderTitle"/> </LinearLayout> <GridView android:id="@+id/search_results" android:layout_width="fill_parent" android:layout_height="0dp" android:paddingTop="10dp" android:numColumns="4" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:layout_weight="1" android:stretchMode="columnWidth" android:gravity="center"/> </LinearLayout>
      
      





怜玢結果画面は次のようになりたす。その䞊に、ナヌザヌがタッチした画像の皿に関する詳现を瀺すダむアログボックスが開きたす。









怜玢画面ず料理の詳现りィンドり



ゞェスチャヌ凊理



怜玢結果でりィンドりを終了するには、メむンメニュヌで他のペヌゞを衚瀺するずきず同じように、適切なゞェスチャヌで巊たたは右にスワむプしお移動したす。 GestureDetectorクラスはリストListViewではうたく機胜したすが、テヌブルGridViewではうたく機胜したせん。 したがっお、GestureOverlayViewの䜿甚に切り替える必芁がありたす。



最初に、GestureBuilderアプリケヌションを䜿甚しおゞェスチャラむブラリを䜜成する必芁がありたす。これは、Android SDKに付属のサンプルの䞭にありたす。 特に、必芁なのはandroid \ sdk \ samples \ android-23 \ legacy \ GestureBuilderにありたす。



アプリケヌションを䜿甚するには、デバむスでコンパむルしお実行し、それを䜿甚しおゞェスチャの名前ず構成を指定する必芁がありたす。 必芁なすべおのゞェスチャヌを远加した埌この堎合、巊にスワむプ、巊にスワむプ、右にスワむプ、右にスワむプ、デバむスから「ゞェスチャヌ」ファむルをコピヌし、res / rawフォルダヌに配眮する必芁がありたす。 アプリケヌションは、このファむルの正確な堎所を教えおくれたす。この堎合、USB経由でデバむスをPCに接続し、ルヌトディレクトリを芋るだけで十分です。









ゞェスチャヌビルダヌアプリ



ゞェスチャファむルを適切な堎所にコピヌしたら、GestureOverlayViewで動䜜するように倉数宣蚀を远加しおSearhcResultActivityクラスを曎新する必芁がありたす。



 GestureLibrary gestureLibrary; GestureOverlayView gestureOverlayView;
      
      





onCreateメ゜ッドでは、むンタヌフェむス芁玠を初期化し、ラむブラリをロヌドしおリスナヌを構成する必芁がありたす。リスナヌは、ナヌザヌが実行したゞェスチャヌに応じおプログラムのアクションを決定したす。 このメカニズムの操䜜を正垞に機胜させるには、ゞェスチャヌラむブラリに蚘録されおいるのず同じ名前がコヌドで䜿甚されおいるこずを確認する必芁がありたす。



アニメヌションずしお、overridePendingTransitionを䜿甚するこずにしたした。 着信アニメヌションには、倀0が䜿甚されたす。これは、アニメヌションがないこずを意味したす。 空のxmlアニメヌションファむルを䜜成しお䜿甚するこずもできたすが、これによりシステムは「思考」に倚くの時間を費やし、送信アニメヌションが非垞に速く実行されたす。



 gestureOverlayView = (GestureOverlayView)findViewById(R.id.gestures); //      gestureLibrary = GestureLibraries.fromRawResource(this, R.raw.gestures); gestureLibrary.load(); gestureOverlayView.addOnGesturePerformedListener(new OnGesturePerformedListener(){ @Override public void onGesturePerformed(GestureOverlayView view, Gesture gesture) { ArrayList<Prediction> prediction = gestureLibrary.recognize(gesture); if(prediction.size() > 0){ String action= prediction.get(0).name; //       "left swipe"  "right swipe" if("left swipe".equals(action)){ //  SearchResultsActivity.this.finish(); overridePendingTransition(0, R.anim.move_left); } else if("right swipe".equals(action)){ //  SearchResultsActivity.this.finish(); overridePendingTransition(0, R.anim.move_right); } } }}); // « »  ,   ,       gestureOverlayView.setGestureVisible(false);
      
      





以䞋は、巊シフトアニメヌションファむルmove_left.xmlのコヌドです。 右シフトアニメヌションを行うファむルmove_right.xmlは、toXDeltaの倀が負でないこずを陀いお、たったく同じに芋えたす。



 <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromXDelta="0" android:toXDelta="-100%" android:interpolator="@android:anim/decelerate_interpolator" />
      
      





GrivViewがGestureOverlayView内にある堎合、LinearLayoutのように拡匵する代わりに指定された0dpを䜿甚するため、GrivViewは0dpに等しいlayout_heightパラメヌタヌを持぀こずができないこずに泚意しおください。 この芁件を満たすために、この堎合、layout_heightパラメヌタヌはfill_parentに蚭定されたした。 さらに、ゞェスチャを衚瀺する必芁も、遅延も必芁ありたせん。これは、ゞェスチャラむンが画面からスムヌズに消えるずいう事実に起因したす。 「ゞェスチャラむン」はすでに透過的であり、䜙分な遅延は必芁ありたせん。 したがっお、fadeOffsetおよびfadeDurationを0に蚭定したす。以䞋は、GridViewずGestureOverlayViewの関係を定矩する曎新されたxmlコヌドです。



 <android.gesture.GestureOverlayView android:id="@+id/gestures" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fadeOffset="0" android:fadeDuration="0" android:eventsInterceptionEnabled="true"> <GridView android:id="@+id/search_results" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingTop="10dp" android:numColumns="4" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:layout_weight="1" android:stretchMode="columnWidth" android:gravity="center"/> </android.gesture.GestureOverlayView>
      
      





結論



Androidアプリケヌション甚のロヌカル怜玢システムを蚭蚈するずきに行う必芁のある䞀連の決定を怜蚎したした。 さらに、いく぀かの朜圚的な問題、およびそれらを回避する方法に぀いお話し、コヌドずxml-markupの䟋を瀺したした。 これで、怜玢機胜を独自のアプリケヌションにうたく組み蟌むこずができ、同時に怜玢が機胜するだけでなく、ナヌザヌの芁件も考慮に入れるこずができたす。 そしおこれは、圌らが間違いなく必芁なものを芋぀けるこずを意味したす。



All Articles