3.2 討論子系統實作
3.2.2 Socket Client 系統功能實作
}
} catch(Exception e) {
}
params.add(new BasicNameValuePair("query_string", query_string));
httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
InputStream inputStream = httpEntity.getContent();
BufferedReader bufReader = newBufferedReader(new InputStreamReader(inputStream, "utf-8"), 8);
StringBuilder builder = newStringBuilder();
String line = null;
while((line = bufReader.readLine()) != null) { builder.append(line + "\n");
} inputStream.close();
result = builder.toString();
System.out.println("有結果"+result);
} catch(Exception e) { Log.e("log_tag", e.toString());
} } return result;
}
程式碼 3.5 傳遞參數至 getallgroup.php 網頁並接收回傳結果
<?php
$database_dblink = "ntnuxml";
$username_dblink = "root";
// 建立資料庫連線
$dblink = mysql_pconnect("localhost", $username_dblink, $password_dblink) or trigger_error(mysql_error(),E_USER_ERROR);
mysql_query("SET NAMES utf8",$dblink);
mysql_query("SET CHARACTER_SET_CLIENT=utf8",$dblink);
mysql_query("SET CHARACTER_SET_RESULTS=utf8",$dblink);
mysql_select_db($database_dblink, $dblink);
header("Content-Type:text/html; charset=utf-8");
$query_rs = $_POST['query_string'];
$rs = mysql_query($query_rs, $dblink) or die(mysql_error());
while ($row = mysql_fetch_assoc($rs)) { $output[] = $row ;
privateclass ButtonListener implements OnClickListener{
publicvoid onClick(View v){
switch(v.getId()){
case R.id.button1:
intent = new Intent();
intent.setClass(MainView.this, MainActivity.class);
Bundle bundle = newBundle();
bundle.putInt("portnumber", 100);
Bundle namebundle = newBundle();
bundle.putString("name", name);
intent.putExtras(bundle);
intent.putExtras(namebundle);
startActivity(intent);
break;
case R.id.button2:
intent = new Intent();
intent.setClass(MainView.this, MainActivity.class);
bundle = new Bundle();
bundle.putInt("portnumber", 101);
namebundle = new Bundle();
bundle.putString("name", name);
intent.putExtras(bundle);
intent.putExtras(namebundle);
startActivity(intent);
break;
case R.id.button3:
intent = new Intent();
intent.setClass(MainView.this, MainActivity.class);
bundle = new Bundle();
bundle.putInt("portnumber", 102);
namebundle = new Bundle();
bundle.putString("name", name);
intent.putExtras(bundle);
intent.putExtras(namebundle);
startActivity(intent);
break;
程式碼 3.7 使用者選擇任一討論群組進行連線 Bundle MainViewbundle =this.getIntent().getExtras();
getportnumber=MainViewbundle.getInt("portnumber");
Bundle NameViewbundle =this.getIntent().getExtras();
name=NameViewbundle.getString("name");
程式碼 3.8MainAvtivity 接受所傳遞參數,判斷使用者與哪一個 portnumber 建立連 線
try {
InetAddress serverIp;
serverIp = InetAddress.getByName("140.122.184.33");//server位置 int serverPort = getportnumber;//根據使用者傳送過來的portnumber clientSocket = new Socket(serverIp, serverPort);//server位置
// 取得網路訊息
BufferedReader br = newBufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
// 當連線後
while (clientSocket.isConnected()) { // 取得網路訊息
tmp = br.readLine();
// clientSocket.sendUrgentData(0xFF);
// 如果不是空訊息則
//Toast.makeText(getApplicationContext(), "連線失敗", Toast.LENGTH_LONG).show();
publicvoid onClick(View v) { try {
if(clientSocket.isConnected()){
try {
// 取得網路輸出串流 bw = new
BufferedWriter( newOutputStreamWriter(clientSocket.getOutputStream(),bm));
// 寫入訊息bw.write(EditText01.getText()+":"+EditText02.getText()+"\n");
// 立即發送 bw.flush();
} catch(Exception e){
Toast.makeText(getApplicationContext(), "連線失敗,聊天室尚未啟動
", Toast.LENGTH_LONG).show();
}
// 送出文字後便將輸入訊息的文字方塊清空 EditText02.setText("");
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "連線失敗,聊天室 尚未啟動", Toast.LENGTH_LONG).show();
} }
});
程式碼 3.10 送訊息給其他用戶端
3.2.2.1 Dropbox 功能實作
此功能修改自 dropbox 官方所提供的 API 範例[9]並整合至本系統中。此功能 的用處是在於當使用者在實地探訪時,可以將實地物件所拍攝,並將之上傳到系 統所提供的 Dropbox 雲端空間中,提供其他使用者來觀看。另外當討論結束後,
可以將討論內容存檔並上傳至 Dropbox 雲端空間中,提供給使用者日後來編輯彙 整。
在實作此功能之前必須先到 dropbox 官網,創建一個開發 app 並取得 app key 以及 app secret,本系統開發的 app 名稱為 xmlupload,如圖 3.6 所示:
圖 3.6 申請 dropbox appp
建置完畢之後須在程式碼內加入申請的 app key 以及 app secret 如下所示:
publicclass DBRoulette extends Activity { privatestaticfinal String TAG = "DBRoulette";
///////////////////////////////////////////////////////////////////////////
// Yourapp-specific settings.
//
///////////////////////////////////////////////////////////////////////////
// Replace this with your app key and secret assigned by Dropbox.
// Note that this is a really insecure way to do this, and you shouldn't // ship code which contains your key & secret in such an obvious way.
// Obfuscation is good.
finalstaticprivate String APP_KEY = "b1f40rjy2qmly8a";
finalstaticprivate String APP_SECRET = "ywi5iour3qwi4nl";
// If you'd like to change the access type to the full Dropbox instead of // an app folder, change this value.
finalstaticprivate AccessType ACCESS_TYPE = AccessType.APP_FOLDER;
///////////////////////////////////////////////////////////////////////////
// End app-specific settings.
///////////////////////////////////////////////////////////////////////////
// You don't need to change these, leave them alone.
finalstaticprivate String ACCOUNT_PREFS_NAME = "prefs";
finalstaticprivate String ACCESS_KEY_NAME = "ACCESS_KEY";
finalstaticprivate String ACCESS_SECRET_NAME = "ACCESS_SECRET";
程式碼 3.11 設定程式所用到的 key 以及 secret
拍照上傳:上傳的功能分成兩部分,一種為上傳「照片資料」至 dropbox 雲端,
另一種為上傳「照片網址」至本地資料庫中。
第一部分:上傳照片資料到 dropbox 雲端
首先必須先啟動相機功能並預設一個照片名稱並且判斷該手機是否有相機 功能。本系統利用時間函數來取得現在時刻用來當作照片的名稱,並且透過例外
處理來判斷是否有相機功能,其實作代碼如程式碼 3.12 所示:
Intent intent = newIntent();
// Picture from camera
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
// This is not the right way to do this, but for some reason, having // it store it in
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI isn't working right.
Date date = newDate();
DateFormat df = newSimpleDateFormat("yyyy-MM-dd-kk-mm-ss");
String newPicFile = df.format(date) + ".jpg";
String outPath = "/sdcard/chatroom/img/" + newPicFile;
File outFile = newFile(outPath);
mCameraFileName = outFile.toString();
Uri outuri = Uri.fromFile(outFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outuri);
Log.i(TAG, "Importing New Picture: " + mCameraFileName);
startActivityForResult(intent, NEW_PICTURE);
} catch (ActivityNotFoundException e) {
showToast("There doesn't seem to be a camera.");
}
程式碼 3.12 啟動拍照功能
拍完照片之後,系統會呼叫上傳函式並將照片上傳至指定的群組資料夾中,其程
式實作如程式碼 3.13 所示:
protected Boolean doInBackground(Void... params) { try {
// By creating a request, we get a handle to the putFile operation, // so we can cancel it later if we want to
FileInputStream fis = newFileInputStream(mFile);
String path = mPath + mFile.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(), new ProgressListener() {
@Override
publiclong progressInterval() {
// Update the progress bar every half-second or so return 500;
}
@Override
publicvoid onProgress(long bytes, long total) { publishProgress(bytes);
// This session wasn't authenticated properly or user unlinked mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) { // File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) { // We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen, // but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) { // Unauthorized, so we should unlink them. You may want to // automatically log the user out in this case.
} elseif (e.error == DropboxServerException._403_FORBIDDEN) { // Not allowed to access this
} elseif (e.error == DropboxServerException._404_NOT_FOUND) { // path not found (or if it was the thumbnail, can't be
// thumbnailed)
} elseif (e.error ==
DropboxServerException._507_INSUFFICIENT_STORAGE) { // user is over quota
} else { // Something else }
// This gets the Dropbox error, translated into the user's language mErrorMsg = e.body.userError;
if (mErrorMsg == null) { mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) { // Unknown error
mErrorMsg = "Unknown error. Try again.";
}
publicvoid getURL() {
String shareAddress=null;
try {
Entry dirent = mApi.metadata(mPath, 1000, null, true, null);
//取得該目錄下照片的網址 for (Entry ent : dirent.contents) { if (!ent.isDir) {
shareLink = mApi.share(ent.path);
shareAddress = getShareURL(shareLink.url).replaceFirst("https://www", "https://dl");
try {
String getShareURL(String strURL) { URLConnection conn = null;
try {
URL inputURL = newURL(strURL);
conn = inputURL.openConnection();
} catch (MalformedURLException e) { // Log.d(TAG,"Please input a valid URL");
} catch (IOException ioe) { // Log.d(TAG,"Can not connect to the URL");
}
return conn.getHeaderField("location");
}
程式碼 3.14 取得照片的網址
取得照片網址之後便使用 json 格式的資料傳遞到 postTest_mysql.php 網頁,其實
坐方式如程式碼 3.15:
private String uriAPI =
"http://140.122.184.33/thesis/httpPostTest/postTest_mysql.php";
private String sendPostDataToInternet(String strTxt) {
/* 建立HTTP Post連線 */
HttpPost httpRequest = newHttpPost(uriAPI);
/*
* Post運作傳送變數必須用NameValuePair[]陣列儲存 */
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("data", strTxt));
try{
/* 發出HTTP request */
httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
/* 取得HTTP response */
HttpResponse httpResponse = newDefaultHttpClient() .execute(httpRequest);
/* 若狀態碼為200 ok */
if (httpResponse.getStatusLine().getStatusCode() == 200)
/* 取出回應字串 */
String strResult = EntityUtils.toString(httpResponse .getEntity());
// 回傳回應字串 return strResult;
}
} catch (Exception e) {
$database_dblink = "ntnuxml";
$username_dblink = "root";
$password_dblink = "1111";
// 建立資料庫連線
$dblink = mysql_pconnect("localhost", $username_dblink, $password_dblink) or trigger_error(mysql_error(),E_USER_ERROR);
mysql_query("SET NAMES utf8",$dblink);
mysql_query("SET CHARACTER_SET_CLIENT=utf8",$dblink);
mysql_query("SET CHARACTER_SET_RESULTS=utf8",$dblink);
mysql_select_db($database_dblink, $dblink);
// 宣告utf-8的編碼
header("Content-Type:text/html; charset=utf-8");
// 接收POST/GET的資料
$data=@$_REQUEST['data'];
// 如果有資料
if (strcmp(trim($data), "")!=0)
{ $data_array=explode(',', $data);
//data_array[1]=圖片網址 //data_array[0]=使用者組別 //data_array[2]=圖片名稱 //data_array[3]=使用者名稱
$insertSQL="INSERT INTO dropboxwebsite
(website,whichgroup,picturename,username) VALUES
('$data_array[1]','$data_array[0]','$data_array[2]','$data_array[3]')";
mysql_query($insertSQL, $dblink) or die(mysql_error());
}
$sql = "ALTER IGNORE TABLE `dropboxwebsite` ADD UNIQUE INDEX(`website`);";
mysql_query($sql, $dblink) or die(mysql_error());
?>
mfile = (Button)findViewById(R.id.fileupload);
mfile.setOnClickListener(new OnClickListener() { publicvoid onClick(View v) {
FileInputStream inputStream = null;
Date date = newDate();
DateFormat df =
newSimpleDateFormat("yyyy-MM-dd-kk-mm-ss");
try {
File file = newFile("/sdcard/chatroom/chatlog.txt");
inputStream = new FileInputStream(file);
Entry newEntry =
mApi.putFile("/log/"+upgroup+"/"+df.format(date)+"_chatlog.txt", inputStream, file.length(), null, null);
Toast.makeText(DBRoulette.this, "上傳成功",
Log.i("DbExampleLog", "The uploaded file's rev is: " + newEntry.rev);
} catch (DropboxUnlinkedException e) {
// User has unlinked, ask them to link again here.
Log.e("DbExampleLog", "User has unlinked.");
} catch (DropboxException e) {
Log.e("DbExampleLog", "Something went wrong while uploading.");
} catch (FileNotFoundException e) { Log.e("DbExampleLog", "File not found.");
} finally {
Button showimg = (Button) findViewById(R.id.showImg);
showimg.setOnClickListener(new Button.OnClickListener(){
publicvoid onClick(View v) {
try {
String result = DBConnector.executeQuery(
"SELECT `website` FROM `dropboxwebsite` where `whichgroup`="+upgroup,0);
//SQL語法:資料表dropboxwebsite中根據組別取得website欄位的值 JSONArray jsonArray = newJSONArray(result);
urlStrings= new String [jsonArray.length()];
if(urlStrings.length!=0){//要有資料才會執行 for(int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonData = jsonArray.getJSONObject(i);
urlStrings[i]=jsonData.getString("website").replaceAll("\\\\", "").toString();
}
galleryAdapter = new GalleryAdapter(gallery.getContext(),urlStrings);
gallery.setAdapter(galleryAdapter);
gallery.setOnItemClickListener(new OnItemClickListener(){
publicvoid onItemClick(AdapterView parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, "您選的是第"+(position+1)+"張圖"+
","+"上傳者"+username[position], Toast.LENGTH_LONG).show();
} });
}
} catch(Exception e) {
// Log.e("log_tag", e.toString());
} } });
privateclass GalleryAdapter extends BaseAdapter{
private Context ctx;
private GetWebImg imgCache;
private String[] urlStrings;
@Override
publicvoid handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg);
notifyDataSetChanged();
} };
private GalleryAdapter(Context ctx,String[] urlStrings){
this.ctx = ctx;
this.urlStrings = urlStrings;
imgCache = new GetWebImg(ctx);
}
@Override
publicint getCount() {
// TODO Auto-generated method stub returnurlStrings.length;
}
@Override
public Object getItem(int position) { // TODO Auto-generated method stub returnnull;
}
@Override
publiclong getItemId(int position) { // TODO Auto-generated method stub return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ImageView imageView = newImageView(ctx);
imageView.setBackgroundResource(android.R.color.holo_blue_bright);
String urlStr = urlStrings[position];
if(imgCache.IsCache(urlStr)){
imageView.setImageBitmap(imgCache.getImg(urlStr));
}else{
imageView.setImageResource(R.drawable.ic_launcher);
imgCache.LoadUrlPic(urlStr, refreshAdapterHandler);
}
imageView.setLayoutParams(new Gallery.LayoutParams(150, 150));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
return imageView;
} }
程式碼 3.18 取得圖片後顯示在畫面上
下列程式碼收到 executeQuery 傳進來的 sql 語法之後,將 sql 語法傳到本機端的 getwebsite.php 網頁再透過網頁向資料庫取得網址,其資料格式為 JSON,程式
實作方法如程式碼 3.19、3.20 所示:
publicclass DBConnector {
publicstatic String executeQuery(String query_string,int a) { String result =null ;
int whichquery =a;
if(whichquery ==0){//取得網址相關參數 try {
System.out.println(query_string);
HttpClient httpClient = newDefaultHttpClient();
HttpPost httpPost =
newHttpPost("http://140.122.184.33/thesis/httpPostTest/getwebsite.php");
ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("query_string", query_string));
HttpResponse httpResponse = httpClient.execute(httpPost);
//view_account.setText(httpResponse.getStatusLine().toString());
HttpEntity httpEntity = httpResponse.getEntity();
InputStream inputStream = httpEntity.getContent();
BufferedReader bufReader = newBufferedReader(new InputStreamReader(inputStream, "utf-8"), 8);
StringBuilder builder = newStringBuilder();
String line = null;
while((line = bufReader.readLine()) != null) { builder.append(line + "\n");
} inputStream.close();
result = builder.toString();
System.out.println(result);
} catch(Exception e) { Log.e("log_tag", e.toString());
}
程式碼 3.19getwebsite.php 傳遞參數至網頁並接收回傳結果
<?php
$database_dblink = "ntnuxml";
$username_dblink = "root";
$password_dblink = "1111";
// 建立資料庫連線
$dblink = mysql_pconnect("localhost", $username_dblink, $password_dblink) or trigger_error(mysql_error(),E_USER_ERROR);
mysql_query("SET NAMES utf8",$dblink);
mysql_query("SET CHARACTER_SET_CLIENT=utf8",$dblink);
mysql_query("SET CHARACTER_SET_RESULTS=utf8",$dblink);
mysql_select_db($database_dblink, $dblink);
header("Content-Type:text/html; charset=utf-8");
$query_rs = $_POST['query_string'];
$data_array=explode('=', $query_rs );
$query_rs=$data_array[0]." = "."'".$data_array[1]."'";
$rs = mysql_query($query_rs, $dblink) or die(mysql_error());
while ($row = mysql_fetch_assoc($rs)) {
$output[] = $row ; }
print(json_encode($output));
?>
程式碼 3.20 接收參數並對資料庫連線取得照片網址
取得網址之後系統會呼叫 GetWebImg 來將圖片網址轉換成 gallery 內的圖片,
此轉換方法是利用 android 內 Bitmap 類別進行圖片的處理,因為 bitmap 不能直 接處理外部 url 的圖片,所以系統會先進行下載的動作。其下載方式是將圖片轉 換成串流存放到陣列之中,並取得該圖片的串流長度,最後在將陣列中的串流進
行解碼的動作便可以獲得圖片影像,其程式實作如程碼 3.21 所示:
Public synchronized Bitmap LoadUrlPic(Context c, String url) { URL imgUrl;
Bitmap defaultImg = null;
Bitmap webImg = null;
Bitmap webImg_o = null;
try {
imgUrl = new URL(url);
}
catch (MalformedURLException e) {
Log.d("MalformedURLException",e.toString());
return defaultImg;//抓不到網路圖時, 讀預設圖片 }
int length = (int) httpURLConnection.getContentLength();
int readLen = 0,desPos = 0;
byte[] img = newbyte[length];
byte[] tmp = newbyte[tmpLength];
BitmapFactory.Options options = new BitmapFactory.Options();//設 定壓縮倍率參數
options.inSampleSize = 10;//變成原圖的百分之一 if (length != -1) {
while ((readLen = inputStream.read(tmp)) > 0) { System.arraycopy(tmp, 0, img, desPos, readLen);
desPos += readLen;
}
webImg = BitmapFactory.decodeByteArray(img, 0, img.length, options);
}
httpURLConnection.disconnect();
}
catch (IOException e) {
Log.d("IOException",e.toString());
return defaultImg; //抓不到網路圖時, 讀預設圖片 }
return webImg;
}
程式碼 3.21 利用 bitmap 方式處理外部圖片
3.2.2.3 對話紀錄存檔功能實作
使用者可以先透過存檔功能將對話內容存在手機的 chatlog.txt 中之後再透過
dropbox 功能將對話紀錄檔上傳到 dropbox,其存檔的程式實作方法如程式碼 3.22 所示:
//對話紀錄存檔功能
Button button2=(Button) findViewById(R.id.save);
button2.setOnClickListener(new Button.OnClickListener() { // 當按下按鈕的時候觸發以下的方法
publicvoid onClick(View v) { try {
fw = new FileWriter("/sdcard/chatroom/chatlog.txt", false);
bw = new BufferedWriter(fw);
content =TextView01.getText().toString();
bw.write(content);
bw.close();
fw.close();
Toast.makeText(getApplicationContext(), "存檔成功", Toast.LENGTH_SHORT).show();
<form id="form1" name="form1" method="post" action="check.php">
<p>設定討論區分組數目</p>
<table width="487" border="1" align="center">
<tr>
<td width="147" height="53">帳號</td>
<td width="239" align="center" valign="center">
<input name="userid" type="text" id="userid" size="20" />
</td>