[Android] debug不用線,用ADB連接3G/wifi手機

介紹一個很酷的功能無意間看到的

常用Eclipse的人都知道

不管是來開發程式的,還是知名部落客拿來截圖免root權限的

都會用到DDMS

 

通常要用連接USB傳輸線連接到實體手機

等待DDMS跳出你的手機之後才做下一步動作 (開發程式,截圖…等等)

 

這裡教你debug不用線,用3G或wifi直接無線Deploy程式

直接線上出Log

真的還蠻酷的

 

條件

曾經連接過USB做過設定的手機

 

設定方法

1.  先確定手機有電,3G或Wifi的網路有開

2.  用 USB 傳輸線接上你的手機

3.  找到Android SDK的路徑 platform-tools/ 資料夾路徑

(每個人裝位置因作業系統或個人喜好的都不太一樣)

以SDK r11為例,用32位元的Windows用exe版的安裝預設在

C:\Program Files\Android\android-sdk\platform-tools

 

4.  按Win key + R,在執行的視窗中打入 cmd

打入指令 (綠色的為指令,黑色的部分為說明)

C:\

cd C:\Program Files\Android\android-sdk\platform-tools

意思是切換資料夾到剛剛找的路徑

adb tcpip 5555 

意思是用tcpip連線,連接埠號5555做Debug伺服器

 

5.  然後就可以脫離USB連線了

在同一個地方再打入像是

adb connect 192.168.1.3:5555 

中間換成你手機的IP位址

意思是讓電腦使用網路連線到你的手機

 

6.  這時候你就可以用無線做操作了

你可以打 adb logcat 

就會動態傳輸手機的Log到畫面上 (按Ctrl+C結束)

 

打入adb devices,就會列出這個特別的裝置

List of devices attached
192.168.1.3:5555     device

就不會是類似

List of devices attached
SH11KRX10258    device

這樣

 

回到Eclipse上,DDMS已經出現這個特別的裝置了

————————————————————

還原回正常的USB傳輸線的模式,要打 adb usb

 

————————————————————

官方原文截錄

  1. 用 USB 傳輸線接上你的手機
  2. 到Android SDK的路徑 platform-tools/ 資料夾
  3. directory, enter adb tcpip 5555 at the command prompt.
  4. Enter adb connect <device-ip-address>:5555 You should now be connected to the Android-powered device and can issue the usual adb commands like adb logcat.
  5. To set your device to listen on USB, enter adb usb.

http://developer.android.com/guide/topics/usb/index.html

 

————————————————————

補充

Root手機的用戶有福了 🙂

可以不用像是上面這麼複雜喔

Google Market裡面有提供

類似這種Wifi ADB的這種軟體唷

只是需要Root………不知道這是啥的就跳過這段吧

 

adbWireless (Widget version)

https://market.android.com/details?id=siir.es.adbWireless

WiFi ADB

https://market.android.com/details?id=com.ttxapps.wifiadb

 

其中我最喜歡這套

ADB over WIFI Widget
Mehdy Bohlool

https://market.android.com/details?id=bohlool.net.wifiadb

他安裝完沒有甚麼變化和圖示

 

要去桌面 menu >  小工具

然後找到ADB over WIFI Widget

就會有個圖示在你的桌面摟

 

 

電腦這端用上述的

adb connect 192.168.1.3

(192.168.1.3是那隻上面看到的IP)

就可以連上去成為一個裝置摟

 

不用的時候就按一下小綠人就又回復正常摟

 

 

這樣就可以遠端桌面,遠端debug摟

是不是粉方便呢?

 

 

 

 

 

Desire HD 進入安全模式

不知道有沒有人跟我一樣

不小心進入HTC製作的安全模式?

 

進入方法如下

手機重開機,手機震動後

會出現白色畫面中綠色HTC字樣的畫面

這時,等待其載入到出現

小標題quietly brilliant的字樣

的附近

長按音量下鍵 (可以多按幾次,每次都長按即可)

如果成功進入的話,手機會震動一下

而且左下角會寫著安全模式

 

官方寫法是這樣

在安全模式中,所有協力廠商的應用程式都無法執行,所以您可以成功地啟動手機,以解除安裝最近安裝的應用程式,或可能導致手機無法正確啟動的應用程式。

我的解釋是,自行安裝的程式 (所有不是燒在Rom裡的程式),都無法執行

 

離開安全模式,只要重開機即可

[教學] Windows 7 (x64) IME輸入法整合器的手寫版

2011-05-04 07 11 33.png

這篇只有在64位元Windows 7Vista才會有這個問題,32位元的是正常的

(以下有部份畫面是用英文版Win 7示範,但筆者很確定繁體中文的Win 7是可以使用的)


大家如果用過Office 2007 系列的產品

不難知道微軟的新注音輸入法有一個手寫辨識的功能

當你找不到字音要怎麼打的時候,使用滑鼠寫字讓系統去辨識

 

在這

工具選項 > 輸入法整合器

2011-05-04 07 10 25.png

就會看到這個問題畫面

2011-05-04 07 11 33.png

如果你是像筆者一樣是64位元Windows 7的話,就會發現

咦?手寫介面怎麼不見了?

 


 

問題的修正方法

 

按Win key + R,就會有傳統的執行畫面

打入cmd

2011-05-04 07 19 48.png

 

複製以下指令

%systemroot%system32regsvr32.exe "%systemroot%System32IMEIMETC10appletsIMTCCAC.dll"
%systemroot%SysWOW64regsvr32.exe "%systemroot%SysWOW64IMEIMETC10appletsIMTCCAC.dll"

 

這裡是要重新註冊IMTCCAC.dll,因為IMTCCAC.dll有分64位元和32位元

