顯示具有 Android 標籤的文章。 顯示所有文章
顯示具有 Android 標籤的文章。 顯示所有文章

How to transter form Front-end developer to Client-side developer

最近在準備整理該如何教一位 Front-end developer 快速上手成為一位 Android/iOS Developer,以下整理個幾個同事問我的問題:

記憶體管理

但是 objective-c arc/java gc/ swift 雖然看起來差不多(不需要去處理 retain count/ pointer),但還是有很多最佳實踐方式不同。

看的到,选不到

在web上只要看得到的元素都可以用 selector 找到然後修改,在 native 上卻是要找到相對應的記憶體才可以修改,不管是 xcode 還是 android studio 之類的 IDE 對這方面其實都有很強大的索引功能,只是需要花點時間習慣。

档案碎片化,找不到到你是哪個檔案

一般 web 開發可能全部寫在一個檔案或分成幾個 js 載入,看先後順序就知道能不能用,native 上使用的語言都比起 js 看起來更結構化,如果習慣 AMD 架構的 js 可以更快上手。


HTML/CSS/JS 好像被組合起來了,想要調整樣式找不到位置

native 所提供的 SDK UI 組件可以看做是 web component,不論在 iOS, android 都有提供大多數基礎的 UI 組件,但這些組件也都會和原本系統的 UI 樣式相同,因次該如何 hack 他就會成了你非常常去查詢的問題,大多數原生的組件都有提供非常可靠的客製化功能,遠遠比起自己重寫可靠。


不知道該從哪裡切入?

這問題應該是最常聽到,就如同作事一樣,如果沒有目標,作起事來完全沒效率,關於這點目前是參考 Mozilla 相同的作法,每個版本都會有些小 bug,小如圖片放錯、顏色調整,這類的 bug 就很適合給新手來切入,順便在了解過程中就一併開始看架構,就像寫書法一樣,在開始創作前肯定有臨摹的階段。


環境、環境、環境

web 算是個相對成熟的架構,對前端來說不論你用 nginx, apache, nodejs, python, ruby, go 都可以很方便的幫你起一個 server 來開始工作,甚至只要有瀏覽器就可以馬上開始工作,環境這塊還是建議交給專業的來,請專業的人先幫你配置好,或有文件可以參考來靠自己建立起來,這就依賴時間緊迫程度來變動,簡單還是一句話「讓專業的來」。


專業分工

我認為大多數的前端都是對於畫面有一定程度的美感,對細節體驗有一定程度的要求,尤其是有「圖層」的觀念,從這方面出發我認為陣痛期是最短的,因為你負責的還是 UI 相關的事,底層的事可以讓原本熟悉框架的專業人士來負責,一來有成就感(作完馬上可以看到畫面,別再老是看 Hello world!),二來在前端的追求細節精神可以連貫下去。如果不小心寫出興趣還可以往圖學發展XD


Multiple thread

這就牽涉到語言的特性,需要搞清楚點觀念,只要作過 UI 的都知道,main thread 絕對不要處理任何會卡住的事情,任何 http request, 大量運算處理都要做 async 處理,這道理就像你做一個 web application 但是你絕對不會等到所有東西都載入完成後才出現畫面。



最後我想要說的是,最近身邊、老闆總是在談 native 吃掉 web 這回事,我本身是完全不認同,web 不會消失,市場也不會縮減,目前唯一可以跨平台的方案就是 web ,只是他在手機上的方式還不比在 pc 上成熟,效率上無法跟 native 相比,我認為最大原因就是歷史包袱,ios 只需要考慮在 iphone 的使用狀況,不需要考慮在 android, windows phone, browser 上跑起來的狀況,自然可以效率高許多,就像一把瑞士刀肯定不比菜刀好切菜。

多學一種技能也是挺有趣的,可以讓你有不同觀點來切入一件事情,思考上也可以更靈活,在我看來換個語言、平台都是差不多的,就像你會用中文罵「幹」會用英文罵「Fuck」一樣,沒什麼了不起,熟能生巧罷了。多學一點對自己肯定不會吃虧的,如果真的不知道該從哪種語言、平台開始,就找的自己看順眼喜歡的吧,我相信再過不久前端(Front-end) 就會變為客戶端(Client) 或終端工程師跑出來,把控這與使用者接觸的最後一哩路。

