RSS

Category Archives: Mobile Development Application

Cài đặt Driver ADB cho Nook Color – Window Version

  • Bạn là 1 lập trình viên Android
  • Bạn khó chịu khi phải debug trên Emulator vì sự chậm chạp của nó
  • Kinh tế ko quá dư giả để có thể mua một tablet hoàn hảo

Nếu như bạn có 3 yếu tổ trên thì hãy đọc tiếp nha ====>

Nook Color: bản chất là 1 chiếc máy đọc sách với giá thành khá hợp lý (giá mới khoảng từ 150$ đến 200$) nhưng lại rất dễ dàng cho các vọc sĩ.

Vậy sao để bạn có thể debug ứng dụng của nền tảng Android trên một chiếc máy đọc sách =>

Chúng ta sẽ sử dụng CyanogenMod (mình đang dùng version 7.2 kernel: 2.3.7) để mod lại chiếc nook color của  mình. Sau khi chạy CyanogenMod thì nook color sẽ như 1 chiếc tablet thật sự và thậm chí còn overlock lên 1.2Ghz để sử dụng.

Sau khi đã cài đặt CM7.2 cho nook xong, chúng ta bắt đầu cài đặt driver để có thể chạy những “đứa con” của Android Developer trên nook color.

Các công cụ cần thiết:

Eclipse

Android-SDK-Windows : phần ko thể thiếu của 1 lập trình viên Android

USB – Driver for Nook Color

Let’s go:

Sau khi tải và cài đặt , tích hợp android developer tool cho eclipse xong =>Tutorial Here<=

Giải nén Driver for Nook Color vào thư mục Android-SDK-Windows

Cắm chiếc nook color vào máy tính của bạn, mở device manager, sẽ thấy báo có 1 thiết bị chưa cài đặt driver.

Bạn double click vào đó, và chọn update driver => Browse my computer > Let me pick > Have Disk

Chỉ đường dẫn đến thư mục SDK/usb-driver của bạn và cài đặt.

Sau khi cài đặt xong trong thư mục \users\[tên máy]\.android có 1 file là adb_usb.ini, edit file này bằng notepad và paste vào “0×2080″

Mở CMD = > cd [thư mục android-sdk] => platform-tools

adb kill-server

adb devices

nếu cmd báo nhận đc devices của bạn là ok, bây giờ thì mở eclipse để chạy ứng dụng của bạn thôi.

Chúc bạn thành công.

 
Leave a comment

Posted by on 08/04/2012 in Android Developmennt

 

Thẻ: , , , ,

Auto Format Currency On Edittext Android

Đầy là đoạn code để khi nhập ký tự vô Edittext trên Android, sẽ tự động format thêm phân chia dấu ngăn cách và format về định dạng tiền tệ:

 
txtNewItemPrice.addTextChangedListener(new TextWatcher() {
 private String current = "";
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // TODO Auto-generated method stub

 if(!s.toString().equals(current)){

 String cleanString = s.toString().replaceAll("[$,.]", "");

 double parsed = Double.parseDouble(cleanString);

 String formated = NumberFormat.getInstance().format((parsed/100));

 current = formated;

 txtNewItemPrice.setText(formated);
 txtNewItemPrice.setSelection(formated.length());
 }

 }

 @Override
 public void beforeTextChanged(CharSequence s, int start, int count,
 int after) {
 // TODO Auto-generated method stub

 }

 @Override
 public void afterTextChanged(Editable s) {
 // TODO Auto-generated method stub

 }
 });

Đây là đoạn code tương tụ như trên nhưng sẽ ko có dấu “$”, để lưu trữ bớt gặp khó khăn khi thay đổi locale.

txtNewItemPrice.addTextChangedListener(new TextWatcher() {
 private String current = "";
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // TODO Auto-generated method stub
 if(!s.toString().equals(""))
 {
 if(!s.toString().equals(current)){

 String cleanString = s.toString().replaceAll("[,.]", "");

 double parsed = Double.parseDouble(cleanString);

 String formated = NumberFormat.getInstance().format((parsed));

 current = formated;

 txtNewItemPrice.setText(formated);
 txtNewItemPrice.setSelection(formated.length());
 }
 }
 }

 @Override
 public void beforeTextChanged(CharSequence s, int start, int count,
 int after) {
 // TODO Auto-generated method stub

 }

 @Override
 public void afterTextChanged(Editable s) {
 // TODO Auto-generated method stub

 }
 });

Ở đây có 1 lỗi, là ko sử đụng được các kỹ tự thập phân, ví dụ như 2,333.3 sẽ ko hiểu. Bro nào làm được rồi pm lại dùm mình nha.

Ở 2 đoạn code có 1 sự khác biệt, với đoạn code trên (tham khảo trang nước ngoài) bạn sẽ bij lõi khi xóa hết các ký tự, nên khi customize lại, mình đã thêm đk để bỏ qua điều này.

Chúc các bạn thành công

 
Leave a comment

Posted by on 17/02/2012 in Android Developmennt

 

Thẻ: , , , ,

Sử dụng Camera và MediaStore trong Android Development

Để có thể sử dụng trực tiếp Camera của thiết bị mà ko cần phải dùng Api Camera do Google cung cấp.

Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(Intent.createChooser(cameraIntent,”Select Picture”), CAMERA_PIC_REQUEST);

Sau khi goi được Camera sử dụng hàm onActivityResult để lấy kết quả

if(requestCode == CAMERA_PIC_REQUEST && resultCode == Activity.RESULT_OK)
{
Uri newuri = null;
final ContentResolver cr = getContentResolver();
final String[] p1 = new String[] {
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.DATE_TAKEN
};
Cursor c1 = cr.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, p1, null, null, p1[1] + ” DESC”);
if ( c1.moveToFirst() ) {
String uristringpic = “content://media/external/images/media/” +c1.getInt(0);
newuri = Uri.parse(uristringpic);
Log.i(“tho”, “newuri “+newuri);

}
c1.close();

String imagePath = getPath(newuri);

Log.i(“tho”, “Image Path “+imagePath);
AppDataStatic.imgReportPath1 = imagePath;
Bundle extras = data.getExtras();
Bitmap bmp = (Bitmap) extras.get(“data”);
rightFragmentGeneral = (SettingsGeneral)getFragmentManager().findFragmentByTag(“rightFragmentGeneral”);
imgRestaurant = (ImageView) rightFragmentGeneral.getView().findViewById(R.id.imageRestaurant);
imgRestaurant.setImageBitmap(bmp);
alert.dismiss();
}

