2011年12月25日 星期日

Android學習_建立程式內(application)的全域變數(Global Variable)

在Activity間傳遞變數可以利用Bundle的方式來處理,但是如果當Activity太多,又每一個都可能運用到相同的參數,如每一個頁面都要去判斷登入者來決定可使用的功能,這時候可能會將值儲存在所謂的全域變數。

步驟:
1. 建立繼承於Application的類別

package tw.com.ola;
import android.app.Application;
public class GlobalVariable extends Application {
public String UserID = "";
}
說明:
*必須要繼承Application
*可以自行撰寫getter或setter,就跟一般的類別檔一樣
*上述程式碼僅建立一個外部可讀寫的變數UserID

2. 設定AndroidManifest

<application android:name=".GlobalVariable" android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Activity_CheckAndroid" android:label="@string/Activity_CheckAndroid_Title" android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
說明:
*一般AndroidManifest中有一個application標籤,原本沒有android:name屬性,將第一步驟建立的類別檔加入,例:android:name=".GlobalVariable"。

3. 將值放入與將值讀出

//放入
GlobalVariable globalVariable = (GlobalVariable)context.getApplicationContext();
globalVariable.UserID = key_UserID;

//讀出
GlobalVariable globalVariable = (GlobalVariable)context.getApplicationContext();
String UserID = globalVariable.UserID;
說明:
*如此就可以將各個Activity都需要的變數,進行儲存與讀取的動作。

2011年12月20日 星期二

iOS_於XCode4.2 Empty Application建立ESRI iOS開發環境

如果使用XCode4.2版在建立新專案的時,就不會出現ArcGIS的template,所以可能要自己建立相關的環境(或許過一陣子就有template可以用),既然要建立環境當然就是從Empty Application開始最有意義。

步驟:
1. 建立Empty Application專案

2. 取個名字,將該專案建立起來。

3. 加入ArcGIS library(於專案Build Phases內的Under the Link Binary with Libraries按“+”鍵),ArcGIS library並不在預設之內所以要點選“Add Other...”(預設位置:${HOME} /Library/SDKs/ArcGIS/iOS.sdk/usr/local/lib)。預設${HOME} /Library/是隱藏的資料夾,必須在command line輸入“chflags nohidden ~/Library/”,完成後${HOME} /Library/其實叫做“資源庫”。

4. 因為ArcGIS的library有使用到一些預設的framework與library,所以空專案必須要將其內容都加進去。(資料來源)
********************************************************
CoreGraphics.framework
CoreLocation.framework
Foundation.framework
QuartzCore.framework
UIKit.framework
CoreText.framework (dependency introduced at v1.8)
libstdc++.dylib (dependency introduced at v1.8)
MediaPlayer.framework (dependency introduced at v2.0)
MobileCoreServices.framework (dependency introduced at v2.0)
libz.dylib (dependency introduced at v2.1)
Security.framework (dependency introduced at v2.1)
********************************************************
連同上一步驟加上去的共12項。

5. 設定Build Setting(搜尋Other Linker Flags增加-all_load與-ObjC)