Inside salon #2 千萬下載等級遊戲開發商 Orange Nose Studio 創業與中國經驗分享 - 重點整理

我是個不太常在手機上玩遊戲的人,大多會玩遊戲就是為了打發時間,而 Orange Nose studio 出的遊戲完全是主打我這族群,無腦的遊戲有助於紓壓(無誤)。

這邊來重點整理一下這次所聽到 Leon 所談的重點,省略前面自家的火力展示,以下未依照演講時順序,未必完全與演講用字相同,僅以當時筆記為主

  • 成功的原因
    • 找到對的TA (不玩遊戲的人)
    • 找到對的市場,市場一定要夠大,並且具發展性
    • 30 秒測試
      • 用 30 秒對一個沒用過的使用者測試,30 秒如果沒辦法提起興趣那這個人就不是你的 TA或你設計根本有問題
      • 測試時什麼都不要說,在旁安靜的觀察使用者
      • 偷偷跑去手機店把要測試的 App 安裝到展示機上,然後躲在旁邊觀察,最好還可以先把 App 打開後再去旁邊觀察,確保使用者一定是看到這 App(先前我自己在寫 Android 也想過這方法 XD,這也許是個 business model)
    • 免費
    • 同時間在多個平台( ios, android )上架,所以類似 cocos2d 這類的 framework 會是你的好夥伴
    • 病毒式成長
      • 前期還是需要打廣告增加曝光量,但前期購買下載量 CP 值不高
      • 廣告再多還是比不上病毒行銷的擴散速度
      • marketing 再怎樣強還是比不上產品好
      • app + market = viral
    • 好的評分( rating )
      • 如果評分低於 4 顆星那肯定是產品出問題了,有 1顆星出現那肯定是會有 crash 或無法正常進行遊戲
  • 做一個好的遊戲
    • 選一個屬於你的市場
      • 不一定要做的特別快,但一定要想清楚
      • 維持在高的評分( rating )
      • 別只能跟電腦玩,加入社群元素可以發展更快
        • e.g. race cars vs race with friends
          • race cars - 那市場限定在熱愛賽車的人
          • race with friends - 市場肯定比 race cars 大,重點是妹也會玩
      • 最好是免費的
        • 免費市場肯定比付費市場大
        • 免費第一名下載量大約等於付費的 10 倍
      • 跨平台 ( ios, android )
    • 了解你的市場
      • 觀察同一個市場上其他優秀 App 怎麼做
      • 觀察這些優秀 Apps 的留言,看到其實哪邊還可以再改進,使用者喜好
      • 觀察市場的大小
      • 詢問自己,是否適合這市場
    • First love in 30s
      • 使用前 30 秒幾乎是掌握會不會再使用下去的關鍵(很多使用者下載後是不會開啟 App 或不了解馬上刪除)
      • Icon, title 就是吸引用戶的第一步,不好看的 icon 下載機會大幅降低
      • 如果 30s 測試無法成功通過那就表示這 App 有問題
      • 通過 30s 測試後詢問使用者
        • 了解 or 疑惑
        • 是否對某個片段有映像 or 失望
        • 是否喜歡
      • 如果可能一定要做使用者測試
    • 做出產品
      • 計畫 milestone 和 上市時間
      • 除了做使用者測試外也要做市場測試
        • 市場測試可以利用國家為範圍,香港是個很好的測試環境,測試結果幾乎會與全球差不多
      • 找出最好的付費點,做 App 是要賺錢的
        • 大多要依靠 經驗、測試,然後微調
    • 賣出你的產品
      • 可以考慮 itunes 最為你的第一個平台
      • 找出最划算的下載 預算
        • 投遞不同方式、種類的廣告,多嘗試幾個不同的通路
        • 想要大量下載基本上還是要靠錢
        • 目前(CPI) 單價越來越高(2~3+ 美金/每個下載)
      • 確保排名在前面
        • itunes 的規則前兩三個月才又改過,要靠長期觀察
          • 使用率
          • 下載量
          • 刪除率
          • 好的品質(raking)
        • Google 會依照多少人砍了你的 App
        • 各家 store 都會營造出榜單是活的感覺(常常跳動)
        • 不一定要衝上第一,前幾名一樣很有用
      • 從小的市場開始,早期測試早期修正
      • 考量長期的拓展模式
      • 考慮內至廣告模式賺錢
        • 不同國家使用不同家廣告,找出最自己最有利的
        • 最好設計成可線上切換廣告模式,多測試幾家不會錯
        • 影片廣告 ( e.g. vungle )
      • 3rd 網站廣告購買
      • android 可以考慮跟 Tapjoy 合作
      • 跟發行商合作 Chillingo
  • 中國市場
    • 市場大小
      • 250m 智慧型手機
      • 超高成場率
      • 中國市場 幾乎等同於 全球(中國以外國家)市場
    • 中國境內大約有 200 個以上的 android apps store
    • 中國使用社群
    • 手機出場 bundle app 也是常見的行銷方法
    • 收費
      • 管道
        • 電信商
          • 抽 30%
          • 提供小額付費
          • 一定要包自家的SDK(每一家都不同)
          • 還可能會被電信商要求改介面(不改不能上架)
        • 在地出版商
          • 抽 40 ~ 60%(也有抽到 90%)
          •  360, 91, baidu, ....等
          • 很可能會要求簽首發(eg. 一個月內只能在某個 store 賣)
          • 一定要包自家的SDK(每一家都不同)
        • 代理出版
          • 抽 50%
          • 你中國的窗口
          • 會幫你想辦法打擊盜版
            • Leon 提到當地盜版商甚至會把你的 App 盜版後要求正版下架,除非你花 XXX 元來買通
          • 會幫你進行手機測試,中國很多沒牌的手機
          • 會幫你通過審核
            • 一般審核約 1~2 個月,透過合作出版商大約 1 週
        • 在中國沒有設立公司妹辦法透過電信商收費
        • 一般來說大概僅剩下 12% 實際收益
      • 在地化
        • 一定要用中國用語
        • 但不一定要翻譯的很完整,因為太完整可能會被當做中國本土產品
      • 收費模式
        • 中國 IAP 模式收費為 2, 4, 6 元(人民幣)
        • 6 元(人民幣)已經是最貴
        • 以 causal game 來說中國會玩的人收入大多不高,2 元(人民幣)是非常願意付費
        • 不要讓使用者玩太久,玩太久就不付錢,所以有些 App 甚至是限定時間,超過 5 分鐘就需要付費
        • 中國 App 不能放廣告
      • 中國在地遊戲 vs 全球遊戲比例大約為 6 : 4
      • 在地出版商合作
        • 營收拆帳 + MG(保證金,超過XXX量後再跟你算)
        • 360 不給 MG
        • 有 MG 比較有保障,多少就是靠談判
        • MG 越高,因為電信商想賺回來,所以會更努力賣
        • 貨比三家不吃虧
      • 進入中國市場需要擁有的特殊技能
        • 整合各家 SDK (各家都有自己的)
          • 如果放心的話可以直接給 source code,對方會幫忙整
          • 如果是好遊戲,其他平台版本對方都可以幫忙做
        • 翻譯成中國用語
      • 如何進入
        • 找到一個好的管道
        • 整合當地的付費方式
        • GOOD LUCK


