Androidを使ったリコール情報検索アプリを作ってみよう
本チュートリアルの内容
■ 開発環境の確認
前提とする開発環境
このチュートリアルでは、以下の環境を想定します。Androidの開発はAndroidStudioで行います。AndroidStudioのインストールはすんでいるものとします。
- 開発PC:Windows7 Professional、MySQL5.5.39、MySQL Connector/J 5.1.47
- 開発環境:AndroidStudio 3.1.4
前提知識
以下のチュートリアルで、MySQLを使ったDBの作成方法について復習しておきましょう。
■ 開発するアプリの概要
今回開発するアプリの概要は以下のような企業活動や行政による情報提供が行われていることを前提としています。
企業は社会的責任を果たすために、不具合のある製品を出荷してしまった場合には、速やかにそれを回収するために、様々なチャネルでリコールの告知をしています。告知には、その製品の名前や、JANコード、不具合の内容、対処方法などが含まれています。このようなリコールの情報は、消費者庁が提供しているリコール情報サイトでも公開されていますが、現在はウェブで公開されています。
このようにリコールに関する情報は、行政も集約し、消費者に提供しているものの、ウェブだけでの提供であるため、消費者が直接閲覧することが前提となっています。幅広く消費者に情報を届けるためには、他のアプリケーションとの連携が必要になるでしょうし、そのためにAPIを利用したサービスなども今後提供されていくでしょう。
本チュートリアルでは、将来的にAPIが提供されることを前提として、商品がリコール対象かどうかを調べるAndroidアプリケーションの作成を目指します。対象商品としては、特に食品を想定します。食品の場合には、JANコードだけでなく、製造所固有記号という企業が工場に付与した番号も重要な要素となりますので、このアプリケーションでは、JANコードと製造所固有記号の組合せからリコール情報を検索することとします。
ここでは、簡単のため、リコール情報提供サービスはMySQLへのDBアクセスで実現することとします。
図 アプリケーションイメージ
■ Android Studioを使ったDB接続
MySQL Connector/Jを用意する
DB接続には、MySQL Connector/Jを使用します。これを使うことで、直接、Android端末とDBを接続することができます。この接続方法は、比較的、簡単に実装できますが、ネットワークの途中にファイヤウォールがある場合などは、ポートを開放するなどの対処が必要となります。
MySQL Connector/Jは、MySQLのホームページからダウンロードしておきます。最新のものではなく、以前のバージョンを使用します。
図 MySQLのHP
mysql-connector-java-5.1.47.zipがダウンロードされたら、zipを解凍して、出てきたフォルダをわかりやすいところに保存しておきます。 実際に使用するのは、このフォルダ内のmysql-connector-java-5.1.47-bin.jarです。
テーブルの設計
次に、今回のアプリケーションで使用するDBを作成します。テーブルは上記で説明した内容を含む以下のような項目を含むものを作成しておきます。
Field | Type | Key | Extra | Description |
id | int(5) | PRI | auto_increment | |
jan |
varchar(20) | JANコード | ||
factId |
varchar(5) | 製造所固有記号 | ||
company |
varchar(30) | 企業名 | ||
name |
varchar(30) | 製品名 | ||
phone |
varchar(12) | 電話番号 | ||
regDate |
date | 登録日 |
idを主キーとして、自動発番とします。DB名は、recall_db、テーブル名は、recall_tblとします。ユーザー名と、パスワードは、recallQry、reca!!Qryとして、チュートリアルを進めます。DBは各自、作成しておいてください。
■ アプリケーションの動作
まず、アプリケーションの画面ですが、次のような画面とします。この画面を前提として、アプリケーションは次のように使用するものとします。
- 消費者は「検索」ボタンを押下し、調査したい商品のバーコードをスキャンする。
- 読取結果が、画面のバーコード入力欄に記載される。
- 続いて消費者は固有記号の入力欄に商品のパッケージに記載されている製造所固有記号を入力する。
- 両方の情報を入力したのち、消費者は「検索」ボタンを押下し、リコール情報提供サービスに接続する。
- リコール情報提供サービス(DBシステム)は、バーコードと製造所固有記号をアンド検索し、該当の情報をアプリケーションに戻す。該当がない場合には、リコール対象でない旨のメッセージを戻す。
■ アプリケーションの実装
画面の作成
画面は、AndroidStudioのレイアウトエディターを使用して作成します。配置するコンポーネントは、「バーコード」と「固有記号」を示すラベル、そして、検索結果の表示蘭は、TextViewを配置します。実際のバーコードと固有記号は、EditTextを配置します。読取ボタンと検索ボタンは、ボタンとなります。
なお、このアプリケーションでは、読取ボタンを押下することで、バーコードの読取りアプリを開き、そのアプリからバーコードの値を取り込むようにします。
- バーコードのラベル:tv1
- 固有記号のラベル:tv2
- バーコードの入力欄:et1
- 固有記号の入力欄:et2
- 読取ボタン:btn1
- 検索ボタン:btn2
通信・DB接続設定
このアプリケーションは、インターネット接続を行いますので、Manifestに次の通信を許可するための記述を追加します。
<uses-permission android:name="android.permission.INTERNET" />
また、MySQLとMySQL Connector/Jで接続するために、先ほどダウンロードしたjarファイルを設定する必要があります。設定は以下の手順で行います。
- jarファイルをアプリケーションのlibsフォルダにコピーする
- jarを新しいモジュールとしてインポートする
- jarをdependenciesに追加する
(2)は、AndroidStudioのFile>New>New Moduleを開いて、appフォルダ内のlibsから、(1)でコピーしたjarファイルを選択することで行います。
図 jarファイルのインポート(1)
図 jarファイルのインポート(2)
(3)は、ナビゲーション部分のappで右クリックし、Open Module Settingsを選択し、開いたウィンドウからdependenciesタブを選択します。開いたウィンドウの右上から「+」を押下し、jarの追加を選びます。開いたウィンドウから、先ほど追加したMySQL Connector/Jを選択することで、アプリケーションからMySQL接続を行うことが可能となります。
図 dependencies設定(1)
図 dependencies設定(2)
コーディング
簡単なアプリケーションですので、MainActivity.javaにすべてのコードを記述します。まず、ライブラリの追加ですが、追加で使用するものは以下のライブラリです。
import android.content.Intent; import android.os.AsyncTask; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import java.sql.DriverManager;
ボタンを押したときの動作があるので、MainActivity.javaはOnClickListenerをimplementsします。また、プログラムで使用する変数も追加しておきます。
// 変数定義 public static final int REQUEST_CODE_BC = 1; private String jan = null; public class MainActivity extends Activity implements OnClickListener { (コードはここでは省略) }
onCreateメソッド内に、それぞれのボタンが押された時の処理を記述します。
// Buttonの操作 Button btn1 = (Button)this.findViewById(R.id.btn1); Button btn2 = (Button)this.findViewById(R.id.btn2); btn1.setOnClickListener(this); btn2.setOnClickListener(this);
それぞれのボタンを押したときの動作の実装は、次のようにすることで実現できます。
@Override public void onClick(View v){ // Button action selection if(v.getId()==R.id.btn1) { // ボタン1が押下された時の処理 }else{ // ボタン2が押下された時の処理 } }
では、まず、ボタン1が押下された時、つまり、バーコードを読み取るときの処理を記述します。今回は、zxingのバーコード読み取りアプリの利用を前提として、記述します。他のアプリケーションとの連携には、intentを使用します。intentを使って、他のアプリケーションを起動し、そこで取得したデータをstartActivityForResultを使って、作成するアプリケーションで、利用するという処理を行います。
具体的には、呼び出す側のでは以下の処理を追加します。
// ボタン1が押下された時の処理 Intent intent = new Intent("com.google.zxing.client.android.SCAN"); try { startActivityForResult(intent, REQUEST_CODE_BC); } catch (ActivityNotFoundException ex) { Toast toast = Toast.makeText(this, "scanner not found", Toast.LENGTH_LONG); toast.show(); }
バーコードを読み取るアプリケーションがない場合には、画面にアプリケーションがない旨のメッセージがポップアップします。
startActivityForResultメソッドは次のように記述します。
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ if(requestCode==REQUEST_CODE_BC && resultCode== Activity.RESULT_OK){ jan=data.getStringExtra("SCAN_RESULT"); // 読取結果をjanに格納 EditText et1 = (EditText) findViewById(R.id.et1); // ed1を定義 et1.setText(jan); // ed1にjanを記述する } }
この状態で、いったんアプリケーションを動かしてみましょう。
読取ボタンを押下すると、xzingのアプリケーションが開き、バーコードを読み取ると、そのコードが、EditTextに記載されると思います。無事に動いたでしょうか。
図 起動画面
図 バーコード読み取り
続いて、検索ボタンを押下した際の処理を追加します。ここでの注意点は、DBアクセスが非同期で行われるということです。非同期で処理をする際には、AsyncTaskを拡張したクラスを利用する必要があります。そこで、ここでは、まず、そのクラスを作成することにします。
ここでは、TaskDbQueryというクラスを作成します。AsyncTaskクラス を継承するこのクラスは、3つのパラメータの方の型を指定する必要があります。
class TaskDbQuery extends AsyncTask <Void,Void,String >{ // この中をこれから記述 }
最初が、読み出し元でメソッドが実行される時に渡される引数の型、2つ目は進捗を表現する時に使用する型、3つ目はスレッド終了時に返す値の型です。ここでは、起動時の引数は渡さないのでVoid、進捗も表示しないのでVoidとし、処理の結果として、画面表示を行いたいので、3つ目はStringとしました。
クラス側でActivityを定義し、コンストラクタにおいて引数として渡されてきたアクティビティを代入します。
Activity activity = null; // コンストラクタ public TaskDbInsert(Activity activity){ this.activity = activity; }
次に、実際の処理を記述します。AsyncTaskでは、doInBackgroundメソッドを実装する必要があり、今回はそのメソッド にDBアクセスのコードを記述します。アプリケーションのフローのところでも説明したように、ここでは、バーコードと製造所固有記号のアンド条件で検索を行います。そして、該当する商品がある場合には、結果をrsTextにアペンドして作成し、結果がない場合には、該当する商品がない旨をrsTextに記載します。対象商品がある際のrs.getString()の引数の番号は、テーブルの構造によります。
記述の内容は、基本的に通常のDB接続と同じです。IPアドレスは、接続するサーバーのIPアドレスですので、皆さんの環境に合わせて設定してください。
@Override protected String doInBackground(Void... params){ // JANコードを取得する EditText ed1 = (EditText)activity.findViewById(R.id.et1); String jan = ed1.getText().toString(); // 製造所固有記号を取得する EditText ed2 = (EditText)activity.findViewById(R.id.et2); String factId = ed2.getText().toString(); // 結果の文字列 String rsText=""; // DB query try{ Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.107/recall_db", "recallQry", "reca!!Qry"); Statement stmt = conn.createStatement(); String sql = "SELECT * FROM recall_tbl WHERE jan ='"+jan+"' AND factId='"+factId+"'"; ResultSet rs = stmt.executeQuery(sql); int rsCnt=0; while(rs.next()){ // 商品のレコードの取り出し rsText = "リコール対象です\r\n\n"; rsText+= "製品名:"+rs.getString(5)+"\r\n"; rsText+="JAN:"+rs.getString(2)+"\r\n"; rsText+="製造所固有記号:"+rs.getString(3)+"\r\n"; rsText+="製造メーカー:"+rs.getString(4)+"\r\n"; rsText+="連絡先:"+rs.getString(6)+"\r\n"; rsText+="届出日:"+rs.getString(7)+"\r\n\n"; rsCnt++; } // レコードがない場合の記載 if(rsCnt==0)rsText="リコール対象ではありません"; // 終了処理 rs.close(); stmt.close(); conn.close(); }catch(Exception e){ rsText=e.getMessage(); } return rsText; }
また、非同期処理が終了後の処理は、次のようになります。結果を、tv3に書き出す処理になります。
protected void onPostExecute(String result){ TextView tv3 = (TextView)activity.findViewById(R.id.tv3); tv3.setText(result); }
非同期処理用のクラスの作成は以上です。
では、先にボタン押下を判定し、このクラスのインスタンスを作成し処理する部分を記述しましょう。これは、class MainActivity内にメソッドとして定義します。
// ボタン2が押下された時の処理 TaskDbQuery task = new TaskDbQuery(MainActivity.this); task.execute();
ここまで実装することで、検索ができるはずです。DBに何らかのデータを入力して、検索をしてみましょう。
図 製造所固有記号の入力
図 検索結果表示
検索結果は無事に表示されたでしょうか。
■ アプリケーションの課題
このアプリケーションにはたくさん課題があります。各自、課題の解決に取り組んでみましょう。
- JANコードと製造所固有記号のアンド検索となっていますが、製造所固有記号のデータがそもそもない場合、また、アプリでの入力し忘れの時の処理がされていません。
- リコール情報提供サービスがDBに直接接続となっていますが、ネットワーク環境を考えれば、HTTP接続にした方がよいと考えられます。
- 消費者庁が提供するウェブでは商品の画像情報も表示されています。画像があった方が分かりやすいので、画像を表示する方がよいでしょう。
- 同じ製品について、複数のリコールがあった場合の処理がなされていません。
- リコール情報提供サービスにデータを投入するクライアントアプリケーションもあった方がいいでしょう。
他にもアプリケーションをよりよくする機能があると思います。是非、皆さんで挑戦してみてください。
(ページの先頭へ)