6. 設定Build Setting(搜尋User Header Search輸入$(HOME)/Library/SDKs/ArcGIS/iOS.sdk/usr/local/include/**)

7. 都設定完成後,就可以先執行一下,看是否有跳出錯誤。

8. 接下來就可以測試是否可以正確接到ESRI的Map Service
h檔

#import
#import "ArcGIS.h"
#define kTiledMapServiceURL @"http://your url/ArcGIS/rest/services/MapServer"

@interface AppDelegate:UIViewController {
AGSMapView *_mapView;
}
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, retain) AGSMapView *mapView;
@end


m檔

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize mapView = _mapView;

-(void) initApp
{
CGRect appRect = [[UIScreen mainScreen] applicationFrame];
_mapView = [[AGSMapView alloc] initWithFrame:appRect];
[self.window addSubview:_mapView];

AGSTiledMapServiceLayer *tiledLayer = [[AGSTiledMapServiceLayer alloc] initWithURL:[NSURL URLWithString:kTiledMapServiceURL]];
[self.mapView addMapLayer:tiledLayer withName:@"Tiled Layer"];

[tiledLayer release];

AGSSpatialReference *sr = [AGSSpatialReference spatialReferenceWithWKID:102443];
double xmin, ymin, xmax, ymax;
xmin = 281082;
ymin = 2739078;
xmax = 341217;
ymax = 2791975;

// zoom to the United States
AGSEnvelope *env = [AGSEnvelope envelopeWithXmin:xmin ymin:ymin xmax:xmax ymax:ymax spatialReference:sr];
[self.mapView zoomToEnvelope:env animated:YES];
}

-(void)dealloc
{
[_mapView release];
[_window release];
[super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self initApp];
[self.window makeKeyAndVisible];
return YES;
}

9. 都完成後,可以執行看看效果。


如此我們就可以從一個完全空白的專案到一個TiledMapService讀進來。

2011年12月18日 星期日

巨龍之魂_死亡之翼的狂亂 KO

經過發呆→秒滅→發呆→秒滅→發呆→秒滅→發呆→秒滅,終於在忘記開英勇的狀況下看到了動畫!

感謝:阿龍、飛魚、辰藍、飆魔、真影、小乾乾、KAKA、洛琪、嘉嘉、我!


終於不是我是關鍵了! @O@

2011年12月15日 星期四

SQL Spatial學習_利用既有數字欄位計算空間欄位

若在資料表中已有坐標資料,就可以利用其直接計算空間欄位。

語法:
update CPDATA SET Shape =geometry::STPointFromText ('POINT('+ cast(E as varchar) +' '+ cast(N as varchar) +')',102443)

iOS學習_ESRI iOS SDK download and run MapViewDemo

等待很久的MacBook Pro終於在星期二到貨,真是喜憂參半,喜的是在課程結束前到貨,憂的是也沒有別的理由說沒辦法測試了。首先要完成的就是安裝開發環境,並進行初步測試。

所以安裝完XCode後,接下來就是ESRI iOS SDK的安裝與MapViewDemo的執行。

1. 下載ESRI iOS SDK(位置)

*下載必須要先註冊為會員。

2. 安裝ESRI iOS SDK
目前下載的檔案為AGSAPIiOSV21.pkg,安裝很簡單幾乎不用進行什麼設定。


3. 執行MapViewDemo範例。下載完成後可以到ArcGIS Resource Center來看各項說明文件,於ArcGIS API for iOS/Getting Started/Using the Samples(網址)內有提到在安裝SDK時會附帶一個最基本的範例(MapViewDemo)。

並且提到該安裝位置為:${HOME}/Library/SDKs/Samples/MapViewDemo,找資料夾的方法為在桌面點選上面的:前往/ 前往檔案夾,並輸入~/Library/SDKs/Samples/MapViewDemo


4. 執行MapViewDemo
點擊專案檔就可以直接看到接著ESRI地圖服務的簡單範例。


接下來就是要開始測試基礎功能與實機的安裝,不知道要到何年何月 lol

2011年12月12日 星期一

jQuery筆記_拆解JSON

有時候我們所得到的JSON可能不會很單純的是下面這樣的格式。

{"A":"1","B":"2"}

有可能得到的是:

{
"Name" : "shi fu",
"Aliases" : {
"AName" : "ola"
},
"Item" : [
{
"name" : "location",
"type" : "esri",
"alias" : "ola",
"length" : 10
}
],
"Object" : [
{
"attributes" : {
"Name" : "ola wang"
}
}
]
}


如果我們使用:

$.each(response, function (key, val) {
alert(key);
alert(val);
}
就可以看到Aliases與Object後面跳出[object object],原因是有些val並非單一的數值,而是陣列型態。

所以如果我們需要取得Object裡面的attributes內的第一個名字"ola wang"

$.each(response, function (key, val) {
if (key == "Object") {
var Name = val[0].attributes["Name"];
}
});

jQuery除錯_訪問不同網域之服務出現「No Transport」錯誤

最近持續在一些"接近尾聲"的案子打轉,其中有一個案子幾乎都要使用javascript來處理,對於js不太靈光的我當然遇到很多問題,其中一個是使用ajax()去呼叫其他網域服務時會出現No Transport的錯誤。

環境:
1. ESRI ArcGIS Server所提供的服務。
2. 選擇回傳JSON格式。
3. 呼叫的服務與程式屬於不同網域

經過Google與實際測試後,有幾種方式可以正確取得數值。
1. 使用ajax(),dataType為html:

function getData() {
jQuery.support.cors = true;
$.ajax({
type: "GET",
dataType: "html",
url: url,
contentType: "application/json; charset=utf-8",
success: showData,
error: function (xhr, ajaxOptions, thrownError) {
alert("err: " + thrownError);
}
});
}

function showData(response) {
var obj = jQuery.parseJSON(response);
$.each(obj, function (key, val) {
//拆解JSON
});
}
說明:
1. 重點在於jQuery.support.cors = true;的設定。(官方說明)
2. 該方法所返回的response必須先轉成JSON格式,再進行拆解。

2. 使用ajax(),dataType為jsonp:

function getData() {
$.ajax({
type: "GET",
dataType: "jsonp",
url: url,
contentType: "application/json; charset=utf-8",
success: showData,
error: function (xhr, ajaxOptions, thrownError) {
alert("err: " + thrownError);
}
});
}

function showData(response) {
$.each(response, function (key, val) {
//拆解JSON
});
}
說明:
1. 將dataType設為jsonp(JSON with Padding),但是必須對方服務支援該方式。
2. 該方法所返回的response已為JSON格式。

3. 使用$.getJSON()

function getData() {
jQuery.support.cors = true;
$.getJSON(url,{}, showData);
}

function showData(response) {
$.each(response, function (key, val) {
//拆解JSON
});
}
說明:
1. 該方法所返回的response已為JSON格式。
2. 雖然看似比較單純,但是沒有提供可以做錯誤處理地方。

---------------------------------------------------

*上述三種方式於IE8與Chrome15.0.874.121皆可正常取得回傳數值。
*如果比較深入去查可以發現圍繞著XMLHttpRequest對於跨域的說明。(參考文件)
*如果自己要利用jsonp的方式來實現跨域,"似乎"安全性要格外注意。

2011年12月7日 星期三

Oracle除錯_ORA-01756: 引號字串未以恰當方式終止

通常我們會使用QueryString來傳遞網頁與網頁中的參數,當我們決定這麼做的同時,弱點掃瞄工具就會塞很多可能造成程式錯誤或SQL Injection的內容,今天幫同事修正弱點掃描的內容,其中一項就是因為掃描工具將「」塞到QueryString中,造成Oracle在查詢時出現『引號字串未以恰當方式終止』這個錯誤。

而根本的解決之道並不是將該值置換或是進行其他字串的處理,而是在進行查詢時以參數的方式代入查詢內容,而非直接組SQL的查詢字串。


Imports Oracle.DataAccess.Client

sSql = "select * from Table Name = :Name "
Dim sCon As New Oracle.DataAccess.Client.OracleConnection(Constr)
Dim sCmd As New Oracle.DataAccess.Client.OracleCommand(sSql, sCon)
sCon.Open()

Dim param As OracleParameter = sCmd.CreateParameter()
param.ParameterName = ":Name "
param.Value = Name
param.OracleDbType = OracleDbType.Varchar2
sCmd.Parameters.Add(param)


說明:
1. Oracle的參數用冒號(:)
2. 使用OracleDbType 要先引入Oracle.DataAccess.Client

上述參數設定部分也可以簡化成

sCmd.Parameters.Add("Name ", OracleDbType.Varchar2).Value = Name

2011年12月6日 星期二

Android學習_唯一值(Android_id、IMEI、Wifi MAC)

如果希望可以"鎖"某些事情只能讓特定機器執行,不管是手機上的功能、伺服器的服務或是系統的登入,都必須先取得一個唯一值,網路上也有許多取得唯一值得方法,看了很多相關的文章,似乎每一種方法都有些許問題,可能還是需要看狀況來決定該用哪種方式:

1. IMEI(android developer說明)
TelephonyManager tM=(TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
String imei = tM.getDeviceId();
Log.v("ola_log", "imei:" + imei);
權限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
說明:手機的IMEI值。
缺點:由權限(READ_PHONE_STATE)可看出,IMEI值為"電話"的屬性,對於Wifi版本的平板會取得NULL值。


2. Android_id(android developer說明)
String android_id = Secure.getString(this.getBaseContext().getContentResolver(), Secure.ANDROID_ID);
Log.v("ola_log", "android_id:" + android_id);
說明:設備第一次啟動時產生的序號。
缺點:網路上部分文章指出,某些廠牌會有android_id重複的情況產生;當機器回原廠設定時,Android_id將會變更。


3. Wifi MAC(android developer說明)
WifiManager wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
Log.v("ola_log", "MacAddress:" + wifiInfo.getMacAddress());
權限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
說明:Wifi的MAC。
缺點:網路上部分文章指出,機器沒有開啟Wifi時取不到MAC;但我關閉平板Wifi還是正常取到值。


4. Build.SERIAL(android developer說明)
String BuildSERIAL = android.os.Build.SERIAL;
Log.v("ola_log", "BuildSERIAL:" + BuildSERIAL);
說明:硬體的唯一值。
缺點:該值必須要API Level 9才支援;這個問題看專案類型可大可小,對於某些專案來說甚至不是問題。

5. UUID(android developer說明)
String UUID_Value = UUID.randomUUID().toString();
Log.v("ola_log", "UUID_Value:" + UUID_Value);
說明:randomUUID可以隨機的製造一個唯一值,或是利用其他內建方法製造唯一值(EX:nameUUIDFromBytes (byte[] name))。
缺點:必須要自己處理UUID的製造及儲存,若使用randomUUID則代表的是"該次安裝的唯一值"。



感覺一件很簡單的事情,其實也不單純勒。

2011年12月2日 星期五

SQL筆記_將某欄位重新編號

若是有需要將某欄位重新編流水號碼,可利用:

declare @num INT
select @num = 0
UPDATE TableName SET @num = @num + 1,IDField = @num


筆記一下。

2011年12月1日 星期四

Android/Java_將字串去掉科學記號

在寫與坐標相關的應用時,通常我們所接到的坐標值都是121XXXXXX、24XXXXXX,也就是一個是九碼代表經度,而八碼代表緯度,如果都這樣直接儲存並不會遇到什麼問題,但若是希望秀出來的值為121.XXXXXX、24.XXXXXX這種方式,就會進行一些"簡單"的轉換。

而當我們把121.123456這樣的數值乘以1E6時,會發現會傳回1.21123456E8這樣的科學記號,如果從頭到尾都使用數字也不會有太大關係,但若是中途有進行一些字串的轉換,就會變得有點麻煩,所以我們"可能"會希望還是以121123456這樣的方式表示:


DecimalFormat df1 = new DecimalFormat("#########");
String in_Xcoord = String.valueOf(df1.format(Float.parseFloat("121.123456")*1E6));
String in_Ycoord = String.valueOf(df1.format(Float.parseFloat("24.123456")*1E6));

主要是利用DecimalFormat,給予相對應的數值格式。

如果要將121123456轉成121.123456,只需要單純的轉換。

String fac_Xcoord = String.valueOf(Float.parseFloat(fac_Xcoord_1e6)/1E6);
String fac_Ycoord = String.valueOf(Float.parseFloat(fac_Ycoord_1e6)/1E6);


若是要將數字以金錢的方式呈現(每三位一個逗號),也可以利用這樣的方式。
new DecimalFormat(",###").format(ShowMoney) + "元";