所以要依序在system32和SysWOW64的地方做重新註冊DLL

 

輸入完畢的畫面會像這樣,會依序跳出二個註冊成功的對話框

2011-05-04 07 21 20.png

另外也要用登錄檔修正

 

COPY下列文字將它存成ChtImePad64.reg

(可能要先開啟副檔名才能修改副檔名)


Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}]
@="TC IME7 Handwriting Applet"

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}Implemented Categories]

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}Implemented Categories{E081E1D6-2389-43CB-B66F-609F823D9F9C}]

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}InprocServer32]
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,
  00,5c,00,53,00,59,00,53,00,54,00,45,00,4d,00,33,00,32,00,5c,00,49,00,4d,00,
  45,00,5c,00,69,00,6d,00,65,00,74,00,63,00,31,00,30,00,5c,00,61,00,70,00,70,
  00,6c,00,65,00,74,00,73,00,5c,00,69,00,6d,00,74,00,63,00,63,00,61,00,63,00,
  2e,00,64,00,6c,00,6c,00,00,00
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}ProgID]
@="IMEPad.HWR.TCIME7"

[HKEY_CLASSES_ROOTCLSID{C0AA878E-97A5-44df-B7EF-2E732F7B2FEC}VersionIndependentProgID]
@="IMEPad.HWR.TCIME"


然後執行剛剛存的ChtImePad64.reg

2011-05-04 07 25 07.png

需要Administrator的權限才能夠繼續

如果UAC提示關掉的話就會像我這樣,按Yes繼續

2011-05-04 07 26 08.png

修改登錄成功

2011-05-04 07 26 58.png  

 

 

然後再回到輸入法整合器做修正

按下那整合器的小圖示 > 輸入法選項 > 設定

 

2011-05-04 07 13 46.png

然後你會看到手寫識別其實是有載入的

我們將它移除,按下關閉之後,

2011-05-04 07 14 52.png

然後再重新新增回去,重新載入

2011-05-04 07 15 31.png

這時你的輸入法整合器就會多出一個小圖示

2011-05-04 07 16 17.png

 

 

然後…..

 

 

就可以像32位元一樣,正常的使用手寫識別的功能了

2011-05-04 07 16 26.png

 

 

參考資料

http://www.hkepc.com/forum/viewthread.php?tid=1368387

http://www.hkepc.com/forum/viewthread.php?tid=1320778

http://www.youtube.com/watch?v=lyVBPjiCB4M

http://www.facebook.com/note.php?note_id=337682464204

[Fedora12-14] 設定遠端桌面連線 (rdp)

大家都有用過WIndows的遠端桌面連線吧

其名稱叫做Remote Desktop Protocol (RDP)

是一個網路協定,微軟WinXP之後的都有他的Client可以說是非常方便

而Linux呢?沒有原生的RDP的Server

但有VNC,而且有個xrdp的軟體能夠『透過rdp協定』來連線vnc

設定上有一點點小複雜,不過應該還好

————————————————–

安裝vnc server

我之前也有寫過VNC的架設,大家可以參考一下

http://j796160836.pixnet.net/blog/post/20787531

這裡的設定跟之前寫的差不多,避免變成二篇文章後

大家設定不起來,還是簡單節錄一下

 

這裡我們用的是tightvnc server

直接下yum指令安裝

[root@localhost ~]# yum install vnc-server -y

 

安裝完畢後就可啟動服務

[root@localhost ~]# /etc/init.d/vncserver start

然後開一個user來做VNC連線登入的帳號,本例是vncDesktop

(也可以跟本機帳號一樣,如果是這樣就省略開帳號的動作)

[root@localhost ~]# useradd vncDesktop

設定密碼

[root@localhost ~]# passwd vncDesktop

如果是root登入,需要切換到該使用者,來設定vnc使用的密碼

[root@localhost ~]# su vncDesktop

設定vnc使用的密碼(這裡的密碼到時候就會是遠端桌面使用的密碼)

[vncDesktop@localhost ~]# vncpasswd

再切換回root

[vncDesktop@localhost ~]# su –

 

這裡需要設定哪個使用者需啟用vnc服務

[root@localhost ~]# vi /etc/sysconfig/vncservers

解除註解並修改

VNCSERVERS=”2:vncDesktop
VNCSERVERARGS[2]=”-geometry 800×600 -nolisten tcp -localhost”

 

 

2冒號  不可省略,指的是Terminal的號碼
VNCSERVERARGS註解要拿掉

 

 

然後重啟vnc服務,套用新設定

[root@localhost ~]# /etc/init.d/vncserver restart

這時候,如果沒有提示錯誤的話

應該會跑vnc在5902的port

這個port防火牆可以不開,也不需要開,因為我們要用xrdp去連vnc

 

————————————————–

 

安裝xrdp

 

這裡還是要再三描述觀念

xrdp是基於vnc服務的服務,所以vnc的架設和設定不能省略

架設方法在上文

 

xrdp安裝一樣直接下yum指令安裝

[root@localhost ~]# yum install xrdp -y

 

安裝完畢後就可啟動服務

[root@localhost ~]# /etc/init.d/xrdp start

 

防火牆對應做修改,打開3389的port

[root@localhost ~]# vi /etc/sysconfig/iptables

加一行文字,打開3389的port

-A INPUT -m state –state NEW -m tcp -p tcp –dport 3389  -j ACCEPT

 

然後記得重啟防火牆,讓他套用新設定

[root@localhost ~]# /etc/init.d/iptables restart

 

 

————————————————–

我們需要修改startwm.sh修改啟動X Window的的順序

因為Fedora來說預設只有裝gnome

所以我們需要把它改到優先(橘色為修改)

[root@localhost ~]# vi /etc/xrdp/startwm.sh