相關連結
Orange Nose studio
http://registrano.com/events/isalon2
ios
android
cocos2d
itunes
Google play
vungle
freeappaday.com
AppGratis.com
Chillingo
360
91
baidu
安卓
中國移動
中國聯通
新浪微博
騰訊微博
人人

terminal new alias name

自定義Terminal的內容,可使用以下方式

新增一個Alias
alias YOUR_NEW_ALIASNAME='YOUR_COMMAND'

移除alias
unalias YOUR_NEW_ALIASNAME


Android WebView with load ProgressBar

It usually difficulty internet environment on mobile device. Sometimes angry for don't know the loading status. Maybe device be like angry bird fly on air. The feedback is very very important.

How to get WebView status Sample as below
webView = (WebView) findViewById(R.id.index_webview);
webView.loadUrl("YOUR_URL");
webView.setWebChromeClient(new WebChromeClient(){
public void onProgressChanged(WebView view, int progress) {
//Make the bar disappear after URL is loaded, and changes string to Loading...
if(newProgress <= 10){ //TODO something } // Return the app name after finish loading if(progress == 100){ //TODO something } } });

Reference
Android Developer
Android Developer - WebView

Android Webview disable link click highlight

Android平常開啟時常會有討厭的預設的邊框,相當的顯眼,對於使用者來說這是個不錯的回饋,但對於已經有設定好另外的回饋來說這就變得有點多餘,只需要在css中加上以下一行即可消除預設的框框。

-webkit-tap-highlight-color: rgba(0, 0, 0, 0);


Android Webview hide scrollbar

scrollbar很重要,可以讓使用者清楚的知道現在的位置,但是在不該出現的時候跑出來就很討厭,下面這行可以把非必要時的scrollbar隱藏起來。

webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);


Android webView get javascript web value

用法很簡單,功能上也比起iOS所能提供得支援強大,廢話不多說往下看。

JS呼叫Android

JS
function androidResponse() {
window.YOURNAME.FUNCTIONNAME("I am being sent to Android.");
}

Android
final class IJavascriptHandler {
IJavascriptHandler() {}
public void FUNCTIONNAME(String text) {
// this is called from JS with passed value
Toast t = Toast.makeText(getApplicationContext(), text, 2000);
t.show();
}
}


WebView記得要去設定一下
webView.addJavascriptInterface(new IJavascriptHandler(), "YOURNAME");




Android呼叫JS

JS
funcrion androidResponse(string){
alert(string)
}

Android
webView.loadUrl("javascript:androidResponse();");

webView記得去把JS enable
webview.getSettings().setJavaScriptEnabled(true);
或用
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);



update 2012-08-16
熊熊發現到Android Developer官方就有篇教學
http://developer.android.com/guide/webapps/webview.html

相關連結
Android Developer
Android Developer - WebView

Android WebView Enable Javascript

Android webView預設Javascript是不允許使用的,以下方法為開啟Javascript:
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);


相關資訊
Android Developer

Android Gallery switch to position移動至指定位置

需要將Gallery、ListView、GridView移動至指定位置皆可使用此語法。

setSelection(position, animate)

Sample
imageGallery.setSelection(position, animate)


相關連結
Android Developer
Android Developer - Gallery
Android Developer - ListView
Android Developer - GridView

MySQL Client on Android

現在App對於網路的依賴度越來越高,畢竟資料如果是死的,沒辦法分享給朋友,不能按讚、+1、Tweet、Plurk......等的因素實在很痛苦,Android的SDK對於SQLite有完整的支援,但SQLite畢竟還是個local的資料存取,想要更新資料還是需要透過網路,一般App在這種狀態下大概可以分為三種方式。

1. 每次開啟App將所有資料更新
優點:一次將所有資料更新完成,在後續使用上可以完全不必在進行網路存取,減少每次等候時間,常見於電子書
缺點:安全性倍受考驗,若資料有安全性考量應盡量避免,資料量若太大會佔用到過多的容量空間,Mobile Device不是電腦上的HDD,容量是用G來計算

2. 即時存取 - 使用Api界接
優點:由後台對資料整理過後再進行傳輸,減少掉不必要的資訊,快速達成所需,製作一次可供多種平台做使用
缺點:執行製作上必須多花一份工

3. 即時存取 - 直接Query資料庫
優點:省去後台多做一次工
缺點:每次使用都需要與資料庫連線才可以取得資料,Mobile Device上的網路狀況並不像電腦的網路環境,常常會遇上無法順利與資料庫產生連線導致無法取得資訊

不過今天所要談的重點為MySQL Client,所以當然是講"3. 即時存取 - 直接Query資料庫",在這邊我選擇直接使用JDBC來溝通,直接進入重點

Step 1.下載JDBC http://dev.mysql.com/downloads/connector/j/5.0.html#downloads
因為Android對於JAVA支援版本關係,無法使用最新版,經過測試後發現3.0.17這版本就以足夠使用


Step 2. 將JDBC的Jar檔案加入至專案中

Step 3. Sample code
private Connection connect = null;
private Statement statement = null;
private ResultSet resultSet = null;

public static final String MYSQL_IP = "192.168.0.100";
public static final String MYSQL_DBNAME = "Book";
public static final String MYSQL_USERNAME = "isken";
public static final String MYSQL_PASSWORD = "isken";

public ArrayList bookList() throws Exception {
ArrayList results = new ArrayList();
try {
String script = "SELECT id, name, URL FROM Book";
Log.e("Isken", "script = "+script);

// This will load the MySQL driver, each DB has its own driver
Class.forName("com.mysql.jdbc.Driver");

Log.e("Isken", "jdbc:mysql://"+MYSQL_IP+"/+MYSQL_DBNAME+?"+ "user="+MYSQL_USERNAME+"&password="+MYSQL_PASSWORD);

// Setup the connection with the DB
connect = (Connection) DriverManager.getConnection("jdbc:mysql://"+MYSQL_IP+"/+MYSQL_DBNAME+?"+ "user="+MYSQL_USERNAME+"&password="+MYSQL_PASSWORD);

Log.e(PAGETAG, "connection is success");

// Statements allow to issue SQL queries to the database
statement = (Statement) connect.createStatement();

// Result set get the result of the SQL query
resultSet = statement.executeQuery(script);

while (resultSet.next()) {
MyObj obj = new MyObj();
String id = resultSet.getString("id");
String name = resultSet.getString("name");
String url = resultSet.getString("URL");
obj.setId(id);
obj.setName(name);
obj.setURL(url);
results.add(obj);
}
Log.e(PAGETAG, "results size = "+results.size());
} catch (Exception e) {
throw e;
} finally {
close();
}
return results;
}



相關連結
Android Developer
MySQL Developer Zone
Sample Code

Android Google Map Streetview 街景服務

街景服務也是個Google很強大的功能之一,但這功能如果只能使用在一般的PC上實在有點可惜,當然iOS、Android也有相關服務可以使用,在此介紹Android上的使用方式

double objLatitude = 25.066319;
double objLongitude =  121.557541;
Intent streetView = new Intent(android.content.Intent.ACTION_VIEW,Uri.parse("google.streetview:cbll="+ objLatitude+","+objLongitude+"&cbp=1,99.56,,1,-5.27&mz=21"));
startActivity(streetView);


相關連結
Android Developer
Android Developer - Activity

Android phone call撥號

Android內也一樣可以在app內直接進行撥號,如果是iOS上可參考前一篇"iOS dial a phone call 在app內撥電話
"

用法上相當簡單,只要在需要撥號的地方加上以下這段code
Intent i = new Intent( Intent.ACTION_CALL );
i.setData(Uri.parse("tel:"+"Phone number"));
startActivity(i);


然後在"AndroidManifest.xml"的<manifest>與</manifest>內加上下面這段
<uses-permission android:name="android.permission.CALL_PHONE"/>

※"AndroidManifest.xml"在建立專案時就會自動產生在專案最外層

相關連結
Android Developers
Android Developers - ACTION_CALL

Android adapter getView

因為這getView被問上不少次,其實這東西就像是iOS UITableViewDelegate內的"cellForRowAtIndexPath",只是在android上不僅可以使用於listView也可以使用在gridView,簡單一句話就是"他很好用"。

不過小弟我根本不會寫程式,如果有寫錯的部份就別給我面子捅下去就對了(簡單一個字就是懶...)

以下為自訂row在getView
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row;
//直接去抓xml的方式來定義內容
row=inflater.inflate(R.layout.custom_row, parent, false);

TextView title=(TextView)row.findViewById(R.id.title);
TextView subtitle=(TextView)row.findViewById(R.id.subtitle);
ImageView myImage = (ImageView)row.findViewById(R.id.myImage);

return (row);
}


