1 實驗十二:待辦事項程式 ( 儲存在遠端伺服器上 )
實驗十二 2 主題 本實驗為練習使用 Web Service 操作資料庫 使用資料庫用來建立、新增、刪除、修改資料等功能 目的 學習如何使用 Web Service 的連線 了解與遠端伺服器的參數傳遞 環境需求 Java SE Development Kit (JDK) Android SDK Eclipse ADT Apache MySQL PHP
實驗十二範例 3 將製作一個行程事項列表應用程式 按下新增後,會將輸入的資訊存入遠端伺 服器資料庫
網頁端程式
範例使用的資料庫 資料庫名稱 :schedule 資料表名稱 :todolist 欄位名稱資料型態預設備註 _idint(11)primary key auto_increment 流水號 ( 系統自動新增 ) datevarchar(254) 日期 timevarchar(254) 時間 titlevarchar(254) 標題
在 MySQL 建立資料庫 主機的 IP/phpMyAdmin
在 MySQL 建立資料表
在 MySQL 建立欄位資料 自行建立 Sql 檔匯入
C:\AppServ\www\php\setting.php PHP 網頁與資料庫連線 <? $dbhost = “localhost”; 資料庫 IP 或是 domain name $dbname = "schedule"; 資料庫名稱 $dbuser = "android"; 帳號 $dbpass = "sqllite"; 密碼 $db = mysql_connect($dbhost, $dbuser, $dbpass); mysql_query("SET NAMES 'utf8'"); global $db; mysql_select_db($dbname, $db); ?>
C:\AppServ\www\php\getalltodo.php 顯示資料表所有的資料 <? echo ' '; include "./setting.php"; $result = mysql_query(“SELECT * FROM todolist”) or die(mysql_error()); if (mysql_num_rows($result) > 0) { while ($row = mysql_fetch_array($result)) { echo " "; echo " ".$row["_id"]." "; echo " ".$row["date"]." "; echo " ".$row["time"]." "; echo " ".$row["title"]." "; echo " "; } echo ' '; ?> 查詢 todolist 的所有資料
所有資料的 XML /08/20 13:30 Android /08/21 09:20 Android 2
C:\AppServ\www\php\addtodo.php 新增資料 <? echo ' '; include "./setting.php"; $date = $_POST['date']; $time = $_POST['time']; $title = $_POST['title']; $sql = "INSERT INTO todolist(date,time,title) VALUES('$date','$time','$title')"; $result = mysql_query($sql); if($result) echo "1"; else echo "0"; echo ' '; ?> 新增資料到 todolist 中
C:\AppServ\www\php\updatetodo.php 更新資料 <? echo ' '; include "./setting.php"; $id = $_POST['_id']; $date = $_POST['date']; $time = $_POST['time']; $title = $_POST['title']; $sql = "UPDATE todolist SET date='$date',time='$time',title='$title' WHERE _id=$id"; $result = mysql_query($sql); if($result) echo "1"; else echo "0"; echo ' '; ?> 更新資料到 todolist 中
C:\AppServ\www\php\deltodo.php 刪除資料 <? echo ' '; include "./setting.php"; $id = $_POST['_id']; $sql = "DELETE FROM todolist WHERE _id=$id"; $result = mysql_query($sql); if($result) echo "1"; else echo "0"; echo ' '; ?> 刪除資料
手機端程式
加入使用網路的權限 AndroidManifest.xml 點選 Permissions 新增 新增 Uses Permission 使用網路 1 1
res/layout/activity_main.xml <LinearLayout xmlns:android=" xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <EditText android:layout_weight=“1” android:layout_width="match_parent" android:layout_height="wrap_content" android:hint=“ 輸入日期 ” android:inputType="date" /> <EditText android:layout_weight=“1” android:layout_width="match_parent" android:layout_height="wrap_content" android:hint=“ 輸入時間 ” android:inputType="time" /> // 接下頁 2 2 輸入日期和時間 的編輯框
res/layout/activity_main.xml <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <EditText android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint=" 輸入標題 " /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 新增 " /> <ListView android:layout_width="match_parent" android:layout_height="wrap_content" /> 3 3 輸入標題的編輯 框和新增的按鈕
新增 res/layout/list.xml 在 layout 按右鍵 → 新建 →Android XML File 4 4 XML 名稱
res/layout/list.xml <LinearLayout xmlns:android=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" android:layout_gravity="center_vertical" android:layout_weight="1" /> 一列列表選項佈局 5 5
src/MainActivity.java public class MainActivity extends Activity { EditText inputdate,inputtime,inputtitle; ListView lv; SimpleAdapter adapter; ArrayList > todolist; static final int SHOW_RESULT = 0; 自訂 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); inputdate=(EditText)findViewById(R.id.editText1); inputtime=(EditText)findViewById(R.id.editText2); inputtitle=(EditText)findViewById(R.id.editText3); lv=(ListView)findViewById(R.id.listView1); lv.setOnItemClickListener(this); Button bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(this); GetAllToDoList todolist=new GetAllToDoList(); todolist.execute(); } 產生一個執行緒用來處理 查詢遠端資料庫的資料
src/MainActivity.java 將滑鼠移到 AsyncTask ,匯入 AsyncTask 將滑鼠移到 GetAllToDoList ,新增未實作方法
src/MainActivity.java protected ArrayList > doInBackground( Void... arg0) { HttpClient client = new DefaultHttpClient(); HttpPost request = new HttpPost(“ 遠端伺服器 /php/getalltodo.php"); HttpResponse response = client.execute(request); return null; } 將滑鼠移到 client.execute() 中,產生 try/catch 區塊, 避免執行失敗造成程式關閉 連線到遠端伺服器的網址
protected ArrayList > doInBackground( Void... arg0) { try { HttpResponse response = client.execute(request); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } 11 取得 DocumentBuilder 物件,將資料以 DOM 的方式存到手機中 加入 catch
src/MainActivity.java try { HttpResponse response = client.execute(request); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(response.getEntity().getContent()); NodeList items=doc.getElementsByTagName("item"); ArrayList > list=new ArrayList >(); // 接下頁 } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } return null; 12 解析 XML 回應的內容 取得 XML 中標籤名稱為 item 的 NodeList
src/MainActivity.java try { for (int i=0;i<items.getLength();i++) { Node x=items.item(i); NodeList childs=x.getChildNodes(); int num=0; HashMap row=new HashMap (); for(int j=0;j<childs.getLength();j++){ if(childs.item(j).getNodeName().equals("_id") || childs.item(j).getNodeName().equals("date") || childs.item(j).getNodeName().equals("time") || childs.item(j).getNodeName().equals("title")){ num++; if(childs.item(j).hasChildNodes()){ row.put(childs.item(j).getNodeName(), childs.item(j).getChildNodes().item(0).getNodeValue().trim());} } if(num>0) list.add(row); } return list; } 13
protected void onPostExecute(ArrayList > result) { todolist=result; adapter= new SimpleAdapter(MainActivity.this,result, R.layout.list, new String[]{"date","time","title"}, new int[]{R.id.textView1,R.id.textView2,R.id.textView3}); lv.setAdapter(adapter); super.onPostExecute(result); } 14 Alt+/ 覆寫 onPostExecute() 方法 查詢的結果存到 SimpleAdapter 中,顯示在列表處中
src/MainActivity.java public void onClick(View arg0) { AddToDo todo=new AddToDo(); todo.execute(inputdate.getText().toString(), inputtime.getText().toString(), inputtitle.getText().toString()); } 15 將滑鼠移到 AddToDoList ,新增未實作方法 新增資料的執行緒
src/MainActivity.java protected String doInBackground(String... params) { HttpClient client = new DefaultHttpClient(); HttpPost request = new HttpPost(" 遠端伺服器 /php/addtodo.php"); List post_params = new ArrayList (); post_params.add(new BasicNameValuePair("date", params[0])); post_params.add(new BasicNameValuePair("time", params[1])); post_params.add(new BasicNameValuePair("title", params[2])); UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(post_params); return null; } 16 HttpPost 傳送的參數和參數的值 產生 try/catch 區塊,避免執行失敗造成程式關閉
src/MainActivity.java try { UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(post_params); HttpResponse response = client.execute(request); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(response.getEntity().getContent()); NodeList items=doc.getElementsByTagName("result"); Node x=items.item(0); return x.getChildNodes().item(0).getNodeValue().trim(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } return null; 17
protected void onPostExecute(String result) { if(result.equals("1")) { GetAllToDoList todolist=new GetAllToDoList(); todolist.execute(); Toast.makeText(MainActivity.this, " 新增成功 ", Toast.LENGTH_LONG).show(); inputdate.setText(""); inputtime.setText(""); inputtitle.setText(""); }else Toast.makeText(MainActivity.this, " 新增失敗 ", Toast.LENGTH_LONG).show(); super.onPostExecute(result); } 18 Alt+/ 覆寫 onPostExecute() 方法
src/MainActivity.java public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) { HashMap record=todolist.get(arg2); String id=record.get("_id"); Intent intent = new Intent(); intent.setClass(this, modify.class); Bundle bdl = new Bundle(); bdl.putString("id", id + ""); TextView date=(TextView)arg1.findViewById(R.id.textView1); bdl.putString("date", date.getText()+""); TextView time=(TextView)arg1.findViewById(R.id.textView2); bdl.putString("time", time.getText()+""); TextView title=(TextView)arg1.findViewById(R.id.textView3); bdl.putString("title", title.getText()+""); intent.putExtras(bdl); startActivityForResult(intent, SHOW_RESULT); } 19 開啟 modify 的活動視窗 將列表處的資料綁在 Bundle 中傳遞過去 開啟需要回傳結果的活動視窗
protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == SHOW_RESULT) { if (resultCode == RESULT_OK) { GetAllToDoList todolist=new GetAllToDoList(); todolist.execute(); } 20 Alt+/ 覆寫 onActivityResult() 方法
新增 modify 活動視窗 套件名稱按右鍵 → 新建 → 其他 21
新增 modify 活動視窗 22 活動視窗名稱
res/layout/activity_modify.xml <LinearLayout xmlns:android=" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 日期 " /> <EditText android:layout_weight="1" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="date" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:text=" 時間 " android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="time" /> // 接下頁 23 修改日期和時間 的編輯框
res/layout/activity_modify.xml <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" 標題 " /> <EditText android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" 修改 " /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text=" 刪除 " /> 24 修改標題的編輯框 修改和刪除的按鈕
src/modify.java public class modify extends Activity implements OnClickListener { EditText dateET,timeET,titleET; String public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_modify); Button btn = (Button) findViewById(R.id.button1); btn.setOnClickListener(this); btn = (Button) findViewById(R.id.button2); btn.setOnClickListener(this); Bundle bdl = getIntent().getExtras(); id = bdl.getString("id", "0"); date = bdl.getString("date", "0"); time = bdl.getString("time", "0"); title = bdl.getString("title", "0"); dateET = (EditText) findViewById(R.id.editText1); dateET.setText(date); timeET = (EditText) findViewById(R.id.editText2); timeET.setText(time); titleET = (EditText) findViewById(R.id.editText3); titleET.setText(title); } 25 取得主程式傳遞過來的資料
src/modify.java public void onClick(View v) { switch (v.getId()) { case R.id.button1: UpdateToDo update = new UpdateToDo(); update.execute(id,dateET.getText().toString(), timeET.getText().toString(),titleET.getText().toString()); break; case R.id.button2: DelToDo del=new DelToDo(); del.execute(id); break; } Intent intent = new Intent(); setResult(RESULT_OK, intent); finish(); } 26 更新資料執行緒 判斷哪個按鈕被按下 刪除資料執行緒 回傳結果回主程式 關閉視窗
src/modify.java class UpdateToDo extends AsyncTask protected String doInBackground(String... params) { HttpClient client = new DefaultHttpClient(); HttpPost request = new HttpPost(" 遠端伺服器 /php/updatetodo.php"); List post_params = new ArrayList (); post_params.add(new BasicNameValuePair("_id", params[0])); post_params.add(new BasicNameValuePair("date", params[1])); post_params.add(new BasicNameValuePair("time", params[2])); post_params.add(new BasicNameValuePair("title", params[3])); // 接下頁 return null; } 27
src/modify.java try { UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(post_params); request.setEntity(formEntity); HttpResponse response = client.execute(request); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(response.getEntity().getContent()); NodeList items=doc.getElementsByTagName("result"); Node x=items.item(0); return x.getChildNodes().item(0).getNodeValue().trim(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } 28
protected void onPostExecute(String result) { if(result.equals("1")) Toast.makeText(modify.this, " 更新成功 ", Toast.LENGTH_LONG).show(); else Toast.makeText(modify.this, “ 更新失敗 ”, Toast.LENGTH_LONG).show(); super.onPostExecute(result); } 29 Alt+/ 覆寫 onPostExecute() 方法
src/modify.java class DelToDo extends AsyncTask protected String doInBackground(String... params) { HttpClient client = new DefaultHttpClient(); HttpPost request = new HttpPost(" 遠端伺服器 /php/deltodo.php"); List post_params = new ArrayList (); post_params.add(new BasicNameValuePair("_id", params[0])); return null; } 30
src/modify.java try { UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(post_params); request.setEntity(formEntity); HttpResponse response = client.execute(request); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(response.getEntity().getContent()); NodeList items=doc.getElementsByTagName("result"); Node x=items.item(0); return x.getChildNodes().item(0).getNodeValue().trim(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } 31
protected void onPostExecute(String result) { if(result.equals("1")) Toast.makeText(modify.this, " 刪除成功 ", Toast.LENGTH_LONG).show(); else Toast.makeText(modify.this, " 刪除失敗 ", Toast.LENGTH_LONG).show(); super.onPostExecute(result); } 32 Alt+/ 覆寫 onPostExecute() 方法