#!/bin/sh -l

# change the order in line below to run to run whatever window manager you
# want, default to kde

SESSIONS=”gnome-session startkde startxfce4 xterm”

# change PATH to be what your environment needs usually what is in
# /etc/environment
#PATH=”/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games”
#export PATH=$PATH

# for PATH and LANG from /etc/environment
# pam will auto process the environment file if /etc/pam.d/xrdp-sesman
# includes
# auth       required     pam_env.so readenv=1
#. /etc/environment
#export PATH=$PATH
#export LANG=$LANG

# for bash profile
#. ~/.bash_profile
#. /etc/profile

for WindowManager in $SESSIONS
do
  which $WindowManager
  if test $? -eq 0
  then
    echo “Starting $WindowManager”
    $WindowManager
    exit 0
  fi
done

exit 1

————————————————–

接下來,在實際測試的時候會出現一個很奇怪的現象

就是xrdp之後,滑鼠正常,但鍵盤就是無法使用

無法打入帳號密碼

後來發現是因為是鍵盤配置檔出問題

因為

在繁體中文的環境下,xrdp會抓不到對應的鍵盤配置檔

 

所以我們必須修正這個問題

以我的為例,xrdp的設定檔有這些

[root@localhost ~]# ls /etc/xrdp/

km-0004.ini  km-0409.ini  km-0419.ini  sesman.ini   xrdp.sh      
km-0404.ini  km-040c.ini  km-041d.ini  startwm.sh   
km-0407.ini  km-0410.ini  rsakeys.ini  xrdp.ini     

請注意這些km-xxxx.ini這些就是鍵盤配置檔

km-0409.ini 這個是英文的鍵盤配置

以下列出一些常看到的語系代碼,如果沒有的話請到以下網址去參考

http://xrdp.sourceforge.net/documents/keymap/rfc1766.html

 

“0004”=”zh;Chinese”
“0404”=”zh-tw;Chinese (Taiwan)”
“0804”=”zh-cn;Chinese (China)”
“0C04″=”zh-hk;Chinese (Hong Kong SAR)”
“1004”=”zh-sg;Chinese (Singapore)”

“0409”=”en-us;English (United States)”
“0809”=”en-gb;English (United Kingdom)”
“0C09″=”en-au;English (Australia)”
“1009”=”en-ca;English (Canada)”
“1409”=”en-nz;English (New Zealand)”
“1809”=”en-ie;English (Ireland)”
“1C09″=”en-za;English (South Africa)”
“2009”=”en-jm;English (Jamaica)”
“2809”=”en-bz;English (Belize)”
“2C09″=”en-tt;English (Trinidad)”

 

以繁體中文0404為例,因為我們的鍵盤配置跟英文一樣

所以只要打上這個指令就行了

[root@localhost ~]# cp /etc/xrdp/km-0409.ini /etc/xrdp/km-0004.ini

[root@localhost ~]# cp /etc/xrdp/km-0409.ini /etc/xrdp/km-0404.ini

其他鍵盤方面沒講到的地方都在這:

http://xrdp.sourceforge.net/documents/keymap/newkeymap.html

 

————————————————–

最後,測試成功後,就可以將它設定為開機自動啟動

[root@localhost ~]# chkconfig xrdp on

[root@localhost ~]# chkconfig vncserver on

————————————————–

參考資料

http://hpclab.cs.pu.edu.tw/wiki/index.php/Xrdp#.E9.8D.B5.E7.9B.A4.E9.8C.AF.E4.BA.82

http://chip.twbbs.org/2009/06/xrdpubuntu-904.html

[Android] 使用HTTP的POST方式和網頁表單溝通

 

2011-04-21 02 04 20.png  


2012.08.13版主回覆:

底下好多留言都詢問,奇怪?怎麼模擬器上都出現文字
然後網頁上沒出現?