Tương tự như z, chúng ta có thể làm hàm để select hình ảnh từ mediastore

Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
/* intent.setType(“image/*”);
intent.putExtra(“return-data”, true);*/
startActivityForResult(intent, STORE_PIC_REQUEST);

Và lấy kết quả từ onActivityResult

alert.dismiss();
Uri selectedImageUri = data.getData();
Log.i(“tho”,”selected Image Uri “+selectedImageUri);

String selectedImagePath = getPath(selectedImageUri);
Log.i(“tho”,”selectedImagePath ” +selectedImagePath);
AppDataStatic.imgReportPath1 = selectedImagePath;

rightFragmentGeneral = (SettingsGeneral)getFragmentManager().findFragmentByTag(“rightFragmentGeneral”);
imgRestaurant = (ImageView) rightFragmentGeneral.getView().findViewById(R.id.imageRestaurant);
imgRestaurant.setImageURI(selectedImageUri);

Chúc các bạn thành công!

 
Leave a comment

Posted by on 16/02/2012 in Android Developmennt

 

Thẻ: , , ,

Bộ tài liệu học lập trình Android – Android Development

  1. Apress Begining Android: DOWNLOAD HERE
  2. Apress Begining Android 2: DOWNLOAD HERE
  3. Android Application Development: DOWNLOAD HERE
  4. Profesional Android Application Development: DOWNLOAD HERE
  5. Hello Android: DOWNLOAD HERE
  6. maning Unlocking Android : Liên hệ it_tran90 (do dung lượng file lớn nên không up lê mạng được)
 
1 Comment

Posted by on 07/09/2011 in Android Developmennt

 

Thẻ: , , , ,

Tích Hợp Plug-In Android SDK vào Eclipse trên Ubuntu

Bài trước mình đã hướng dẫn các bạn cài đặt android sdk và tích hợp plug-in vào eclipse trên window, hôm nay mình sẽ hưỡng dẫn các banj tích hợp trên Linux (Mình chọn lựa sử dụng và demo trên Ubuntu 10.10 Maverick).

Đầu tiên, bạn cần truy cập vào Android website và download SDK. Phải chọn phiên bản Linux.

android-sdk-download
Giải nén file đã download vào thư mục chủ. Khi đó bạn sẽ thấy thư mục với tên “android-sdk-linux_x86”.
Bước 2: Mở Terminal lên là mở file .bashrc lên:
gedit ~/.bashrc
Add vào file đó đoạn code sau:
export PATH=${PATH}:<your_sdk_dir>/tools
Thay thế <your_sdk_dir> bằng đường dẫn file thực cho thư mục SDK. Nếu bạn đã bung file vào thư mục chủ của mình, khi đó nó sẽ có dạng/home/your_username/android_sdk_linux_x86/.
Sau khi đã giải nén android sdk nhưng trong này chưa có các platfrom cho chúng ta tạo cac Emulator.
Bước 3: Cài đặt, update android SDK (Yêu cầu tình kiên trì và mạng khỏe). Chắc cũng cả đêm đó, nên tốt nhất cắm máy cho load rồi đi ngủ mai làm tiếp.
Vào đường dẫn sau:
[SDK Folder]/tools/android
double click vào file android mà run intermal, đến đây sẽ mở ra SDK manager cho các bạn lựa chọn platform và cài đặt.
Và chở đợi.
SAu khi cài đặt Android SDK xong chúng ta cài đătj Eclipse trên Linux: Tutorial Here

Khi cài đặt được hoàn tất, mở Eclipse (Application -> Programming -> Eclipse)
Trên menubar, kích Help -> Install new software

android-sdk-eclipse1
Tại trường Work with, nhập vào https://dl-ssl.google.com/android/eclipse và nhấn nút Add.
Check vào các Developer Tools cho Android mà chờ cài đặt, sau khi cài đặt thành công sẽ auto restart exlipse của bạn.

Vào Windows -> Preferences. Bên phía trái, chọn entry Android.

Nhập đường dẫn file Android vào trường SDK location. Kích Apply và OK.

Công việc vậy là OK! Chúc các bạn thành công.

Nguồn tham khảo: http://onthefencedevelopment.com/?p=455

 

Thẻ: , , , ,

Bộ tài liệu cho newbie lập trình Blackberry.

Đây là bộ tài liệu tìm hiểu và hướng dẫn lập trình ứng dụng JAVA cho Blackberry.

Đầu tiên là cuốn “Beginning Blackberry Development – Apress”. Theo đánh giá của mình, cuốn này khá hay và bổ ích cho newbie

 

Thứ hai là cuốn “Advance Blackberry Development – Apress”. Sau khi đọc cuốn Begining bạn nên đọc cuốn này. Đây là phần nâng cao của Begining.

DOWNLOAD HERE

Còn đây là các tài liệu dành cho developer cho Blackberry cung cấp (không phải bàn về độ chính xác và đầy đủ).

 

 
1 Comment

Posted by on 17/06/2011 in Blackberry Development

 

Thẻ: , , , ,

Storing Data with Sqlite in Blackberry Development

Lưu trữ dữ liệu là một phần khác quan trọng trong các ứng dụng bao gồm các ứng dụng desktop, web hay mobile.

Có rất nhiều cách để lưu trữ dữ liệu trên ứng dụng Blackberry như:

  • Storing file in file system
  • Storing data in SQLite
  • Storing object persistently
  • Storing object non persistently
  • Storing data with RMS
Dưới đây mình sẽ giới thiệu với mọi người cách lưu trữ với SQLite trên ứng dụng BB:
Do phần tìm hiểu khá dài nên mình up file để mọi người tiện đọc. Trong này rất nhiều phần mình viết sơ xài nên các bạn bỏ qua cho, hiii.
 

Thẻ: , , , , , , , , ,

Lập trình với Blackberry – Phần 2

Bài 2:  Tạo Form Login Sử Dụng Blackberry        Component