以下為row的xml內容,基本上就是看你高興...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="left"
>

<ImageView
android:id="@+id/myImage"
android:src="@drawable/my"
android:layout_width="100px"
android:layout_height="100px"
</ImageView>

<LinearLayout
android:gravity="left"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="100px">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Title"
android:textSize="8pt"
android:singleLine="true">
</TextView>
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Subtitle"
android:textSize="6pt"
android:singleLine="true">
</TextView>
</LinearLayout>
</LinearLayout>


基本上到了這邊應該還會有個疑問是那每一個row要怎樣來把資料丟進去?我個人都是建一個class丟進array內來做管理,對我這種腦內記憶力不足的人來說還蠻好用的。
public class MyObj{
private String title;
private String subtitle;
private Drawable imageDrawable;
}


對應到row裡面可以使用下面這方法,其中的"myArray"也請記得先宣告出來
MyObj myObj = (MyObj)myArray.get(position);

相關連結
Android Developer
Android Developer - adapter
Android Developer - listview

Android Activity重複開啟

Activity在android的角色在我看來就像是iOS的ViewController,可以同時控制很多的東西,在iOS中可以透過push、model等方式直接來做切換,Android中可以靠Intent來做,如果今天單純兩個Activity還很容易,反正A切到B就把自己finish掉就好了,反之亦同,但如果多一點頁面想要掌控這就比較麻煩了,A、B同時都開啟C,那C不就重複開兩次,多佔用了記憶體。Intent所擁有的功能相當的多,不過這篇不是專門介紹Intent就不多提。

Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityB.class); //要從哪一個Activity切換到另一個
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); //如果這Activity是開啟的就不再重複開啟
startActivity(intent); //開啟指定的Activity
finish(); //結束掉這Activity