不要再相信沒有事實根據的說法了 (大誤
不要再說沒有小弟不才,沒有爬文 

請移步至新版:

http://j796160836.pixnet.net/blog/post/30577968

個人還是建議從本篇看起,概念比較清楚


 

 最近常常被問到這些問題

Android要怎麼接MySQL資料庫呀? MySQL在網路上

Android怎麼接上雲端的資料庫?

Android怎麼傳送表單內容?

 

這些答案都在這裡

網路上的資料庫,不太容易,也不建議直接與資料庫做溝通

因為涉及到資訊安全的東西

 

 

可以用網頁來做中間的介面,讓二者產生關聯

做類似WebServices的東西
(雖然不是真正的WebServices,但其角色是類似的)

 


伺服器端

你可以簡單寫個印字串的程式,如果收到POST的封包

就印出其內容

如果是PHP可能這樣寫

<?php

        //宣告utf-8的編碼

        header("Content-Type:text/html; charset=utf-8");

        $data=$_POST[‘data’];

        echo "data=".$data;

?>

把寫好程式,取名httpPostTest.php

把他擺到htdoc底下 (windows)

或是/var/www/ (ubuntu)

或是/var/www/html (Fedora, Cent OS)

用ASP可能這樣寫

<%@ LANGUAGE=VBScript CodePage=950%>
<%
data=request("data")
response.write "data="&data
%>

不管如何,請照你的伺服器語言撰寫

 


Android手機端

 

可以用範例程式碼來解決問題

這些範例仿間找的到

因為過於複雜,所以我又重新整理了其範例給大家看

 

關鍵程式碼不到5行,但重點是在於你對Android的UI介面認識與否

和動態網頁的語言的熟練度

 

 


照慣例,文字要放在string.xml裡

/res/values/string.xml

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

<resources>

    <string name="app_name">httpPostTest</string>

    <string name="help_txt">請輸入文字以便使用POST傳送:</string>

    <string name="txt_message_hint">請輸入文字</string>

    <string name="send">送出</string>

</resources>


看一下Layout檔

/res/layout/main.xml

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/help_txt"

    />

    <EditText

    android:id="@+id/txt_message"

    android:hint="@string/txt_message_hint"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

   />

   <Button

   android:id="@+id/send_btn"

   android:text="@string/send"

   android:layout_width="fill_parent"

   android:layout_height="wrap_content"

   />

</LinearLayout>

 

這裡沒甚麼特別,就是一個EditText來讓使用者能打入資料

然候一個按鈕讓系統傳送封包到寫死的網址路徑

 


程式碼要上了

main.java

 

package com.J_Test.httpPostTest;

 

/*

 * ====httpPostTest範例====

 * 1. 請先確認Apache有沒有正確執行

 * 2. 放入以下PHP代碼到htdoc資料夾中(或是/var/www/)等路徑

 *

 

 <?php

 //宣告utf-8的編碼

 header("Content-Type:text/html; charset=utf-8");

 $data=$_POST[‘data’];

 echo "data=".$data;

 ?>

 

 *

 * 3. 修改uriAPIIP和檔案名稱為正確 (請用電腦對外之IP)

 * (不可用127.0.0.1因為Android手機上也有本機位址)

 *

 */

 

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

 

import org.apache.http.HttpResponse;

import org.apache.http.NameValuePair;

import org.apache.http.client.ClientProtocolException;

import org.apache.http.client.entity.UrlEncodedFormEntity;

import org.apache.http.client.methods.HttpPost;

import org.apache.http.impl.client.DefaultHttpClient;

import org.apache.http.message.BasicNameValuePair;

import org.apache.http.protocol.HTTP;

import org.apache.http.util.EntityUtils;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

 

publicclass main extends Activity implements OnClickListener

{

    private EditText txtMessage;

    private Button sendBtn;

    private String uriAPI = "http://192.168.1.3/httpPostTest.php";

 

    @Override

    publicvoid onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

        txtMessage = (EditText) findViewById(R.id.txt_message);

        sendBtn = (Button) findViewById(R.id.send_btn);

 

        if (sendBtn != null)

        {

            sendBtn.setOnClickListener(this);

        }


    }

 

    @Override

    publicvoid onClick(View v)

    {

        if (v == sendBtn)

        {

            String msg = null;

            if (txtMessage != null)

            {

                msg = txtMessage.getEditableText().toString();

                String result = sendPostDataToInternet(msg);

 

                // 印出網路回傳的文字

                if (result != null)

                    Toast.makeText(this, result, Toast.LENGTH_LONG).show();

            }

        }

    }

 

    private String sendPostDataToInternet(String strTxt)

    {

        / 建立HTTP Post連線 /

        HttpPost httpRequest = new HttpPost(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 = new DefaultHttpClient()

                    .execute(httpRequest);

            / 若狀態碼為200 ok /

            if (httpResponse.getStatusLine().getStatusCode() == 200)

            {

                / 取出回應字串 /

                String strResult = EntityUtils.toString(httpResponse

                        .getEntity());

 

                // 回傳回應字串

                return strResult;

            }

 

        } catch (ClientProtocolException e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        } catch (IOException e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        } catch (Exception e)

        {

            Toast.makeText(this, e.getMessage().toString(), Toast.LENGTH_SHORT)

                    .show();

            e.printStackTrace();

        }

        returnnull;

    }

 

}

 

 


最後是AndroidManifest.xml

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.J_Test.httpPostTest"

      android:versionCode="1"

      android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".main"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

    </application>

    <!– 這裡加入可以存取網路的權限 –>

    <uses-permission android:name="android.permission.INTERNET" />

</manifest>

 

這裡很重要也很容易疏忽

除了Activity要在這裡註冊外

能對外上網的權限也在這裡註冊

如果遇到

WARN/System.err(503): java.net.SocketException: Permission denied

就該發現權限少了這一項

<uses-permission android:name="android.permission.INTERNET" />

另一個權限也常用,但仿間書常常會遺漏

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

就是能夠存取手機記憶卡的權限

 

 


這樣有看懂嗎?

 

主要重點在這裡

  / 建立HTTP Post連線 /

  HttpPost httpRequest = new HttpPost(uriAPI);

這個HttpPost是主要的Class名,這裡要填入存取的網址

 

然後

 /*

  * Post運作傳送變數必須用NameValuePair[]陣列儲存

  */

  List<NameValuePair> params = new ArrayList<NameValuePair>();

  params.add(new BasicNameValuePair("data", strTxt));

 

使用系統指定的資料格式BasicNameValuePair

BasicNameValuePair在new的時候裡面為二個字串,一個是名稱,一個是值

這裡用"data"當名字,值就是剛剛讓使用者打的資料

 

  / 發出HTTP request /

  httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

的  HTTP.UTF_8 可以指定編碼格式,不過要跟伺服器端相同(照我範例走的話是不用動)



2011-04-21 02 18 45.png  

其實這個Android其實是跟以下網頁的功能是相同的

有些值你可以對照看看,相關對照的字詞都用顏色標明了

可以將它另存到httpPostTest.htm

 

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;

<html xmlns="http://www.w3.org/1999/xhtml”&gt;

<head>
<meta http-equiv="Content-Language" content="zh-tw" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF_8" />
<title>httpPostTest</title>
<head></head>
<body>
請輸入文字以便使用POST傳送:<br />
<form method="POST" action="http://192.168.1.3/httpPostTest.php">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input name="Submit1" type="submit" value="送出" /><br />
</form>
</body>
</html>

 


延伸

其實網頁大多喜歡把很多功能做在一個檔裡,就是用一個隱藏值來判斷現在進行到那個階段