Các API BlackBerry bao gồm một framework phong phú để xây dựng giao diện người dùng cho các ứng dụng. Trong bài này, chúng ta cùng tìm hiểu cách sử dụng các thành phần giao diện người dùng BlackBerry để xây dựng một ứng dụng với một vài màn hình và một số điều khiển để đáp ứng với input của người dùng.

I.       Các Thành Phần Của Blackberry UI

Tất cả các phần tử trực quan(visible) có thể hiển thị trên màn hình của Blackberry là một trong 3 kiểu sau:

  • Fields: Đây là các khối xây dựng cơ bản của các UI. Nói chung, mỗi control, như một button hoặc text field, sẽ tương ứng với một thể hiện của một Field. Lớp Field sẽ vẽ các điều khiển và xử lý input người dùng.
  • Managers: Chúng được sử dụng để sắp xếp các Field trên màn hình. Mỗi Field chỉ được chứa trong một và chỉ một Manager. Mỗi Manager thực chất cũng là một Field(lớp này kế thừa từ Field), có nghĩa là mỗi manager có thể chứa các manager khác.
  • Screens: Chỉ có một screen được active trên một ứng dụng tại mọi thời điểm. Screens xử lý layout của Field thông qua manager và cung cấp các chức năng bổ xung, như

Fields được dẫn xuất từ net.rim.device.api.ui.Field. Có rất nhiều Field dựng sẵn hữu ích trong gói net.rim.device.api.ui.component.

Managers được dẫn xuất từ gói net.rim.device.api.ui.Manager, nó kế thừa từ lớp net.rim.device.api.ui.Field. Một số manager hữu ích được định nghĩa trong gói net.rim.device.api.ui.container.

Sreens được dẫn xuất từ gói net.rim.device.api.ui.Screen, nó kế thừa từ lớp Manager. Có một số screen hữu ích trong gói net.rim.device.api.ui.container.

Lưu ý Mặc dù Screen kế thừa từ Field, nhưng bạn không thể thêm một Screen vào một Manager.

1.     Tạo Ứng Dụng

Giao diện mà chúng ta sẽ xây dựng như hình vẽ sau:

Bây giờ, ta tạo ra một project UiFun, sau đó tạo ra một package blog.mobileprogramming.uifun; tiếp theo tạo 2 lớp UiFunApplication và UiFunMainScreen.

package blog.mobileprogramming.uifun;

import net.rim.device.api.ui.UiApplication;

public class UiFunApplication extends UiApplication {

public UiFunApplication() {

UiFunMainScreen mainScreen = new UiFunMainScreen();

pushScreen(mainScreen);

}

public static void main(String[] args) {

UiFunApplication app = new UiFunApplication();

app.enterEventDispatcher();

}

}

package blog.mobileprogramming.uifun;

import net.rim.device.api.ui.container.MainScreen;

public class UiFunMainScreen extends MainScreen {

public UiFunMainScreen() {

}

}

2.     Thêm Image Logo

Đầu tiên, ta thêm một thể hiện net.rim.device.api.ui.component.BitmapField thể show image lên đỉnh màn hình. Các thiết bị Blackberry có thể hiển thị các hình ảnh PNG, JPEG hay GIF, tuy nhiên hầu hết các ứng dụng sử dụng PNGs bởi chúng có kích thước nhỏ, chất lượng cao và hỗ trợ transparent.

3.     Thêm Image Vào Project

Nếu bạn sử dụng JDE Plugin for Eclipse, thêm image vào project Eclipse bằng cách tạo một folder “res”cùng cấp với folder “src”.

4.     Thêm Image Vào Screen

Tạo một thể hiện BitmapField để thêm vào Screen, trước khi tạo ra thể hiện này, tạo một đối tượng Bitmap         để load image từ resource của project.

Bitmap logoBitmap = Bitmap.getBitmapResource(“res/apress_log.png”);

Trong Constructor của lớp UiFunApplication, ta làm như sau:

package blog.mobileprogramming.uifun;

import net.rim.device.api.system.Bitmap;

import net.rim.device.api.ui.Field;

import net.rim.device.api.ui.component.BitmapField;

import net.rim.device.api.ui.container.MainScreen;

public class UiFunMainScreen extends MainScreen {

BitmapField bitmapField;

public UiFunMainScreen() {

Bitmap logoBitmap = Bitmap.getBitmapResource(“res/apress_logo.png”);

bitmapField = new BitmapField(logoBitmap, Field.FIELD_HCENTER);

add(bitmapField);

}

}

Bây giờ, nếu bạn chạy ứng dụng sẽ cho giao diện như sau:

5.     Style Flags Của Field

Hầu như tất cả các Field và Manager đều có một constructor mà có chứa tham số style. Style được đánh dấu bởi các flags style, mỗi style sẽ được sử dụng kết hợp với nhau bởi toán tử “|”. Flags được định nghĩa trong API, mỗi style sẽ có tác động nhất định đến Field hoặc Manage, chẳng hạn như nó quy định vị trí, hành vi…

6.     Tạo Các Field Usename Và Password

Ta sẽ sử dụng lớp EditField  để thiết lập usename, PasswordEditField để thiết lập password. Chúng ta không cần sử dụng style đặc biệt cho các Field này.

EditField usernameField;

PasswordEditField passwordField;

usernameField = new EditField(“Username:”, “”);

passwordField = new PasswordEditField(“Password:”, “”);

add(usernameField);

add(passwordField);

7.     Tạo Domain Và CheckBox Field

Tạo domain nên sử dụng drop-down list, trong Blackberry API, một giao diện net.rim.device.api.ui.component.ChoiceField sử dụng tương tự như một drop-down list. Bạn có thể thực thi gian diện này một cách trực tiếp, nhưng trong ví dụ này, ta chỉ sử dụng một component thực thi giao diện này, đó là net.rim.device.api.ui.component.

ObjectChoiceField, nếu bạn muốn list các số, sử dụng net.rim.device.api.ui.component.

NumericChoiceField để thay thế.

ObjectChoiceField domainField;

CheckboxField rememberCheckbox;

domainField = new ObjectChoiceField(“Domain:”, new String[] {“Home”, “Work”});

add(domainField);

rememberCheckbox = new CheckboxField(“Remember password”, false);

add(rememberCheckbox);

8.     Tạo Button