相關連結
Android Developers
Android Developers - Activity
Android Developers - Intent

Android Byte Array to Bitmap rotate & resize 圖片旋轉、縮放

最近會用上這也是因為在拍照時需要做些處理,拍完原始檔太大要傳好久光想就很麻煩,最後決定將檔案縮小再傳是比較適當點,剛拍完的照片儲存方式為Byte Array,但作些圖像處理時大多需要轉換為Bitmap比較方便。

Byte Array to Bitmap
buteArrayName就是這byte array的名稱
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArrayName, 0, byteArrayName.length);


Bitmap to Byte Array
其中"bitmap"就是Bitmap的變數名稱,90就是這照片的品質
ByteArrayOutputStream out = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
byte[] array= out.toByteArray();


Rotate
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
//set rotate
int w = bitmap.getWidth();
int h = bitmap.getHeight();

// Setting post rotate to 90
Matrix mtx = new Matrix();
mtx.postRotate(90);

// Rotating Bitmap
Bitmap rotatedBMP = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
//BitmapDrawable bmd = new BitmapDrawable(rotatedBMP); //如果要在畫面中顯示才需要


resize

Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

//set rotate
int w = bitmap.getWidth();
int h = bitmap.getHeight();

//set final size
int destWidth = 480;
int destHeigth = 800;