本例用op當階段的旗標

 

PHP版:

請輸入文字以便使用POST傳送:<br />
<form method="POST" action="<?php echo $_SERVER[‘PHP_SELF’]; ?>">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input type="hidden" name="op" value="showValue" />
<input name="Submit1" type="submit" value="送出" /><br />
</form>

 

ASP版:

 

請輸入文字以便使用POST傳送:<br />
<form method="POST" action="<%=Request.ServerVariables("PATH_INFO")%>">
<input type="text" name="data" size="20" value="請輸入文字" /><br />
<input type="hidden" name="op" value="showValue" />
<input name="Submit1" type="submit" value="送出" /><br />
</form>


2011-04-21 02 05 40.png

   2011-04-21 02 17 35.png  

 

2011-04-21 02 25 29.png  

 

不過還是再三的提醒

範例程式碼很簡陋,指是要讓大家看懂其中的語法

真正寫程式使用的時候

 

要記得在伺服器判斷輸入的型別

更不要直接讓表單直接下SQL指令

 

怕被資料隱碼攻擊(SQL Injection)

 

這是很危險低~~~~

 

 

參考資料
Google Android SDK開發範例大全 佘志龍等人著
悅知文化

[Android] 從新建專案看版面Layout設計

這部分給剛入門的Android新手看的,寫的不好請多包涵

 

一個Android手機程式中

一個畫面,包含可能程式化的內容,就可以稱為一個Activity

定義不重要,這只是我的解釋而已

至少一個Activity會抓一個Layout檔,來顯示版面

才能做之後的事情

 

———————————————————–

 

而Android的版面Layout基本上都是用XML做定義的

XML概念跟HTML有那麼一點點相似,但不太一樣

XML自訂性較高,但也較嚴謹,只要出錯整的檔都會讀不出來

基本上原則就是

  • Node要成雙成對,沒有結束符號要加上 / 符號
  • Root Node素只能有一個

這部分就不再贅述

 

 

這是剛新建專案的Layout

layout.xml,路徑在res/layout/main.xml

新開的檔會以建立的Activity做名稱,一個Activity可以有一個Layout檔,也可以用人家的(自己沒有)

<?xml version=“1.0” encoding=“utf-8”?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:orientation=“vertical”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:layout_width=“fill_parent”

    android:layout_height=“wrap_content”

    android:text=“@string/hello”

    />

</LinearLayout>

 

 

首先看看Layout檔

HelloWorld只會有二個控制項,也是首先會接觸到的

TextView 

手機螢幕部分只要眼睛看的見的幾乎都是控制項,叫做View

有以下屬性

    android:layout_width  為控制項的寬度

    android:layout_height  為控制項的高度

單位可以填dip,也是最常用的,就是單位螢幕點(相對長度),依解析度和螢幕尺寸不同而會有不同

也可以填像素px啦 (這樣會失去自動調整的能力,官方不建議)

也可以填以下屬性:

    “fill_parent”    代表填滿父控制項,在這裡通常是指撐滿螢幕(寬度或是高度)

  “wrap_content” 就是指依照你內容有多少就給你多少(寬度或是高度)

android:text  就是要顯示的文字拉

 

怎麼沒有看到  Hello World, main!   呢?

原來文字存到string.xml裡了

“@string/hello” 這樣就是在指,去string.xml找到名為hello的字串,當然也可以直接打上去拉,只是不建議這樣做,以後有關多國語言會提到

 

 

這裡是string.xml,路徑在res/value/string.xml

<?xml version=“1.0” encoding=“utf-8”?>

 

<resources> 

    <string name=“hello”>Hello World, main!</string>

    <string name=“app_name”>Hello World test</string>

</resources> 

 

之後會提到android:id的部分,這裡先不提

 

———————————————————–

再來講

LinearLayout 

這種Layout的家族統稱稱為ViewGroup

ViewGroup可以想成各種View的群組,有以下幾種

  • AbsoluteLayout
  • RelativeLayout
  • FrameLayout
  • LinearLayout

通常也最常用的就是LinearLayout,原因無他,只是方便好用

LinearLayout只會做一件事,指定一個方向(垂直或是水平)

然後不管控制項有多大,全部照樣往下(或往右)排排站

 

在這裡LinearLayout有以下屬性

xmlns:android=“http://schemas.android.com/apk/res/android”   這句話絕對不能省略,放在最外層的那控制項即可

依據XML的特性,要去指定一些標籤的定義,就像法條才會有憑有據

android:orientation=“vertical”   就是排列方向為垂直(由上而下)

android:orientation=“horizontal”   就是排列方向為水平(由左而右)

 

———————————————————–

講一下

RelativeLayout 

好了

在Layout檔看起來如下:

 

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android” 

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

 

</RelativeLayout>

看起來跟LinearLayout沒啥不同

但多的特性就多了

首先,他沒有android:orientation可以用,因為他是用控制項的相對位置去編排的

如果控制項沒有設定那些多出來的參數,很有可能會發生二控制項重疊

裡面的控制項屬性會多出二種類型的屬性

  • 邊框位置
  • 跟另一個控制項的相對位置

屬性有以下:

 

android:layout_alignLeft 

android:layout_toRightOf 

android:layout_below 

android:layout_above 

android:layout_alignParentLeft 

android:layout_alignParentTop 

android:layout_alignParentRight 

android:layout_alignParentBottom 

android:layout_centerInParent 

 

 

邊框位置

先有一個控制項位置做絕對位置,才能做相對位置的判定嘛

以word的文字編排方式可以很直覺的理解

android:layout_alignParentLeft  靠左對齊,(吸附邊框左邊)

 

android:layout_alignParentTop   靠上對齊,(吸附邊框上方)