Để tạo 2 button Clear và Login, ta tạo ra 2 thể hiện từ lớp ButtonField, đồng thời gán vào style là ButtonField.CONSUME_CLICK. Nếu không sử dụng style này, thì sự kiện click sẽ được truyền vào Screen, một menu sẽ được bật lên khi người dùng click vào button, mặc dù button vẫn làm cho action này thực hiện.
BitmapField bitmapField;

EditField usernameField;


clearButton = new ButtonField(“Clear”, ButtonField.CONSUME_CLICK);

loginButton = new ButtonField(“Login”, ButtonField.CONSUME_CLICK);

add(clearButton);

add(loginButton);

Tóm lại, code sau khi thêm các thành phần giao diện trong lớp UiFunMainScreen như sau:

package blog.mobilesprogramming.uifun;

import net.rim.device.api.system.Bitmap;

import net.rim.device.api.ui.Field;

import net.rim.device.api.ui.component.BitmapField;

import net.rim.device.api.ui.component.ButtonField;

import net.rim.device.api.ui.component.CheckboxField;

import net.rim.device.api.ui.component.EditField;

import net.rim.device.api.ui.component.ObjectChoiceField;

import net.rim.device.api.ui.component.PasswordEditField;

import net.rim.device.api.ui.container.MainScreen;

public class UiFunMainScreen extends MainScreen {

BitmapField bitmapField;

EditField usernameField;

PasswordEditField passwordField;

ObjectChoiceField domainField;

CheckboxField rememberCheckbox;

ButtonField clearButton;

ButtonField loginButton;

public UiFunMainScreen() {

Bitmap logoBitmap = Bitmap.getBitmapResource(“res/apress_logo.png”);

bitmapField = new BitmapField(logoBitmap, Field.FIELD_HCENTER);

add(bitmapField);

usernameField = new EditField(“Username:”, “”);

passwordField = new PasswordEditField(“Password:”, “”);

add(usernameField);

add(passwordField);

domainField = new ObjectChoiceField(“Domain:”, new String[] { “Home”,”Work” });

add(domainField);

rememberCheckbox = new CheckboxField(“Remember password”, false);

add(rememberCheckbox);

clearButton = new ButtonField(“Clear”,ButtonField.CONSUME_CLICK);

loginButton = new ButtonField(“Login”,ButtonField.CONSUME_CLICK);

add(clearButton);

add(loginButton);

}

}

Bây giờ, nếu bạn chạy ứng dụng sẽ như hình vẽ sau:

9.     Sắp Xếp Các Button Theo Chiều Ngang

Lớp UiFunMainScreen trong ví dụ này kế thừa từ MainScreen, nên nó có một trình quản lý layout mặc định là VerticalFieldManager để quản lý các Field. Khi thêm bất kỳ Field nào vào ứng dụng, trình quản lý này sẽ sắp xếp các Field theo chiều dọc. Tuy nhiên trong ví dụ này, ta muốn một số thành phần được sắp xếp theo chiều dọc, riêng các Button thì sẽ sắp xếp theo chiều ngang; để làm được như vậy, chúng ta sẽ sử dụng HorizonetalFieldManager với style là Field.FIELD_RIGHT(canh bên phải) để đẩy các Button vào màn hình.
HorizontalFieldManager buttonManager = new HorizontalFieldManager(Field.FIELD_RIGHT);

buttonManager.add(clearButton);

buttonManager.add(loginButton);

add(buttonManager);

Ngoài ra, ta sẽ sử dụng thêm một đối tượng SeparatorField để vẽ một thanh chắn ngang bên dưới image với các Field của ứng dụng.

Bitmap logoBitmap = Bitmap.getBitmapResource(“res/apress_logo.png”);

bitmapField = new BitmapField(logoBitmap, Field.FIELD_HCENTER);

add(bitmapField);

add(new SeparatorField());

add(new LabelField(“Please enter your credentials:”));

usernameField = new EditField(“Username:”, “”);

passwordField = new PasswordEditField(“Password:”, “”);

add(usernameField);

add(passwordField);

domainField = new ObjectChoiceField(“Domain:”, new String[] {“Home”, “Work”});

add(domainField);

rememberCheckbox = new CheckboxField(“Remember password:”, false);

add(rememberCheckbox);

add(new SeparatorField());

clearButton = new ButtonField(“Clear”, ButtonField.CONSUME_CLICK);

loginButton = new ButtonField(“Login”, ButtonField.CONSUME_CLICK);

HorizontalFieldManager buttonManager =

new HorizontalFieldManager(Field.FIELD_RIGHT);

buttonManager.add(clearButton);

buttonManager.add(loginButton);

add(buttonManager);

Bây giờ, nếu bạn chạy đoạn code trên, nó sẽ như hình vẽ sau:

Bài viết liên quan:

Lập trình với BlackBerry – Phần 1

Đang update các source demo cho các bạn, sẽ cập nhật trong thời gian sớm nhất!

Nguồn tham khảo: mobileprograming Blog và Beginning_BlackBerry_Development

 
Leave a comment

Posted by on 15/04/2011 in Blackberry Development

 

Thẻ: , ,

Lập trình với Blackberry – Phần 1

Bài 1:      Tổng Quan Về Blackberry

I.       Vòng Đời Của Blackberry Application

1.     Bắt Đầu Ứng Dụng

Một ứng dụng thường bắt đầu theo một trong 3 cách sau:

  • Người dùng click vào icon của ứng dụng trên home screen Blacberry.
  • Ứng dụng là một ứng dụng start một cách tự động và chạy khi thiết bị turn on hay sau khi nó reboot.
  • Ứng dụng chạy bởi một ứng dụng khác.

Trong mọi trường hợp, phương thức main là một entry point đầu tiên của ứng dụng. Các thiết bị Blackberry sẽ tạo một tiến trình để gọi phương thức main. Khi phương thức main exit, tiến trình cũng kết thúc và ứng dụng exit. Điều này có nghĩa rằng, nếu bạn muốn ứng dụng làm bất cứ điều gì, bạn sẽ làm điều đó trong phương thức main.

Phương thức main nhận một mảng các đối tượng String làm tham số. Thông thường, mảng này empty, nhưng các tham số có thể được gán nếu bạn định nghĩa chúng trong properties project hay nếu chúng được gán bởi một tiến trình khác mà tiến trình này start ứng dụng.