//set scale size
float scaleWidth = ((float) destWidth) / w;
float scaleHeight = ((float) destHeigth) / h;

//set resize
Matrix mtx = new Matrix();
mtx.postScale(scaleWidth, scaleHeight);

// Rotating Bitmap
Bitmap rotatedBMP = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
//BitmapDrawable bmd = new BitmapDrawable(rotatedBMP); //如果要在畫面中顯示才需要


相關連結
Android Developer
Android Developer - Bitmap
Android Developer - BitmapDrawable
Android Developer - ByteArrayOutputStream
Android Developer - BitmapFactory

Android String字串處理

記得之前寫過一篇"Object C - String",會寫這些很簡單就是因為我大腦記不住,反正知道去哪找就好,超小的腦容量要記住這麼多東西真是有點困難。

這邊就紀錄一下常用的合併、切割、型態轉換、搜尋、替換、找出位置...等

合併
/* 合併 */
String cht = "一二三四五六七八九十";
String num = "1234567890";
String append = cht+num;
System.out.println("append = "+append);
//一二三四五六七八九十1234567890


切割
/* 切割字串 */
String eng = "abcdefghijklmnopqrstuvwxyz";
String[] array = eng.split("k");
for(int i = 0 ; i < array.length ; i ++){ System.out.println("array["+i+"] = "+array[i]); } //array[0] = abcdefghij //array[1] = lmnopqrstuvwxyz


型態轉換
/* 轉換型態 */
String num = "1234567890";
//string轉int
int number = Integer.valueOf(num); //string to int
int aaa = 9999999;
//int轉string
String fromInt = String.valueOf(aaa);
System.out.println("fromInt = "+fromInt+" || number = "+number);
//fromInt = 9999999 || number = 1234567890