android:layout_alignParentRight   靠右對齊,(吸附邊框右邊)

android:layout_alignParentBottom   靠下對齊,(吸附邊框下方)

android:layout_centerInParent    置中,(計算放在正中間)

這類型就是以RelativeLayout的邊框做位置,做對齊

 

而另一種就是以別人的控制項位置做為自己的控制項位置

 

android:layout_toLeftOf       這在(等下要寫的控制項的名)的左邊

android:layout_toRightOf        這在(等下要寫的控制項的名)的右邊

android:layout_below        這在(等下要寫的控制項名)的下面

android:layout_above       這在(等下要寫的控制項名)的上面

 

這個等下要寫控制項的名稱,很重要

控制項的順序也很重要

基本上,這個名子一定要再你的Layout上有提及

還有這個控制項名稱要在XML敘述上比現在這個控制項還要早出現

XML的Layout檔上基本上可以先寫靠左或靠右對齊的控制項敘述

才寫這種相對敘述

 

控制項在XML裡寫的順序很重要

—————————————————–

 

 

補充:FrameLayout 

 

FrameLayout可以想成是RelativeLayout的功能閹割版

 

RelativeLayout的部份

 

1. 能對齊View的框邊

例如:

android:layout_alignParentLeft  靠左對齊,(吸附邊框左邊)

或是

2. 設定二格View之間的排列關係

例如:

android:layout_toLeftOf       這在(等下要寫的控制項的名)的左邊

上面都提過了

 

 

FrameLayout只剩下

 

對齊View的框邊的功能

android:layout_gravity  來指定

如果在其中的View有二個設定成一樣的話呢

就會「依序」重疊上去

 

注意一點,只有RelativeLayoutFrameLayout 

才會發生控制項有重疊的現象

如果版面看似調不出來,可以檢查一下是否為二個控制項重疊

或是版面出界了

 

版面出界的狀況在初期很容易發生

 

像是LinearLayout 裡面有二個控制項

第一個控制項是  android:layout_width=“fill_parent”    android:layout_height=“fill_parent”

填滿全螢幕

第二個  android:layout_width=wrap_content    android:layout_height=wrap_content

這樣第二個一定出界的

 

設定上要小心

 

—————————————————–

所有的View和ViewGroup都可能需要android:id這東西

他會在Compile專案時會產生一個R檔,就是gen/你的package名稱/R.java

這個R檔會包含你的所有Layout上的所有id和string.xml上的名稱….等等內容,沒事別去動他

寫法如下

    android:id=“@+id/tv01”

這裡的@就是叫程式去R檔裡面找到代稱叫做tv01的id名稱

這裡的+號不能省略,代表的是我需要在R檔裡新增一個id名稱叫做

這個所有的Layout檔都適用,不同Layout裡的控制項id最好是要不一樣

在一個Layout檔中,控制項的id一定要不同

 

到時候程式可以用findViewById去依照這個id抓取其控制項

 

—————————————————–

底下寫一個LinearLayout的範例,改用RelativeLayout會怎麼寫

 

現在用LinearLayout來撰寫Layout

 

<?xml version=“1.0” encoding=“utf-8”?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:orientation=“vertical”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:id=“@+id/tv01”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text01”

    />

    <TextView 

    android:id=“@+id/tv02” 

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text02”

    />

    <TextView 

    android:id=“@+id/tv03”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text03”

    />

    <TextView 

    android:id=“@+id/tv04”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text04”

    />

    <TextView 

    android:id=“@+id/tv05”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text05”

    />

</LinearLayout>

 

 

—————————————————–

改用RelativeLayout會變成

 

 

<?xml version=“1.0” encoding=“utf-8”?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

    android:layout_width=“fill_parent”

    android:layout_height=“fill_parent”

    >

<TextView 

    android:id=“@+id/tv01”

    android:layout_alignParentTop=“true”

    android:layout_alignParentLeft=“true”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text01”

    />

    <TextView 

    android:id=“@+id/tv02” 

    android:layout_below=“@id/tv01”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text02”

    />

    <TextView 

    android:id=“@+id/tv03”

    android:layout_below=“@id/tv02”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text03”

    />

    <TextView 

    android:id=“@+id/tv04”

    android:layout_below=“@id/tv03”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text04”

    />

    <TextView 

    android:id=“@+id/tv05”

    android:layout_below=“@id/tv04”

    android:layout_width=“wrap_content”

    android:layout_height=“wrap_content”

    android:text=“Text05”

    />

</RelativeLayout>

 

 

 

 

android:orientation=“vertical”

[分享] Asus RT-N10+刷DDT-WRT之不專業分享文

我原本就有一顆無線AP了
是PCI的BLW-54MR

掛BT很多年機器也不會掛點
還蠻穩定的 

 

因為搬家,家裡隔間改變了

那台無線AP的訊號涵蓋有限(被二個鐵門和大牆檔住)

所以就去光華尋找一顆無線AP了

無意中找到這台Asus RT-N10+

 

網路上說,原廠rom很好設定

特色是

設定簡單,有三種mode可以選

傳統無線分享器、純無線AP、無線repeater

 

  1.  傳統無線分享器,不是我要的功能,所以跳過 (一般人都會只用這功能)

  2.  純無線AP,看起來我能用,WAN port插上網路線,收到dhcp封包,可以上網了
    但有線lan介面完全廢掉,失敗

  3.  無線repeater功能,只要是無線訊號都可以延伸,

不限定牌子跟款式,這功能真的很威

設定方式還蠻簡單的,接線連到web管理介面,

選好要放大的無線訊號

設定完成後,就可拔線,整台擺到你想擺的地方

最好是算一下入射角和反射角(開完笑的啦)