2.     Tạo Ứng Dụng

  • Tất cả các ứng dụng BlackBerry muốn trình diễn một UI cho người dùng phải kế thừa lớp UiApplication. Bạn chỉ có thể tạo ra một thể hiện của UiApplication cho tất cả tiến trình ứng dụng; BlackBerry runtime sẽ ném một ngoại lệ nếu bạn cố gắng khởi tạo một tiến trình thứ hai.
  • Thậm chí, các ứng dụng không có UI phải kế thừa từ lớp net.rim.device.api.system.Application, tuy nhiên các kiểu ứng dụng như vậy không được thảo luận trong bài này.
  • Bạn có thể truy cập thể hiện của ứng dụng bằng cách sử dụng phương thức static UiApplication.getUiApplication(). Phương thức này sẽ trả về một thể hiện của lớp ứng dụng, vì vậy ở bất kỳ đâu trong ứng dụng HelloWorld (có một lớp HelloWorldApp kế thừa UiApplication), công việc sau được phép:

HelloWorldApp helloWorld = (HelloWorldApp)UiApplication.getUiApplication();

3.     Gọi Event Thread

  • Các thread sự kiện được bắt đầu bởi hệ điều hành BlackBerry, nhưng nó không bắt đầu xử lý sự kiện và vẽ các giao diện cho đến khi bạn yêu cầu nó một cách tường minh. Bạn yêu cầu nó thực thi bằng cách gọi phương thức UiApplication.enterEventDispatcher(). Một khi phương thức này được gọi, thread đó đi vào phương thức main() và làm nhiệm vụ lắng nghe các input từ UI và vẽ giao diện lên màn hình. Bạn vẫn sẽ nhận được một cơ hội để làm việc trên thread này, nhưng thông thường, các hoạt động của nó được lên kế hoạch(schedule) với hệ điều hành BlackBerry.
  • Phương thức enterEventDispatcher() sẽ không trả lại cho toàn bộ vòng đời ứng dụng của bạn, do đó, nếu có bất cứ điều gì main thread phải làm trước khi gọi phương thức này (ví dụ, thực hiện một số công việc khởi tạo), thì bạn phải thực hiện các công việc khởi tạo trước(có thể khởi tạo trước lời gọi enterEventDispatcher() hay khởi tạo trong Constructor của ứng dụng).

4.     Xử Lý Sự Kiện

Ứng dụng này đáp ứng các sự kiện nhập vào bàn phím, trackball, hoặc chuyển động màn hình cảm ứng và nhấp chuột và các sự kiện khác như thông điệp hệ thống.

5.     Thoát Khỏi Ứng Dụng

Nói chung, một ứng dụng BlackBerry exit khi màn hình cuối cùng được remove từ display stack (bằng cách đóng nó). Bạn có thể gọi phương thức System.exit() để thoát khỏi ứng dụng, nhưng cách này được khuyến nghị nên tránh và nên clean up ứng dụng đang tồn tại bằng cách đóng tất cả các màn hình. Khi thoát ứng dụng, tất cả các trạng thái ứng dụng sẽ được clean up, và lần tiếp theo nếu người dùng nhấp vào icon của ứng dụng thì phương thức main sẽ được gọi trở lại với một tiến trình mới.

II.       Threading Và Event Thread

BlackBerry UI API là đơn luồng(single-thread). Điều này có nghĩa rằng tất cả các thông tin cập nhật giao diện người dùng và sự kiện được xử lý bởi cùng một thread, hay chính xác hơn, phải được thực hiện trong khi giữ khóa sự kiện, mà hầu hết thời gian được tổ chức bởi thread UI. Nó có một vài tác động đối với các ứng dụng BlackBerry: các thread khác không thể truy cập trực tiếp vào UI mà không đạt được khóa sự kiện một cách rõ ràng(một ngoại lệ sẽ được ném ra nếu bạn cố gắng), và nếu bạn thực hiện một hoạt động trên event thread mà nó chiếm nhiều thời gian, toàn bộ giao diện người dùng sẽ tạm dừng trong khi hoạt động đó đang diễn ra.

1.     Nhận Biết Khi Ứng Dụng Của Bạn Hoạt Động Trên Event Thread

Bạn luôn luôn có thể nhận biết nếu code của bạn đang được thực hiện bởi event thread bằng cách gọi phương thức UiApplication.isEventDispatchThread(). Tuy nhiên, thông thường chúng ta không gọi phương thức này. Một nguyên tắc nhỏ để nhận biết ứng dụng đang làm việc trên event thread:

  • nếu code được gọi trực tiếp từ phương thức run() của thread mà ta tự tạo ra, có nghĩa là ứng dụng không hoạt động trên event thread.
  • nếu code được gọi bởi hệ thống để đáp ứng các input từ người dùng(ví dụ như click vào menuitem hay button), thì có nghĩa là ứng dụng đang hoạt động trên event thread.

2.     Cập Nhật UI Từ Các Thread Khác

Tất nhiên, có nhiều khi bạn muốn một sự kiện trong thread khác để được phản ánh(reflect) trong UI, ví dụ tạo một thread để xử lý quá trình download file. Để làm điều đó, có một vài phương pháp.

  • Phương pháp đầu tiên sử dụng UiApplication.invokeLater() hoặc UiApplication.invokeAndWait() để báo cho thread UI để chạy một số code trên event thread ở cơ hội có sẵn tiếp theo.
  • Phương pháp thứ hai là thu được khóa sự kiện UI bằng cách đồng bộ hóa trên các đối tượng trả về bởi UiApplication.getEventLock(). Chúng ta sẽ ứng dụng phương pháp đầu tiên bằng cách sửa đổi ứng dụng Hello World để bắt đầu một thread mới, và thread này sẽ thêm các message vào LabelField của main screen sau mỗi 5 giây.

Lưu ý Cả hai phương thức invokeLater() và invokeAndWait() cùng hoạt động như nhau – đó là đưa vào hàng đợi một thể hiện của java.lang.Runnable để được thực thi trên event thread. Sự khác biệt là invokeLater() trả về ngay lập tức, trong khi invokeAndWait() không trả lại cho đến khi phương thức run() của Runnable đã kết thức việc thực thi,  và do đó, block thread gọi nó.