搜尋字串(從0開始算)
/* 搜尋字串 */
String eng = "abcdefghijklmnopqrstuvwxyz";
int searchLoc = eng.indexOf("i");
System.out.println("i = "+searchLoc);
//i = 8

searchLoc = eng.indexOf("xy");
System.out.println("xy = "+searchLoc);
//xy = 23

searchLoc = eng.indexOf("isken");
System.out.println("isken = "+searchLoc);
//isken = -1(找不到)


搜尋字元(從0開始算)
/* 搜尋字元 */
String cht = "一二三四五六七八九十";
String num = "1234567890";
char c = cht.charAt(2);
System.out.println("cht third char = "+c);
//cht third char = 三

c = eng.charAt(1);
System.out.println("eng second char = "+c);
//eng second char = b


取得字串指定位置(從0開始算)
/* 取得字串指定位置 */
String num = "1234567890";
String subTest = num.substring(1, 4);
System.out.println("subTest = "+subTest);
//subTest = 234


字串長度
/* 字串長度 */
System.out.println("cht length = "+cht.length());
//cht length = 10


替換字串
/* 替換字串 */
//替換全部
String replaceTest = "abcabcabc";
String replaced = replaceTest.replaceAll("abc", "123");
System.out.println("replaceAll = "+replaced);
//replaceAll = 123123123

//替換最先找到那個
replaced = replaceTest.replaceFirst("abc", "123");
System.out.println("replaceFirst = "+replaced);
//replaceFirst = 123abcabc


格式化字串
/* 格式化字串 */
String formatTest = "%02d";//定義為兩位不足兩位則補"0"
for(int i = 5; i < 15; i++){ System.out.println("format = "+String.format(formatTest, i)); } //format = 05 //format = 06 //... //format = 13 //format = 14


清除空白字串(清除前後所有的空白,但是字串與字串間空格不會被清除)
/* 清除字串空格 */
String trimTest1 = "abc ";
String trimTest2 = " abc";
String trimTest3 = " abc ";
String trimTest4 = "abc abc";
String trimTest5 = " d abc";
System.out.println("trimTest1 = "+trimTest1.trim());
System.out.println("trimTest2 = "+trimTest2.trim());
System.out.println("trimTest3 = "+trimTest3.trim());
System.out.println("trimTest4 = "+trimTest4.trim());
System.out.println("trimTest5 = "+trimTest5.trim());
//trimTest1 = abc
//trimTest2 = abc
//trimTest3 = abc
//trimTest4 = abc abc
//trimTest5 = d abc


字串比對
/* 字串比對 */
String cht = "一二三四五六七八九十";
String num = "1234567890";
String equalcht = "一二三四五六七八九十";
System.out.println("cht & equalcht = "+cht.equals(equalcht)+" || cht & eng = "+cht.equals(eng));
//print cht & equalcht = true || cht & eng = false


字串轉字元
/* 字串轉字元 */
String cht = "一二三四五六七八九十";
char c = cht.toCharArray()";
for(int i = 0; i < c.length; i++){ System.out.print("["+i+"] = "+c[i]); }


相關連結
Android Developer
Object C - String

Android soft keyboard keyCode 66 called twice軟體鍵盤重複送出ENTER

前幾篇有介紹到EditText要怎樣來偵測所按下的按鈕"Android EditText Listening soft keyboard"確實可以很正常的運作,那篇內也有寫到如何偵測硬體鍵盤,但就在今天發現了這新問題,在Input的時候所有按鍵都是正常的,但在按下"ENTER"(中文環境下為"完成")居然會重複送出兩次,如果這按鈕沒作啥特別事情還好,但如果是需要送request給server就頭大了,把log印出來看了一下發現重複被執行了兩次,一次是按下,一次是放開,相對於Flash內就是Press&Release,iOS內就是TouchDownInside&TouchUpInside,而Android內則是ACTION_DOWN&ACTION_UP。

用法其實沒啥兩樣,就再多加上一個判斷就好
EditText.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
System.out.println("keyCode = "+keyCode+" || event = "+event);

if(event.getAction()==KeyEvent.ACTION_DOWN){
//按下
return true;

}else{
return true;
//放開
}