就是repeater擺的位置最好要有ok的無線訊號

才能去repeat傳到更遠的地方

我喬了幾個位子之後,無線連線訊號滿格,但就還是不能上網
(沒有足夠repeat的訊號)

所以先暫緩

 

 

目前看到的缺點

存檔要存很久,而且有時候會斷線

有事沒事呈昏睡狀態(像是當機一般)

要透過光碟附的尋找介面去尋找AP的IP

因為他有可能會跳

 

 


網路上再找找

這台是網友們口中說的CP值很高的ㄧ台強大router

怎麼說呢?

因為有第三方rom加持,DDT-WRT

解除封印

 

DDT-WRT這韌體我之前就有聽過

當紅的機子是DLINK DIR-300系列

便宜router,刷過以後變成高檔router

之前我也想嘗試,只是PCI系列的產品一概不支援

只有殘念

 

 

 

————————————————-

這次真的讓我見識到 DDT-WRT的威力了

我刷的版號

DD-WRT v24-sp2 (03/17/11) std – build 16454

 

可以從eko大大的最新版下載

在router database中可是沒有這版低

 

網址在這

http://www.dd-wrt.com/site/support/other-downloads?path=others/eko/BrainSlayer-V24-preSP2/12-24-10-r15962/Asus-RT-N10PLUS/#

(直接打網址進去好像看不到我看到的頁面,進去點BrainSlayer-V24-preSP2然後照以下路徑點選)

Path: Downloads › others › eko › BrainSlayer-V24-preSP2 › 2011 › 03-17-11-r16454 › Asus-RT-N10PLUS

2011-03-29 01 27 09.png  

 

怎麼刷?

真的有夠簡單

裡面有二個檔

factory-to-ddwrt.trx 是給原廠韌體刷成ddwrt使用

asus-rt-n10plus-ddwrt-webflash.bin  是給已經是ddwrt升級用的

 

所以當然是選factory-to-ddwrt.trx

在原廠畫面直接按更新韌體的功能上傳factory-to-ddwrt.trx這個檔

然後就靜待你的AP不會變成黑磚

 

 

等待値到顯示完成還不會跳下一個畫面的時候

手動刷新頁面就會看到摟

刷回去原廠韌體,亦然

擁有這麼好的韌體,除非需要送修

應該不會有人想刷回去吧 ㄎㄎ

 

 

裡面有很強大的功能,我還沒有全部玩會

聽說還有指令列模式(像是在設定cisco裝置類似)

我大概說幾個功能好了

除了NAT、有虛擬伺服器外(防火牆例外)

 

還有多個DHCP主機設定其範圍

內建VPN伺服器(PPTP,OpenVPN可能要刷另一版的rom)

vlan tagging管理,橋接bridge設定

防火牆VPN Passthrough設定

BGP、RIP2路由功能(這種功能我只在教科書上看過而已)

網路喚醒,定時重開機設定

Qos、Upnp設定

還有監控圖表

……………..等等很多等你去發掘

2011-03-29 01 45 30.png  

光是看到VPN Server就夠強大了吧

相同的功能大約要3xxx多的router才有呢

 

重點是,有繁中介面喔~~~

找到Administration -> Management

卷軸往下拉

接近尾巴有個Language Selection
就可以調整了

2011-03-29 01 53 14.png  

2011-03-29 01 28 51.png   

 


如何將WAN當做普通LAN port使用?

原文網址:

http://www.dd-wrt.com/wiki/index.php/WAN_Port

 

Note: Steps are true for firmwares current as of the author date of this article. v2.4, post SP2 firmwares. These steps were done with build 12307 (2009 06 17), widely regarded as stable. Other firmware builds of DD-WRT have the same or very similar steps.

  1. Open up the Web Interface to your DD-WRT Device
  2. Set WAN ‘Connection Type’ to Disabled.
  3. Down the Basic Setup page, the option WAN Port appears. Check the box ‘Assign WAN Port to Switch’.
  4. Save/Reboot

The WAN port is now the same as the other LAN ports.

 

  1.  先開啟網頁介面

  2.  到Basic Setup -> WAN Connection Type,設定成Disabled

基本設定 -> WAN 連接類型,設定成「關閉」

  1.  然後捲軸往下拉,有個

Assign WAN Port to Switch (將 WAN 端指定給交換器)  的勾勾,把它勾起來

  1. 存檔重啟機器

 

————————————————-

 

 

文後附記:

我想  RT-N10 plus  和  RT-N10

有點差異吧

所以我沒有刷 RT-N10  的韌體 (我拿的是RT-N10 plus)

理當刷機失敗會進入救援模式,聽說就可以反刷回去

心臟夠強的人可以試試

有成功再告訴我好消息

 

http://blog.xuite.net/librastw/3C/37393327 (這篇是給RT-N10的,非RT-N10 plus)


http://5i01.com/topicdetail.php?f=110&t=2005151&last=26730263

http://www.dd-wrt.com/wiki/index.php/What_is_DD-WRT%3F

http://5i01.com/topicdetail.php?f=110&t=1875971&p=1 (這篇是給DIR-300的)

http://tw.network01.net/modules/newbb/viewtopic.php?topic_id=129&forum=6

[Android] 多執行緒-Handler和Thread的關係

要寫Android,難懂的多執行緒一定要給他搞懂
在Android當中,如果做超過5秒被系統強制關閉
(收到Application not Responsed簡稱ANR)
onCreate()如果做超過10秒就會跳ANR

所以繁重的事情不能在onCreate()裡頭做

有沒有解決辦法?? 就是Thread 中文叫執行緒

搞不清楚?

 

用現實的例子說明好了

 

Thread ==>  做工的工人 

Runnable ==> 要做的工作事項 (工作說明書)

 