Đầu tiên, thay thế biến cục bộ labelField thành một biến thành viên, sau đó thêm một phương thức appendLabelText().

public class HelloWorldMainScreen extends MainScreen {

private LabelField labelField;

public HelloWorldMainScreen() {

labelField = new LabelField(“Hello World”);

add(labelField);

}

public void appendLabelText(String text) {

labelField.setText(labelField.getText() + “\n” + text);

}

}

Bởi vì phương thức appendLabelText() gọi phương thức LabelField.setText(), lời gọi này chỉ có thể được thực hiện event thread. Nếu bạn cố gắng gọi phương thức này trực từ thread khác, một ngoại lệ sẽ được ném.

Bây giờ, chúng ta sẽ tạo một lớp MainScreenUpdaterThread kế thừa từ Thread để thực hiện công việc cập nhật. Nó sẽ lặp từ 1 đến 10. Mỗi lần lặp, nó sẽ đợi 5 giây và sau đó thêm một đoạn text và LabelField.

package blog.mobileprogramming;

import net.rim.device.api.ui.UiApplication;

public class MainScreenUpdaterThread extends Thread {

HelloWorldMainScreen mainScreen;

public MainScreenUpdaterThread(HelloWorldMainScreen mainScreen) {

this.mainScreen = mainScreen;

}

public void run() {

for (int i = 0; i < 10; i++) {

try {

Thread.sleep(5000);

} catch (InterruptedException ex) {

}

// Queue a new task on the event thread

UiApplication.getUiApplication().invokeLater(new Runnable() {

public void run() {

mainScreen.appendLabelText(“Update”);

}

});

}

}

}

Để cập nhật thực sự UI, chúng ta sử dụng lớp nội bộ vô danh(anonymous inner class), đó là lớp mà chúng ta định nghĩa tại thời điểm khởi tạo nó. Lớp vô danh này gọi một phương thức mà cần được gọi trên event thread, đó là phương thức appendLabelText().

Bây giờ, trong constructor của HelloWorldMainScreen, chúng ta thực hiện như sau:

public HelloWorldMainScreen() {

labelField = new LabelField(“Hello World”);

add(labelField);

MainScreenUpdaterThread thread = new MainScreenUpdaterThread(this);

thread.start();

}

Cuối cùng là ta chạy ứng dụng, out put của nó như hình sau đây:

3.     Sử Dụng Event Lock

Chúng ta sẽ sử dụng một phương pháp thứ 2 để cập nhật UI từ một thread khác; đó là bên trong lớp MainScreenUpdateThread, chúng ta goi phương thức getEventLock() để nhận event lock.

public void run() {

for (int i = 0; i < 10; i++) {

try {

Thread.sleep(5000);

} catch (InterruptedException ex) {

}

// Ensure we have the event lock

synchronized(UiApplication.getEventLock()) {

mainScreen.appendLabelText(“Update”);

}

}

}

Phương pháp này cho ra cùng một kết quả với phương pháp đầu tiên.

III.       Thiết Lập Ứng Dụng Chạy Background

Theo mặc định, một ứng dụng sẽ thoát khi màn hình cuối cùng của nó được đóng; tuy nhiên, bạn có thể override hành vi này để thiết lập một ứng dụng chạy background, có nghĩa là UI sẽ không được hiển thị, nhưng ứng dụng vẫn tiếp tục chạy trong khi người dùng thực hiện các công việc khác. Ứng dụng chạy ở dạng Background chỉ thực sự hữu ích trong các tình huống sau:

  • Bạn muốn ứng dụng của bạn kiểm tra định kỳ các thay đổi trên thiết bị hoặc cho các sự kiện. Ví dụ, ứng dụng BlackBerry Message luôn luôn chạy để kiểm tra các mail đến.
  • Bạn muốn tải về theo định kỳ thông tin mới từ mạng. Một số ứng dụng thời tiết và chứng khoán sử dụng phương pháp này.
  • Bạn cần duy trì kết nối đến server, chẳng hạn các ứng dụng chat hay sử dụng phương pháp này.

1.     Phát Hiện Ứng Dụng Đang Ở Background Hay Foreground

Một ứng dụng có thể được chuyển sang Background nếu một người dùng khi nhấn phím red phone hay chuyển sang các task một cách tường minh. Bạn có thể phát hiện trạng thái background này bằng cách override phương thức UiApplication.deactivate(). Tương tự như vậy, bạn có thể phát hiện các ứng dụng của bạn trở về Foreground bằng cách gọi phương thức  UiApplication.activate().

Bây giờ, sữa đổi HelloWorldApp để hiển thị một message khi Hello World đi vào Background hay Foreground

public class HelloWorldApp extends UiApplication {

private HelloWorldMainScreen mainScreen;

public HelloWorldApp() {

mainScreen = new HelloWorldMainScreen();

pushScreen(mainScreen);

}

public void deactivate() {

mainScreen.appendLabelText(“Went to background”);

}

public void activate() {

mainScreen.appendLabelText(“Came to foreground”);

}

/**

* @param args

*/

public static void main(String[] args) {

HelloWorldApp app = new HelloWorldApp();

app.enterEventDispatcher();

}

}

Khi chạy ứng dụng này, ngay lập tức sẽ thấy một message ”Came to foreground”.
Message được hiển thị bởi vì những kích hoạt ban đầu của ứng dụng. Nhấn nút đỏ, và sau đó chọn icon một vài lần để chuyển ứng dụng từ foreground sang background.

2.     Chuyển Ứng Dụng Sang Background

Bạn có thể chuyển ứng dụng sang Background bằng cách gọi phương thức UiApplication.requestBackground(). Để làm cho Hello World chuyển sang Background thay vì exit khỏi ứng dụng khi người dùng đóng màn hình chính, hãy ghi đè phương thức Screen.close() trong HelloWorldMainScreen:

public class HelloWorldMainScreen extends MainScreen {

//…

public void close() {

UiApplication.getUiApplication().requestBackground();

}

}

NGuồn: mobileprograming Blog

 
1 Comment

Posted by on 14/04/2011 in Blackberry Development

 

Thẻ: ,

Làm Việc Với XML Trên Android – Phần 1