//return true = finish || false = track
return false;
}
});


相關連結
Android EditText Listening soft keyboard

Android Timer

在iOS中timer執行時就是直接new一個Thread來執行,但在Android中似乎有別的方式可以選擇

宣告Timer出來,並給予啟動時間,如下面例子timer.schedule(線程名稱, activity停頓幾秒後開始執行, 每隔幾秒執行一次),這部份直接放在onCreate內
Timer timer = new Timer(true);
timer.schedule( timerTask, 2000, 3000); //(taskName, wait(ms), repet(ms))
//timer.cancel(); //stop timer


timer.schedule裡面也一樣有相當多的method,如上面所寫的那是不斷去執行直到你自己去關閉,那如果只要執行一次就使用
Timer timer = new Timer(true);
timer.schedule( timerTask, 2000); //(線程名稱, 開始後多久執行(ms))
//timer.cancel(); //stop timer


但這裡面可以用的東西也是太多了,我這只有2k的大腦記不住這麼多,補全給他按下去就對了,慢慢挑慢慢選


開始執行Timer的線程,其實也可以直接寫在todo something這邊,但是在線程中作這些實在有點不保險,常常會有意想不到的收穫,所以在這還是會推薦在handler內來作。這部份直接放在activity內
/* timer task */
TimerTask timerTask = new TimerTask(){
public void run() {
//todo something
handler.sendEmptyMessage(10);
}
};


由於用上了handler就必須在activity內再加上要執行的部份,如上面的task內所傳送一個數字過去(就是"10")所以在下方handler內的msg.what所印出來的就是"10",只要寫下"if(msg.what == 10)"要作啥事情即可,以此類推就可以有更多的變化
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//TODO something
System.out.println("msg = "+msg.what);
if(msg.what == 10){
//
}
}
};


相關連結
Android Developers
Android Developers - Timer
Android Developers - TimerTask
Android Developers - Handler

Android get Device infomation 取得手機裝置資訊

透過android系統可以很方便的取得Device的相關資訊,能夠取得的資訊真的是相當的完整,就如下面這範例想要取得手機的電信業者名稱(如中華電信這類的,但大多是代號),這些資訊作族群分析等這些資訊就變的相當重要,一般使用者可以透過"Settings(設定)>About phone(關於手機)"裡面可以查到手機資訊,不過這只能夠得知自己的資訊,如果今天寫app想要作族群用戶分析等,在android這系統上也可以很輕鬆的取得這些資訊。

下面這carrierName就是電信業者的名稱
String carrierName = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getNetworkOperatorName();
System.out.println("carrierName = "+carrierName);


透過"TelephonyManager"還可以取得更多的資訊(如下圖),補全給他按下去慢慢選就好,真的都要記下來太累了



取得裝置名稱
android.os.Build.DEVICE

在"android.os.Build"這裡面還有很多參數,以我這腦容量超小的狀況下還是使用補全慢慢挑慢慢選就好


或者可以從"android.os"這裡面也有很多資訊可以取得

可以再搭配前幾篇的"Android get sdk version & app version 取得版本資訊"、"Android 取得畫面解析度"來取得所需的資訊,站在廠商的角度真的要感謝google,感謝facebook,讓我們可以取得更完整的用戶資訊來作分析改善,以便找出淺在用戶。

相關連結
Android Developers
Android Developers - TelephonyManager
Android Developers - Build
Android Developers - android.os

Android get sdk version & app version 取得版本資訊

UI設定在某些狀況下會產生位置錯亂,並不是因為解析度問題,真的是因為版本對於該參數所定義上有修改。

一般來說直接判斷sdk version應該是比較方便,app version可以用在顯示目前app版本的地方,讓使用者知道當前版本。
//sdk verson
String sdkName = Build.VERSION.RELEASE;
String sdkVerson = Build.VERSION.SDK;
System.out.println("sdkName = "+sdkName+" || sdkVersion = "+sdkVerson);
//sdkName = 2.1-update_1 || sdkVersion = 7


//app verson
try {
String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
System.out.println("name = "+versionName+" || code = "+versionCode);
} catch (NameNotFoundException e) {
//Handle exception
}


相關連結
Android developers
Android developers - Build.VERSION