一般的Thread,工人請他來,指定工作給他做。做完就收工閃人回家

有一種Thread,他的性質比較不一樣

算是包月的那種特約駐點工人吧,要簽合約的(笑)

上班時間跟公務員一樣,就算沒事情做也要standby在那裡

這種工人他會有個經紀人幫他管要給他作的事

 

HandlerThread ==>  特約工人

Handler ==>  特約工人的經紀人

———————————————————————————-

回到程式,一般來說,Activity 執行的時候

會有個 UI Thread 或叫 main Thread
就是你程式本身原有的執行緒,管著畫面呈現…..等等事物

main Thread (或叫UI Thread)就是你的程式進入點

 

而main Thread,他也是個HandlerThread

可以給他一個Handler,做接收訊息之用

———————————————————————————-

(以下程式碼只是示意,要表達程式碼的邏輯概念

實際上在運行的時候,模擬器的畫面不會產生任何的變化

可以把它當範本使用,稍加修改)

 

 

package com.J_Test.HandlerAndThread;

 

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

 

publicclass main extends Activity {

    /** Called when the activity is first created. */

    //找到UI工人的經紀人,這樣才能派遣工作  (找到顯示畫面的UI Thread上的Handler)

    private Handler mUI_Handler = new Handler();

    //宣告特約工人的經紀人

    private Handler mThreadHandler;

    //宣告特約工人

    private HandlerThread mThread;

 

    @Override

    publicvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

 

       

        //聘請一個特約工人,有其經紀人派遣其工人做事 (另起一個有HandlerThread)

        mThread = new HandlerThread(“name”);

        //Worker待命,等待其工作 (開啟Thread)

        mThread.start();

        //找到特約工人的經紀人,這樣才能派遣工作 (找到Thread上的Handler)

        mThreadHandler=new Handler(mThread.getLooper());

       

       

        //請經紀人指派工作名稱 r,給工人做

        mThreadHandler.post(r1);

    }

   

    //工作名稱 r1 的工作內容

    private Runnable r1=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //做了很多事

           

            //請經紀人指派工作名稱 r,給工人做

            mUI_Handler.post(r2);

           

        }

    };

    //工作名稱 r2 的工作內容

    private Runnable r2=new Runnable () {

        publicvoid run() {

            // TODO Auto-generated method stub

           

            //………………………..

            //顯示畫面的動作

           

        }

    };

 

    @Override

    protectedvoid onDestroy() {

        super.onDestroy();

       

        //移除工人上的工作

        if (mThreadHandler != null) {

            mThreadHandler.removeCallbacks(r1);

        }

        //解聘工人 (關閉Thread)

        if (mThread != null) {

            mThread.quit();

        }

    }

}



—————

2011.10.17更新新版,請前往:

http://j796160836.pixnet.net/blog/post/29895257

[Android] 安裝Android SDK出現JDK not found.

安裝Android的開發環境,我裝了不下數十次

 

先安裝Java SE Development Kit (JDK)

然後接著解壓縮Eclipse,安裝Android Development Tools (ADT)

然後安裝Android SDK….

咦?我眼睛沒花吧?  明明就有裝JDK
安裝程式就跟我講沒有?

 

JDK not found 

關於安裝Android SDK裝不起來的問題

 

大概是安裝程式的bug吧,64位元電腦安裝64位元的JDK就會有這種情況

網友有找到一種解決方式

就是按Back,然後再按Next

然後就可以繼續裝了

 

參考

http://stackoverflow.com/questions/4382178/android-sdk-installation-doesnt-find-jdk

 

 

[php]UTF-8的fgetcsv函數

Microsoft的Excel有個很奇怪的怪僻
就是xls、xlsx裡面的文字是用UTF-8儲存

但如果另存新檔成csv時,會被降轉成Big5

有個方法可以避免這問題

直接選取資料,Ctrl+C做複製,直接在記事本之類的地方貼上
你會發現資料之間會用tab隔開

再用正規表達式,將  \t  取代成 , 
(tab字元取代成逗點) 

就可以用以下程式做匯入了

用法跟普通的fgetcsv一樣

但不能用以下程式寫成讀取tsv的程式

當遇上二個tab時(也就是有欄位是空的)

就會判斷錯誤喔,注意注意

 

//支援UTF-8的fgetcsv函數
function __fgetcsv(&$handle, $length = null, $d = “,”, $e = ‘”‘)
{
    $d = preg_quote($d);
    $e = preg_quote($e);
    $_line = “”;
    $eof=false;
    while ($eof != true)
    {
        $_line .= (empty ($length) ? fgets($handle) : fgets($handle, $length));
        $itemcnt = preg_match_all(‘/’ . $e . ‘/’, $_line, $dummy);
        if ($itemcnt % 2 == 0)
            $eof = true;
    }
   $_csv_line = preg_replace(‘/(?: |[ ])?$/’, $d, trim($_line));

    $_csv_pattern = ‘/(‘ . $e . ‘[^’ . $e . ‘]*(?:’ . $e . $e . ‘[^’ . $e . ‘]*)*’ . $e . ‘|[^’ . $d . ‘]*)’ . $d . ‘/’;
    preg_match_all($_csv_pattern, $_csv_line, $_csv_matches);
    $_csv_data = $_csv_matches[1];

    for ($_csv_i = 0; $_csv_i < count($_csv_data); $_csv_i++)
    {
        $_csv_data[$_csv_i] = preg_replace(“/^” . $e . “(.*)” . $e . “$/s”, “$1”, $_csv_data[$_csv_i]);
        $_csv_data[$_csv_i] = str_replace($e . $e, $e, $_csv_data[$_csv_i]);
    }
    return empty ($_line) ? false : $_csv_data;
}