Giới thiệu
Android là một hệ điều hành nguồn mở, hiện đại và là SDK cho các thiết bị di động. Với hệ điều hành này, bạn có thể tạo ra các ứng dụng di động rất mạnh. Điều này thậm chí còn trở nên hấp dẫn hơn nữa khi các ứng dụng của bạn có thể truy cập các dịch vụ Web, có nghĩa là bạn cần sử dụng ngôn ngữ của Web là: XML. Trong bài viết này, bạn sẽ thấy nhiều lựa chọn khác nhau để làm việc với XML trên Android và cách sử dụng chúng để xây dựng các ứng dụng Android của chính bạn.
Bắt đầu
Trong bài viết này, bạn học cách xây dựng các ứng dụng Android có thể làm việc với XML từ Internet. Các ứng dụng Android được viết bằng ngôn ngữ lập trình Java™, do vậy mà kinh nghiệm làm việc với công nghệ Java là điều cần phải có. Để phát triển cho Android, bạn sẽ cần đến Android SDK. Toàn bộ mã trình được trình bày trong bài viết này sẽ làm việc với bất kỳ phiên bản nào của Android SDK, nhưng phiên bản SDK 1.5_pre đã được sử dụng để phát triển mã trình. Bạn có thể phát triển các ứng dụng Android chỉ với SDK và một trình biên tập văn bản là đủ, nhưng sẽ dễ dàng hơn nhiều nếu sử dụng Android Developer Tools (ADT), là một trình bổ sung Eclipse. Đối với bài viết này, phiên bản 0.9 của ADT đã được dùng với Eclipse 3.4.2, một phiên bản Java.
XML trên Android
Nền tảng Android là một nền tảng phát triển di động mã nguồn mở. Nó giúp bạn truy cập vào tất cả các khía cạnh của thiết bị di động mà nó chạy trên đó, từ các đồ họa cấp thấp, đến phần cứng như là thiết bị camera trên điện thoại. Với rất nhiều thứ có thể sử dụng Android, có thể bạn sẽ tự hỏi tại sao bạn cần phiền đến XML. Đó không phải vì làm việc với XML rất thú vị; mà là nó đang làm việc với những thứ mà nó kích hoạt. XML thường được dùng như là một định dạng dữ liệu trên Internet. Nếu bạn muốn truy cập dữ liệu từ Internet, các khả năng có thể là dữ liệu sẽ ở dạng XML. Nếu bạn muốn gửi dữ liệu đến một dịch vụ Web, có thể bạn cũng cần gửi cả dữ liệu XML. Nói ngắn gọn là nếu ứng dụng Android của bạn thúc đẩy Internet, thì có thể bạn sẽ cần phải làm việc với XML. Thật may mắn là bạn có rất nhiều lựa chọn có sẵn để làm việc với XML trên Android.
Các trình phân tích XML
Một trong nhữn ưu điểm lớn nhất của nền tảng Android chính là việc nó thúc đẩy ngôn ngữ lập trình Java. Android SDK không hoàn toàn cung cấp sẵn mọi thứ cho Môi trường Thời gian chạy Java (JRE) chuẩn của bạn, nhưng nó lại hỗ trợ một phần rất đáng kể cho nó. Nền tảng Java đã và đang hỗ trợ rất nhiều cách khác nhau để làm việc với XML trong thời gian nhất định, và hầu hết các API có liên quan đến XML của Java đều được hỗ trợ đầy đủ trên Android. Ví dụ, Simple API của Java cho XML (SAX) và Document Object Model (DOM) hiện đều có sẵn trên Android. Nhiều năm qua, cả hai API này là một phần của công nghệ Java. Sản phẩm Streaming API mới đây cho XML (StAX) hiện chưa có trong Android. Tuy nhiên, Android lại cung cấp một thư viện tương đương về mặt chức năng. Điều cuối cùng là Java XML Binding API cũng không có sẵn trong Android. Chắc chắn có thể thực hiện API này trong Android. Tuy nhiên, nó lại có xu hướng là một API nặng ký, với rất nhiều thể hiện khác nhau thuộc các lớp khác nhau thường cần việc trình bày một tài liệu XML. Do vậy mà nó không lý tưởng lắm cho một môi trường bị ràng buộc chẳng hạn như thiết bị cầm tay mà Android được thiết kế để chạy trên đó. Trong các phần tiếp theo, bạn sẽ lấy một nguồn XML đơn giản có sẵn trên Internet, và xem cách phân tích nguồn đó như thế nào trong phạm vi một ứng dụng Android sử dụng các API khác nhau được nhắc đến ở trên.Trước tiên, hãy xem các phần cần thiết của ứng dụng đơn giản sẽ sử dụng XML từ Internet.

Các Từ Viết Tắt Thông Dụng

  • API: Application programming interface (Giao diện lập trình ứng dụng)
  • RSS: Really Simple Syndication (Giao thức tập hợp thông tin đơn giản)
  • SDK: Software Developers Kit (Bộ dụng cụ cho nhà phát triển phầm mềm)
  • UI: User interface (Giao diện người dùng)
  • URL: Universal Resource Locator (Địa chỉ tài nguyên)
  • XML: Extensible Markup Language (Ngôn ngữ đánh dấu mở rộng)
Trình đọc tin Android
Ứng dụng sẽ lấy điểm tin RSS từ trang nhà phát triển Android phổ biến Androidster và phân tách nó thành một danh sách các đối tượng Java đơn giản mà bạn có thể sử dụng để quay lại Android ListView. Đây là hoạt động đa hình thái cổ điển — tức là các thực thi khác nhau (các thuật toán phân tích XML khác nhau) cung cấp hoạt động giống nhau. Ví dụ 1 dưới đây cho bạn thấy bạn có thể mô hình hóa điều này dễ dàng như thế nào trong mã trình Java sử dụng một giao diện.
Ví dụ 1. giao diện trình phân tích điểm tin XML
package org.developerworks.android;

import java.util.List;
public interface FeedParser {
List<Message> parse();
}
Trong ví dụ 2, lớp Message là một POJO (Plain Old Java Object) cổ điển miêu tả một cấu trúc dữ liệu.
Ví dụ 2. Message POJO
public class Message implements Comparable<Message>{

static SimpleDateFormat FORMATTER =
new SimpleDateFormat(“EEE, dd MMM yyyy HH:mm:ss Z”);
private String title;
private URL link;
private String description;
private Date date;
// getters and setters omitted for brevity
public void setLink(String link) {
try {
this.link = new URL(link);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public String getDate() {
return FORMATTER.format(this.date);
}
public void setDate(String date) {
// pad the date if necessary
while (!date.endsWith(“00″)){
date += “0″;
}
try {
this.date = FORMATTER.parse(date.trim());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
// omitted for brevity
}
@Override
public int hashCode() {
// omitted for brevity
}
@Override
public boolean equals(Object obj) {
// omitted for brevity
}
// sort by date
public int compareTo(Message another) {
if (another == null) return 1;
// sort descending, most recent first
return another.date.compareTo(date);
}
}
Message, trong ví dụ 2, thường rất dễ làm. Nó ẩn đi một vài trạng thái bên trong của mình bằng cách cho phép truy cập ngày tháng và các liên kết như các chuỗi đơn giản, trong khi thể hiện chúng như các đối tượng được sắp xếp một cách rõ ràng (một java.util.Date và một java.net.URL). Nó là một Value Object (Đối tượng Giá trị) cổ điển, do vậy nó thực thi equals() và hashCode() dựa trên trạng thái bên trong của nó. Nó cũng thực hiện giao diện Comparable vì thế bạn có thể sử dụng nó để sắp xếp (theo ngày tháng). Thực tế, dữ liệu được phân loại từ điểm tin, do vậy mà điều này không cần thiết.
Mỗi thực thi trình phân tích sẽ cần đưa một URL đến điểm tin Androidster và sử dụng cái này để mở một kết nối HTTP đến trang Androidster. Hoạt động phổ biến này được mô hình hóa một cách tự nhiên trong mã trình Java sử dụng lớp cơ sở trừu tượng như trong Ví dụ 3.
Ví dụ 3. Lớp trình phân tích điểm tin cơ bản
public abstract class BaseFeedParser implements FeedParser {

// names of the XML tags
static final String PUB_DATE = “pubDate”;
static final  String DESCRIPTION = “description”;
static final  String LINK = “link”;
static final  String TITLE = “title”;
static final  String ITEM = “item”;
final URL feedUrl;
protected BaseFeedParser(String feedUrl){
try {
this.feedUrl = new URL(feedUrl);
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
protected InputStream getInputStream() {
try {
return feedUrl.openConnection().getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Lớp cơ sở lưu trữ feedUrl và sử dụng nó để mở java.io.InputStream. Nếu có bất kỳ sai sót nào, đơn giản nó thả một RuntimeException, sao cho ứng dụng dừng hoạt động một cách nhanh chóng. Lớp cơ sở cũng xác định một vài hằng số đơn giản cho tên các thẻ. Ví dụ 4 trình bày một số nội dung mẫu từ điểm tin, qua đó bạn có thể thấy được ý nghĩa của các thẻ này.
Ví dụ 4. Điểm tin XML mẫu
<?xml version=”1.0″ encoding=”UTF-8″?>

<!– generator=”FeedCreator 1.7.2″ –>
<rss version=”2.0″>
<channel>
<title>android_news</title>
<description>android_news</description>
<link>http://www.androidster.com/android_news.php</link>
<lastBuildDate>Sun, 19 Apr 2009 19:43:45 +0100</lastBuildDate>
<generator>FeedCreator 1.7.2</generator>
<item>
<title>Samsung S8000 to Run Android, Play DivX, Take Over the
World</title>
<link>http://www.androidster.com/android_news/samsung-s8000-to-run-android-
play-divx-take-over-the-world</link>
<description>More details have emerged on the first Samsung handset
to run Android. A yet-to-be announced phone called the S8000 is being
reported …</description>
<pubDate>Thu, 16 Apr 2009 07:18:51 +0100</pubDate>
</item>
<item>
<title>Android Cupcake Update on the Horizon</title>
<link>http://www.androidster.com/android_news/android-cupcake-update-
on-the-horizon</link>
<description>After months of discovery and hearsay, the Android
build that we have all been waiting for is about to finally make it
out …</description>
<pubDate>Tue, 14 Apr 2009 04:13:21 +0100</pubDate>
</item>
</channel>
</rss>
Như bạn có thể thấy từ mẫu trong ví dụ 4, một ITEM tương đương với một thể hiện Message. Các nút con của mục chọn (TITLE, LINK và v.v..) tương đương các đặc tính của thể hiện Message. Vì bạn biết điểm tin trông như thế nào rồi và có sẵn tất cả các phần phổ biến, hãy xem làm thế nào để phân tách điểm tin này sử dụng các công nghệ khác nhau có sẵn trên Android. Bạn sẽ bắt đầu với SAX.
Sử dụng SAX
Trong môi trường Java, bạn có thể thường xuyên sử dụng SAX API khi bạn muốn có một trình phân tích nhanh và muốn hạn chế tối đa việc sử dụng (footprint) bộ nhớ ứng dụng của bạn. Điều đó khiến cho cho nó rất phù hợp cho thiết bị di động chạy Android. Bạn có thể sử dụng SAX API như là từ môi trường Java, mà không cần đến những thay đổi đặc biệt cần thiết để chạy trên Android. Ví dụ 5 trình bày một thực thi SAX của giao diện FeedParser.
Ví dụ 5. Thực thi SAX
public class SaxFeedParser extends BaseFeedParser {

protected SaxFeedParser(String feedUrl){
super(feedUrl);
}
public List<Message> parse() {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser parser = factory.newSAXParser();
RssHandler handler = new RssHandler();
parser.parse(this.getInputStream(), handler);
return handler.getMessages();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Nếu trước đây bạn đã sử dụng SAX, thì cái này trông cũng khá quen thuộc. Như với bất kỳ thực thi SAX nào, phần lớn các chi tiết đều nằm trong trình xử lý SAX. Trình xử lý nhận các sự kiện từ trình phân tích SAX khi nó chạy nhanh qua tài liệu XML. Trong trường hợp này, bạn vừa tạo ra một lớp mới gọi là RssHandler và đăng ký nó như là một trình xử lý cho trình phân tích, như trong ví dụ 6.
Ví dụ 6. Trình xử lý SAX
import static org.developerwor Read the rest of this entry »
 
Leave a comment

Posted by on 13/04/2011 in Android Developmennt

 
 
Follow

Get every new post delivered to your Inbox.