Category Archives: Android-Lập trình Android

Android – Fragment

Fragment là một lớp trong Android cho phép thao tác với các View, Fragment cũng có các phương thức khởi tạo, phục hồi, hủy… có thế nhận và xử lý sự kiện…v.v như một Activity, nhìn chung thì chúng ta có thể coi Fragment như một Activity con vậy. Nhưng Fragment không tồn tại một mình như Activity mà một Fragment phải được “gắn” với một Activity nào đó, nếu Activity bị hủy thì Fragment cũng bị hủy, nếu Activity được phục hồi thì Fragment cũng được phục hồi.

Bản chất Fragment cũng giống như một View như Button, EditText…v.v  chỉ khác các View ở chỗ là Fragment lại được dùng để chứa các View khác, có vòng đời của riêng nó và có thể xử lý sự kiện.

Nếu bạn đã từng lập trình GUI với Java Swing thì bạn có thể so sánh Fragment giống như JPanel vậy, còn ActivityJFrame.

Thường thì chúng ta dùng Fragment để phân chia công việc của Activity ra cho dễ quản lý. Sử dụng Fragment cho bạn những lợi thế sau:

  • Có thể chia công việc của Activity cho các Fragment để dễ dàng quản lý và sửa đổi code.
  • Có thể dùng một Fragment cho nhiều Activity, do đó khi tạo một Activity chúng ta không cần phải thiết kế lại giao diện mà có thể dùng giao diện có sẵn từ các Fragment đã tạo trước đó.
  • Có khả năng tùy biến giao diện ứng dụng một cách dễ dàng dựa theo nhiều kích thước màn hình khác nhau.

Vòng đời của một Fragment

Cũng giống như Activity, một Fragment cũng có các phương thức trạng thái của riêng nó.

fragment_lifecycle

  • onAttach: phương thức này sẽ gắn Fragment vào một Activity
  • onCreate: sau khi đã được gắn vào Activity, phương thức onCreate() sẽ tạo một đối tượng mới thuộc lớp Fragment.
  • onCreateView: sau đó phương thức onCreateView() sẽ tạo giao diện cho Fragment và gắn giao diện này vào giao diện chính của Activity.
  • onActivityCreated: phương thức này được gọi sau khi phương thức onCreate() của Activity đã chạy xong.
  • onStart: chỉ khi phương thức onStart() được gọi thì Fragment mới có thể thực hiện các tương tác với người dùng.
  • onResume: phương thức này được gọi sau khi phương thức onResume() của Activity được gọi.
  • onPause: phương thức này được gọi khi Fragment bị ẩn, hoặc khi Activity đi vào trạng thái Paused.
  • onStop: phương thức này được gọi khi Fragment bị xóa hoặc bị thay thế bởi Fragment khác, hoặc khi Activity gọi phương thức onStop().
  • onDestroyView: sau khi gọi phương thức onStop() thì phương thức onDestroyView() được gọi để xóa và gỡ giao diện ra khỏi Activity.
  • onDestroy: phương thức này sẽ thực hiện các công việc dọn dẹp cuối cùng.
  • onDetach: phương thức này sẽ gỡ Fragment ra khỏi Activity.

Nhìn chung thì vòng đời của một Fragment cũng giống như của một Activity nhưng có nhiều phương thức hơn.

Ví dụ

Chúng ta tạo một project như bình thường.

Trong file main.xml chúng ta thiết kế như sau:

<?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">
    <Button android:id="@+id/button1" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="Fragment 1" 
        android:onClick="selectFragment"/>
    <Button android:id="@+id/button2" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="Fragment 2" 
        android:onClick="selectFragment" />
    <fragment android:id="@+id/fragment_place" 
        android:name="com.phocode.FragmentOne" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" />
</LinearLayout>

Giao diện chính của Activity gồm 2 Button và một thẻ fragment, thẻ này mặc định sẽ dùng lớp FragmentOne để tương tác với người dùng, chúng ta sẽ viết lớp này ở dưới, thẻ fragment này cũng có các thuộc tính width, height... như các View bình thường.

android:onClick="selectFragment"

Hai thẻ Button sẽ có phương thức xử lý sự kiện onClickselectFragment().

Tiếp theo chúng ta định nghĩa 2 lớp Fragment, các lớp Fragment này cũng giống như các Activity là sẽ có 1 file .java để xử lý sự kiện và một file .xml để thiết kế giao diện, tất nhiên nếu muốn bạn cũng có thể làm tất cả trong file .java luôn cũng được.

Chúng ta tạo 2 file .java như sau:

package com.phocode;

import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.LayoutInflater;

public class FragmentOne extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                             Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.fragment_one, container, false);
    }
}
package com.phocode;

import android.app.Fragment;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentTwo extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                             Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.fragment_two, container, false);
    }
}

Hai lớp này sẽ kế thừa từ lớp android.app.Fragment.

public View onCreateView(LayoutInflater inflater, ViewGroup container, 
                             Bundle savedInstanceState)
{
    ...
}

Đối với Activity thì các công việc xây dựng giao diện được thực hiện trong phương thức onCreate(), còn đối với Fragment thì là phương thức onCreateView(). Phương thức này nhận vào một đối tượng LayoutInflater, ViewGroup và một đối tượng Bundle.

return inflater.inflate(R.layout.fragment_two, container, false);

Phương thức LayoutInflater.inflate() sẽ thiết kế giao diện cho lớp Fragment, phương thức này nhận vào tên file layout, tham số thứ 2 là đối tượng chứa Fragment này, trong ví dụ này là lớp LinearLayout, tham số thứ 3 cho biết Fragment có được gắn vào LinearLayout đó hay không, ở đây hai tham số sau cũng không quan trọng lắm vì trước sau gì chúng ta cũng gắn Fragment vào LinearLayout.

Sau khi đã có 2 file .java của 2 Fragment thì chúng ta tạo 2 file layout cho 2 Fragment này như sau:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:orientation="vertical" 
        android:background="#00ffff">
 
    <TextView android:id="@+id/textView1" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:layout_weight="1" 
        android:text="Fragment number 1"
        android:textStyle="bold" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent" 
        android:orientation="vertical" 
        android:background="#ffff00">
 
    <TextView android:id="@+id/textView2" 
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:text="Fragment number 2"/>
</LinearLayout>

Các file layout này khá đơn giản, chỉ chứa một TextView.

android:background="#ffff00"

Thuộc tính android:background sẽ quy định màu nền cho Fragment.

Cuối cùng là file MainActivity.java

package com.phocode;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);
    }
 
    public void selectFragment(View view)
    {
        Fragment fr;
 
        if(view == findViewById(R.id.button2))     
            fr = new FragmentTwo();     
        else    
            fr = new FragmentOne();        
 
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.fragment_place, fr);
        ft.commit();
    }
}

Chúng ta định nghĩa phương thức selectFragment() để xử lý sự kiện onClick() của Button.

Fragment fr;
 
if(view == findViewById(R.id.button2))     
    fr = new FragmentTwo();     
else    
    fr = new FragmentOne();

Ở đây chúng ta chỉ đơn giản là nếu ấn button Fragment nào thì sẽ cho hiện ra file layout của Fragment đó.

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_place, fr);
ft.commit();

Để có thể thực hiện các thao tác với Fragment thì chúng ta sử dụng đến lớp FragmentManager, lớp này sẽ tạo một đối tượng FragmentTransaction, đối tượng này cung cấp các phương thức để tạo, xóa, thay thế… các đối tượng Fragment. Phương thức replace() sẽ thay thế một Fragment bằng Fragment khác. Ngoài còn có một số phương thức khác như add() có tác dụng gắn thêm một Fragment mới vào giao diện.

Capture

Click vào nút Fragment 2 để hiển thị giao diện khác.

Capture

Android – Thao tác với Activity

Trong bài này chúng ta sẽ tìm hiểu về vòng đời của một Activity, thường thì những kiến thức dưới đây cũng không được áp dụng nhiều nhưng chúng ta cũng nên tìm hiểu sơ qua.

Không giống như các ngôn ngữ như C++, Java… các ứng dụng bắt đầu chạy từ một hàm có tên là main(), khi người dùng chạy ứng dụng Android thì ứng dụng sẽ tạo một đối tượng Activity để tương tác với người dùng, và đối tượng Activity này còn có các trạng thái khác nhau trong quá trình chạy nữa. Ví dụ như khi mới bắt đầu khởi động ứng dụng thì Activity sẽ thay thế hệ điều hành làm công việc nhận và xử lý các thông tin được gửi tới từ người dùng, tại đây hệ điều hành sẽ gọi các phương thức cần thiết để khởi tạo các thành phần chủ chốt. Khi người dùng thực hiện một hành động mà có tạo ra một Activity mới hay chuyển sang dùng một ứng dụng khác, hệ điều hành lại gọi các phương thức cần thiết khác để khởi tạo còn Activity hiện tại sẽ được chuyển sang trạng thái background, tức là Activity này không còn hiện lên trên màn hình nữa nhưng nó không bị xóa đi mà vẫn còn nằm đâu đó bên dưới hệ điều hành.

Cũng vì Activity có những trạng thái khác biệt như thế nên chúng ta cũng nên tùy biến ứng dụng theo Activity nữa, ví dụ như khi chúng ta xây dựng một ứng dụng xem video, khi người dùng thoát khỏi activity thì chúng ta nên cho tạm dừng các công việc decode, hiển thị frame, ngắt kết nối mạng…v.v rồi khi nào người dùng quay trở lại thì chúng ta mở lại video tại vị trí đã dừng.

Các phương thức Activity

Trong quá trình chạy của một Activity, hệ điều hành sẽ gọi một số phương thức theo một thứ tự nhất định, và mỗi phương thức này sẽ chuyển ứng dụng sang các trạng thái khác nhau. Chúng ta có thể xem các phương thức và trạng thái tương ứng trong hình dưới, trong đó ứng dụng bắt đầu từ phương thức onCreate() và quá trình chạy di chuyển dần lên phía trên phương thức onResume(), quá trình hủy đi dần dần xuống dưới phương thức onDestroy().

basic-lifecycle-paused

Ngoài ra Activity còn có thể đi từ trạng thái Paused (tạm dừng) và Stopped (dừng) quay lại Resumed (phục hồi).

Thường thì các phương thức này được xử lý tự động bởi hệ điều hành, nhưng cũng có một vài trường hợp chúng ta phải override lại giống như với phương thức onCreate(). Việc override các phương thức đảm bảo ứng dụng của chúng ta chạy tốt trong mọi tình huống như không bị crash khi có cuộc gọi đến hoặc người dùng chuyển sang một ứng dụng khác, hay không làm tiêu tốn tài nguyên nhiều khi người dùng không tương tác với ứng dụng, không bị ảnh hưởng bởi thao tác xoay thiết bị…

Trong hình trên chúng ta đã thấy một Activity có nhiều trạng thái khác nhau, nhưng thực ra chỉ có 3 trạng thái là có thể tồn tại trong khoảng thời gian dài là Resumed, PausedStopped. Trạng thái Resumed là trạng thái mà Activity đó đang thực sự hoạt động và tương tác với người dùng. Trạng thái Paused xảy ra khi có một Activity khác được sinh ra và thực hiện việc thao tác với người dùng thay cho Activity cũ, lúc này Activity cũ sẽ không nhận tương tác với người dùng và xử lý chúng nữa. Trạng thái Stopped là trạng thái khi Activity không còn hiện hình nữa, lúc này Activity không bị xóa nhưng cũng không nhận tương tác với người dùng.

Các trạng thái còn lại là Created, StartedDestroyed chỉ xảy ra trong một khoảng thời gian nhất định và hầu như không còn xảy ra sau đó nữa.

Khai báo main Activity

Một ứng dụng có thể có nhiều Activity, nhưng phải có một Activity chính được khởi tạo khi người dùng chạy chương trình, hệ điều hành sẽ gọi phương thức onCreate() của Activity này.

Chúng ta khai báo Activity chính trong file AndroidManifest.xml nằm ở thư mục gốc của project. Ở đây chúng ta khai báo thẻ intent-filter với thẻ actioncategory như sau:

<activity android:name=".MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Nếu chúng ta không khai báo main Activity nào thì ứng dụng sẽ không hiện ra trên màn hình của thiết bị.

Tạo Activity

Hầu hết các ứng dụng đều có nhiều hơn một Activity cho phép người dùng thực hiện nhiều công việc khác nhau. Khi thiết kế một Activity thì chúng ta phải override phương thức onCreate(), phương thức này sẽ làm các công việc mang tính khởi tạo như khởi tạo giao diện người dùng, khai báo biến, hằng số…v.v Ví dụ:

TextView textView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    textView = (TextView) findViewById(R.id.textView);
}

Sau khi hệ điều hành hoàn tất các công việc trong phương thức onCreate() thì sẽ gọi đến 2 phương thức onStart()onResume(). Tham số của phương thức onCreate() là một đối tượng Bundle, chúng ta sẽ tìm hiểu về đối tượng này sau.

Hủy Activity

Có phương thức khởi tạo Activity thì cũng sẽ có phương thức hủy Activity và đó là phương thức onDestroy(), phương thức này được gọi bởi hệ điều hành khi ứng dụng thông báo cho hệ điều hành biết là nó đã hoàn thành công việc và chuẩn bị xóa khỏi bộ nhớ.

Hầu như chúng ta không phải override lại phương thức này vì các công việc như dọn dẹp bộ nhớ, xóa biến…v.v đều được làm tự động bởi hệ điều hành. Tuy nhiên chúng ta nên override lại phương thức này khi ứng dụng của chúng ta có sử dụng đến các luồng (thread) chạy ngầm vì chúng sẽ ngốn rất nhiều tài nguyên kể cả khi chúng ta đã thoát ứng dụng chính. Ví dụ:

@Override
public void onDestroy() {
    super.onDestroy();  
    android.os.Debug.stopMethodTracing();
}

Tạm dừng Activity

Đôi khi một màn hình giao diện của một Activity sẽ bị che khuất một phần bởi các thành phần khác như hộp thoại thông báo… lúc này Activity sẽ chuyển sang trạng thái Paused được gọi bởi phương thức onPause(), một phần của Activity vẫn hiện ra trên màn hình nhưng không xử lý tương tác với người dùng. Khi người dùng quay trở lại Activity thì hệ thống sẽ gọi phương thức onResume()Activity sẽ quay lại trạng thái Resumed. 

Thông thường khi Activity ở trạng thái Paused tức là sau đó người dùng sẽ thoát luôn chứ không phải là quay lại nữa, do đó chúng ta nên làm một số công việc như xóa tài nguyên, lưu dữ liệu đang làm việc dang dở…v.v ở phương thức này. Ví dụ:

@Override
public void onPause() {
    super.onPause();

    if (mCamera != null) {
        mCamera.release();
        mCamera = null;
    }
}

Những công việc thực hiện trong phương thức onPause() nên được đơn giản hóa và không phức tạp để tăng tốc cho ứng dụng.

Khôi phục Activity

Activity sẽ được khôi phục từ trạng thái Paused sang Resumed từ phương thức onResume().

Hệ điều hành sẽ gọi phương thức onResume() mỗi khi Activity hiện lên trên màn hình, kể cả lần khởi tạo đầu tiên. Chúng ta override phương thức này cho mỗi lần khởi tạo ứng dụng. Ví dụ:

@Override
public void onResume() {
    super.onResume(); 

    if (mCamera == null) {
        initializeCamera(); 
    }
}

Dừng Activity

Activity sẽ chuyển sang trạng thái Stopped (dừng) khi phương thức onStop() được gọi, lúc này Activity không còn hiện hữu trên màn hình, ở trong phương thức này chúng ta sẽ thực hiện giải phóng tài nguyên giống như trong phương thức onPause(). Trong một số trường hợp, hệ điều hành có thể hủy ứng dụng mà không gọi tới phương thức onStop(), do đó chúng ta cũng nên override lại phương thức này đề phòng hao tổn bộ nhớ.

Phương thức onStop() được gọi sau phương thức onPause() nhưng hầu hết chúng ta sẽ thực hiện các công việc dọn dẹp và lưu trữ nhiều hơn trong phương thức onStop() như ghi dữ liệu đang làm việc vào cơ sở dữ liệu…v.v. Ví dụ:

@Override
protected void onStop() {
    super.onStop();

    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

   getContentResolver().update(
        mUri, 
        values, 
        null, 
        null
   );
}

Khi Activity đi vào trạng thái Stopped, đối tượng Activity vẫn không bị xóa mà còn nằm trong bộ nhớ và có thể được phục hồi nên chúng ta có thể không cần phải khởi tạo lại những thành phần không bị xóa. Hệ điều hành thậm chí còn lưu lại trạng thái của từng View, giả sử như người dùng nhập text vào một EditText, đoạn text đó sẽ được lưu lại và khi phục hồi Activity thì đoạn text đó cũng sẽ được phục hồi.

Khởi động/khởi động lại Activity

Khi Activity được tạo ra lần đầu tiên, hệ điều hành sẽ gọi đến phương thức onCreate→onStart()→onResume(), khi Activity được khôi phục từ trạng thái Stopped, hệ điều hành sẽ gọi đến phương thức onRestart()→onStart()→onResume().

Phương thức onRestart() được gọi khi Activity được khôi phục, do đó chúng ta có thể chỉ cần khởi tạo lại những thành phần mà không bị xóa. Nhưng thông thường thì trong phương thức onStop() chúng ta sẽ xóa gần như toàn bộ mọi thứ nên phương thức onRestart()onStart() sẽ phải khởi tạo lại tất cả mọi thứ, do đó việc override phương thức onRestart() cũng không cần thiết lắm.

Ví dụ:

@Override
protected void onStart() {
    super.onStart();
 
    LocationManager locationManager = 
    (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
 
    if (!gpsEnabled) {
        ... 
    }
}

@Override
protected void onRestart() {
    super.onRestart();
 
}

Sau khi hệ điều hành đã hủy Activity, phương thức onDestroy() sẽ được gọi nhưng thường thì chúng ta cũng không làm việc với phương thức này vì hầu như toàn bộ công việc dọn dẹp sẽ được thực hiện trong phương thức onStop(). Tuy nhiên nếu muốn bạn có thể override luôn và phương thức onDestroy() là phương thức cuối cùng để chúng ta thực hiện giải phóng tài nguyên, nên bạn cũng cần chắc chắn là đã xóa tất cả mọi thứ đề phóng trường hợp thất thoát tài nguyên.

Android – Tạo Activity

Trong phần trước chúng ta đã tạo một Activity, trong phần này chúng ta sẽ tiếp tục đoạn code ở phần trước và tạo một Activity mới khi click vào nút Send. 

Activity là một thành phần xử lý các hành động, thường thì Activity sẽ làm các công việc khởi tạo giao diện và xử lý sự kiện trên giao diện đó, thông thường chúng ta sẽ thiết kế từng giao diện ứng với từng Activity nên một Activity cũng hay được gọi là một màn hình (screen).

Xử lý sự kiện nút Send

Chúng ta sửa lại file layout chính ở bài trước.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="horizontal" >
    <EditText android:id="@+id/edit_message" 
        android:layout_width="0dp" 
        android:layout_height="wrap_content" 
        android:layout_weight="1" 
        android:hint="@string/edit_message"/>
    <Button android:layout_height="wrap_content" 
        android:layout_width="wrap_content" 
        android:text="@string/button_send" 
        android:onClick="sendMessage"/>
</LinearLayout>

Chúng ta khai báo thêm thuộc tính android:onClick cho thẻ Button, sendMessage là tên phương thức xử lý khi người dùng click vào nút Button.

Trong file MainActivity.java chúng ta sửa lại như sau:

package com.phocode.myfirstapp;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class MainActivity extends Activity {

    public final static String EXTRA_MESSAGE = "com.phocode.myfirstapp.MESSAGE";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void sendMessage(View view)
    {
        Intent intent = new Intent(this, DisplayMessageActivity.class);
        EditText editText = (EditText)findViewById(R.id.edit_message);
        String message = editText.getText().toString();
        intent.putExtra(EXTRA_MESSAGE, message);
        startActivity(intent);
    }
}

Chúng ta khai báo phương thức sendMessage tương ứng với giá trị của thuộc tính android:onClick trong file XML.

public final static String EXTRA_MESSAGE = "com.phocode.myfirstapp.MESSAGE";

Chúng ta khai báo một hằng số có tên là EXTRA_MESSAGE để dùng cho việc gửi dữ liệu đi tới Activity khác (sẽ trình bày ở dưới). Ở đây giá trị của hằng số này chúng ta dùng chính tên package cho khỏi trùng lắp và dễ nhớ, tất nhiên bạn có thể dùng giá trị khác.

public void sendMessage(View view)
{
    ...
}

Phương thức sendMessage nhận vào một đối tượng View, đây chính là đối tượng Button được click, tức là khi chúng ta chạy ứng dụng và click vào nút “Send” thì ứng dụng sẽ gọi phương thức sendMessage và gửi vào đó biến tham chiếu đến đối tượng Button này.

Lưu ý là các phương thức xử lý sự kiện như phương thức sendMessage trên phải được khai báo public, có kiểu trả về là void và tham số duy nhất là một đối tượng View.

Intent intent = new Intent(this, DisplayMessageActivity.class);

Intent là một đối tượng tạo cầu nối giữa các thành phần khác nhau trong khi ứng dụng đang chạy, nói chung là bạn chỉ cần hiểu Intent giống như một máy nhắn tin giúp trao đổi thông tin giữa các thành phần khác nhau vậy, Intent có rất nhiều công dụng nhưng thường thì người ta dùng Intent để chạy một Activity mới.

Tham số của phương thức khởi tạo Intent là một đối tượng lớp Context, ở đây chúng ta truyền this là vì lớp Activity kế thừa từ lớp Context, tham số thứ 2 là tên lớp Activity mà nó sẽ truyền tới, ở đây là lớp DisplayMessageActivity, chúng ta sẽ định nghĩa lớp này sau.

EditText editText = (EditText)findViewById(R.id.edit_message);
String message = editText.getText().toString();

Tiếp theo chúng ta lấy đối tượng EditText đã khai báo trong file main.xml bằng phương thức findViewById(), ở đây chúng ta truyền vào tên thuộc tính id đã khai báo, rồi ép kiểu về lớp EditText bởi vì phương thức này trả về một đối tượng lớp View. Sau đó chúng ta lấy đoạn chuỗi được gõ trong EditText này bằng phương thức getText(), phương thức này trả về một đối tượng Editable nên chúng ta dùng phương thức toString() để lấy giá trị ra kiểu String.

intent.putExtra(EXTRA_MESSAGE, message);

Đối tượng Intent có thể mang theo dữ liệu khi gọi một Activity mới, để truyền dữ liệu đi thì chúng ta dùng phương thức putExtra(), phương thức này nhận vào dữ liệu dạng từ điển, tức là một cặp khóa-giá tr, ở đây chúng ta dùng khóa là hằng số EXTRA_MESSAGE mà chúng ta đã khai báo ở đầu lớp, giá trị là dữ liệu trong biến message.

startActivity(intent);

Cuối cùng để chạy một Activity thì chúng ta gọi phương thức startActivity() và truyền vào một đối tượng Intent.

Tạo Activity mới

Như đã trình bày ở đầu bài, một Activity thông thường sẽ làm công việc thiết kế giao diện của một màn hình và xử lý các thao tác xảy ra trên màn hình đó. Trong một ứng dụng Android thì để thiết kế giao diện của một Activity chúng ta có 2 cách là code “chay” bằng Java bên trong file .java, 2 là thiết kế riêng trong một file XML. Ở đây chúng ta sẽ thiết kế trong file XML.

Chúng ta tạo một file XML có tên là activity_display_message.xml bên trong thư mục res/layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:id="@+id/content" 
        android:layout_width="match_parent" 
        android:layout_height="match_parent">
</RelativeLayout>

Ở đây chúng ta khai báo RelativeLayout với các thuộc tính width, heightid. Chi tiết về các layout sẽ được trình bày ở bài khác.

Tiếp theo chúng ta định nghĩa lớp Activity mới.

package com.phocode.myfirstapp;

import android.content.Intent;
import android.app.Activity;
import android.os.Bundle;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class DisplayMessageActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_display_message);

        Intent intent = getIntent();
        String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
        TextView textView = new TextView(this);
        textView.setTextSize(40);
        textView.setText(message);

        RelativeLayout layout = (RelativeLayout) findViewById(R.id.content);
        layout.addView(textView);
    }
}

Lớp DisplayMessageActivity sẽ kế thừa từ lớp Activity.

setContentView(R.layout.activity_display_message);

Khi biên dịch, các file layout sẽ được gộp lại thành một file có tên là R.java trong thư mục gen/, file này sẽ lưu các ID cho từng layout. Nhờ đó chúng ta có thể tham chiếu đến các layout ngay bên trong code Java.

Intent intent = getIntent();

Bất cứ Activity nào cũng được gọi từ một đối tượng Intent, chúng ta có thể tham chiếu đến đối tượng này thông qua phương thức getIntent().

String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

Đối tượng Intent của chúng ta có mang theo dữ liệu, chúng ta có thể lấy dữ liệu đó qua phương thức getStringExtra(), phương thức này nhận vào khóa và trả về giá trị tương ứng.

TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);

Chúng ta gán giá trị được gửi tới vào một đối tượng TextView, ở đây chúng ta khai báo trong code Java chứ không khai báo trong file layout. Phương thức setTextSize() quy định kích thước chữ, phương thức setText() sẽ quy định nội dung trong TextView đó.

RelativeLayout layout =(RelativeLayout) findViewById(R.id.content);
layout.addView(textView);

Cuối cùng chúng ta tham chiếu đến đối tượng RelativeLayout thông qua phương thức findViewById() và chèn TextView vào layout này bằng phương thức addView().

Sau khi đã định nghĩa xong lớp Activity thì chúng ta phải khai báo Activity đó trong file AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.phocode" android:versionCode="1" android:versionName="1.0">
    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
    <activity android:name="MainActivity" android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name="DisplayMessageActivity"></activity>
    </application>
</manifest>

Chúng ta chỉ cần khai báo thêm một thẻ activity với thuộc tính name là tên lớp Activity mà chúng ta sẽ định nghĩa.

Capture

Biên dịch và chạy ứng dụng, bây giờ khi bấm vào nút “Send” thì ứng dụng sẽ mở một màn hình thứ hai có một chuỗi text lấy từ EditText của màn hình trước.

Capture

 

Android – Thiết kế giao diện người dùng

Giao diện người dùng của một ứng dụng Android được xây dựng bằng các đối tượng ViewViewGroup. View là các đối tượng như button (nút bấm), text field (ô gõ văn bản)… ViewGroup là các khung dùng để chứa các đối tượng View khác, ViewGroup quy định kích thước cũng như vị trí của các View con nằm trong nó, chẳng hạn như sắp xếp các View theo chiều dọc/ngang, hoặc theo dạng bảng…

Android định nghĩa một tập các thẻ XML tương ứng với các lớp ViewViewGroup để chúng ta có thể thiết kế giao diện theo cú pháp XML một cách dễ dàng.

Từ lớp gốc ViewGroup, các lớp con kế thừa được gọi với tên là Layout. Trong phần này chúng ta sẽ làm việc với LinearLayout.

Tạo LinearLayout

Chúng ta dùng thẻ LinearLayout trong file main.xml như sau:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<LinearLayout>

Lớp LinearLayout kế thừa từ lớp ViewGroup, lớp này sẽ sắp xếp các View con theo chiều ngang hoặc chiều dọc. Các phần tử sẽ được sắp xếp theo thứ tự mà chúng được khai báo trong file XML này.

android:orientation="horizontal"

Thuộc tính android:orientation sẽ quy định là sắp xếp theo chiều ngang hay dọc, ở đây horizontal là ngang, còn vertical sẽ là dọc.

android:layout_width="match_parent"
android:layout_height="match_parent"

Hai thuộc tính android:layout_widthandroid:layout_height là bắt buộc phải có, 2 thuộc tính này sẽ quy định kích thước cho đối tượng View. Giá trị "match_parent" tức là kích thước của View con sẽ bằng kích thước của View cha, nhưng vì LinearLayout là lớp View gốc, tức là lớp này không có View cha nào cả nên ở đây lớp LinearLayout này sẽ có kích thước bằng với kích thước màn hình.

Thêm TextField

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent">
    <EditText android:id="@+id/edit_message" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:hint="@string/edit_message" />
</LinearLayout>

Chúng ta thêm thẻ EditText vào bên trong thẻ LinearLayout.

android:id="@+id/edit_message"

Thuộc tính android:id là một cái tên riêng dành cho đối tượng View mà chúng ta đã khai báo, chúng ta có thể tham chiếu tới id này giống như tham chiếu tới biến trong các file .java. Dấu @ có nghĩa là giá trị của biến này được định nghĩa trong các đối tượng resource (tiếng Anh là tài nguyên) chứ không khai báo trực tiếp ở đây, theo sau dấu @ là loại resource, ở đây là id, tiếp theo là dấu / và tên resouce edit_message.

Dấu + phía trước id có nghĩa là tại đây chúng ta định nghĩa luôn id chứ mặc định Android không biết id là cái gì cả. Khi chúng ta dịch project thì SDK sẽ nhìn cái id đó và định nghĩa một lớp có tên là ID bên trong file gen/R.java, các resource có cùng loại id sau này sẽ tự động được thêm vào ở lớp ID này để gán vào các thẻ View của chúng ta. Khi chúng ta định nghĩa một loại resource mà có dấu + thì các resource sau này có cùng loại không cần phải có dấu + nữa.

android:layout_width="wrap_content"
android:layout_height="wrap_content"

Hai thuộc tính layout_widthlayout_height cũng giống với LinearLayout, nhưng ở đây chúng ta sử dụng giá trị wrap_content, giá trị này quy định kích thước của View là vừa đủ để bọc lấy nội dung bên trong nó, chẳng hạn như EditText có 3 kí tự thì kích thước sẽ tự động co dãn để vừa khớp với 3 kí tự đó.

android:hint="@string/edit_message"

Thuộc tính android:hint sẽ hiển thị một chuỗi mặc định nếu chúng ta không gõ gì vào text field. Ở đây giá trị của thuộc tính này tham chiếu tới biến edit_message trong loại resource là string, đây là loại resource có sẵn trong file strings.xml của project nên chúng ta không cần phải thêm dấu + vào làm gì, nhưng chúng ta phải khai báo biến edit_message trong file này, chúng ta sẽ khai báo ở dưới.

Mặc dù cả 2 thuộc tính android:idandroid:hint đều tham chiếu tới resource có cùng tên là edit_message nhưng đây là 2 resource khác nhau vì chúng nằm trong 2 loại resource khác nhau là idstring.

Khai báo tài nguyên string

Mặc định khi tạo project Android thì project này có một file resource chứa loại stringres/values/strings.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <string name="app_name">MainActivity</string>
     <string name="edit_message">Enter a message</string>
     <string name="button_send">Send</string>
     <string name="action_settings">Settings</string>
</resources>

Chúng ta sẽ khai báo thêm một số resource ở đây.

<string name="edit_message">Enter a message</string>

Dòng code trên là cách khai báo một resource có kiểu là string với tên là edit_message, giá trị là Enter a message.

Thường thì khi thiết kế giao diện mà có những giá trị text thì chúng ta nên khai báo bằng biến trong file resource chứ không nên khai báo trực tiếp, tức là thay vì khai báo android:hint="Enter a message" thì chúng ta nên khai báo android:hint="@string/edit_message" hơn, rồi trong file strings.xml chúng ta khai báo thẻ string với nameedit_message. Điều này giúp chúng ta dễ dàng sửa đổi cũng như cập nhật lại sau này.

Thêm Button

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent">
    <EditText android:id="@+id/edit_message" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:hint="@string/edit_message" />
    <Button android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/button_send"/>
</LinearLayout>

Chúng ta thêm một đối tượng ViewButton.

Các thuộc tính của thẻ Button cũng giống các thuộc tính của 2 thẻ kia, chỉ khác ở chỗ là ở đây chúng ta không khai báo id, thuộc tính id là một thuộc tính không bắt buộc.

Hiện tại giao diện của ứng dụng mà chúng ta đã thiết kế sẽ như hình bên dưới.

Capture

Nhìn thì có vẻ không có vấn đề gì, nhưng nếu chúng ta nhập một chuỗi có chiều dài lớn hơn kích thước màn hình thì text field sẽ tự dãn ra và đẩy button biến mất.

Để giải quyết vấn đề này chúng ta có thể dùng đến thuộc tính android:layout_weight, thuộc tính này quy định kích thước của các View theo tỉ lệ.

Ví dụ nếu chúng ta khai báo EditTextweight là 2 và Buttonweight là 1, như thế màn hình sẽ được chia làm 1 + 2 = 3 phần, trong đó EditText sẽ chiếm 2 phần và Button sẽ chiếm 1 phần. Khi chạy ứng dụng thì các View sẽ tự động dãn ra để lấp vừa 3 phần đó, nhưng dãn vừa đủ để EditText vẫn chiếm 2/3 kích thước còn Button chiếm 1/3 kích thước.

Chúng ta sửa lại main.xml như sau:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent">
    <EditText android:id="@+id/edit_message" 
        android:layout_width="0dp" 
        android:layout_height="wrap_content" 
        android:layout_weight="1" 
        android:hint="@string/edit_message" />
    <Button android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="@string/button_send"/>
</LinearLayout>

Mặc định thuộc tính weight của các View là 0, nếu chúng ta khai báo weight cho View nào lớn hơn 0 thì view đó sẽ tự động dãn kích thước ra để lấp đầy khoảng trống còn thừa. Ở đây chúng ta khai báo weight cho EditText là 1.

android:layout_width="0dp"

Ngoài ra ở đây chúng ta cũng thiết lập lại thuộc tính android:layout_width của EditText là 0 bởi vì mặc định wrap_content sẽ yêu cầu ứng dụng phải tính toán kích thước của View dựa trên số lượng kí tự trong đó, nhưng sau đó thuộc tính weight lại yêu cầu ứng dụng dãn EditText ra để vừa khít với phần kích thước còn thừa, như thế việc tính toán kích thước của wrap_content là chẳng để làm gì cả, do đó chúng ta thiết lập “đại” sẵn một con số cụ thể nào đó luôn để ứng dụng khỏi mất công tính nữa, như thế sẽ tăng tốc độ thực thi của ứng dụng lên rất nhiều.

Capture

Chúng ta biên dịch và chạy lại ứng dụng với giao diện mới như hình trên.

Android – Tạo project Android

Một project Android sẽ chứa những file cần thiết dành cho một ứng dụng Android.

Tạo project trong Android Studio

Tạo project trong Android Studio rất đơn giản, chỉ cần vào File→New Project. Sau đó chúng ta thiết lập các thông số cho project:

  • Application Name: tên project, mình đặt là My First App
  • Company domain: đây là tên sẽ được chèn vào trước tên package
  • Package name: đây là tên package cho project, mình đặt com.phocode
  • Project location: đường dẫn đến thư mục chứa project
  • Select the form factors your app will run on: chọn Phone and Tablet
  • Minimum SDK: chọn API 8 nếu bạn đã cài phiên bản Android 2.2 (Froyo) trong SDK Manager, không thì bạn chọn API thấp nhất hiện có trong SDK Manager. Đây là phiên bản Android thấp nhất mà ứng dụng của bạn hỗ trợ.
  • Add an Activity to Mobile: chọn Empty Activity
  • Activity NameLayout Name: đặt tên file Activity là file layout, bạn có thể để mặc định

Cuối cùng nhấn Finish.

Tạo project từ dòng lệnh

Nếu bạn không cài Android Studio mà chỉ cài bộ SDK thôi thì bạn có thể tạo project từ dòng lệnh như sau:

C:\Project\Android\MyFirstApp>android create project --target android-8 --name MyFirstApp 
--path . --activity MainActivity --package com.phocode
Created directory C:\Project\Android\src\com\phocode
Added file C:\Project\Android\src\com\phocode\MainActivity.java
Created directory C:\Project\Android\res
Created directory C:\Project\Android\bin
Created directory C:\Project\Android\libs
Created directory C:\Project\Android\res\values
Added file C:\Project\Android\res\values\strings.xml
Created directory C:\Project\Android\res\layout
Added file C:\Project\Android\res\layout\main.xml
Created directory C:\Project\Android\res\drawable-hdpi
Created directory C:\Project\Android\res\drawable-mdpi
Created directory C:\Project\Android\res\drawable-ldpi
Added file C:\Project\Android\AndroidManifest.xml
Added file C:\Project\Android\build.xml
Added file C:\Project\Android\proguard-project.txt

Lệnh android create project sẽ tạo một project Android tại thư mục hiện hành trong Command Prompt. Tham số target là phiên bản SDK thấp nhất, name là tên project, path là đường dẫn đến thư mục tạo project, ở đây dấu chấm có nghĩa là đường dẫn chỉ đến thư mục hiện tại, package là tên package, activity là tên file Activity được tạo ra.

Project được tạo ra cho dù là từ Android Studio hay từ dòng lệnh cũng đều có các thư mục và file cơ bản sau đây:

bin/
libs/
res/
src/
AndroidManifest.xml  
ant.properties
build.xml
local.properties
proguard-project.txt
project.properties    

Trong đó file AndroidManifest.xml sẽ mô tả các tính chất của chương trình. Các file .java sẽ nằm trong thư mục src/. Các file tài nguyên như file XML, file ảnh… sẽ nằm trong thư mục res/. Các file apk sau khi được tạo ra sẽ nằm trong thư mục bin/. Thư mục libs/ chứa các thư viện hỗ trợ. Hai file ant.propertiesbuild.xml là các file Ant dùng cho việc biên dịch project. Cuối cùng là file local.propertiesproject.properties lưu các đặc tính của project.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.phocode" android:versionCode="1" android:versionName="1.0">
    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
        <activity android:name="MainActivity" 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>
</manifest>

File AndroidManifest.xml lưu trữ các thông tin về project mà chúng ta đã tạo, như tên package, tên file Activity… Hai chuỗi @string/app_name@drawable/ic_launcher là các giá trị tài nguyên được lưu trong các file tài nguyên trong thư mục res/, chúng ta sẽ tìm hiểu sau. Thẻ <intent-filter> nằm bên trong thẻ <activity> khai báo các công việc mà Activity có thể thực hiện, trong đó có một thẻ <action> và một thẻ <category>, cả 2 thẻ này cho biết Activity này là Activity chính được chạy khi ứng dụng chạy.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MainActivity</string>
</resources>

File strings.xml nằm bên trong thư mục res/values định nghĩa các giá trị chuỗi được sử dụng trong ứng dụng. Có thể hiểu đây giống như các biến toàn cục/hằng số được định nghĩa trước vậy. Thẻ <string> sẽ định nghĩa một biến với tên nằm trong thuộc tính name. Mặc định mỗi project Android được tạo ra sẽ có một biến tên là app_name có giá trị là tên Activity mà chúng ta tạo ra.

<?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="Hello World, MainActivity" />
</LinearLayout>

File main.xml nằm trong thư mục res/layout. File này định nghĩa giao diện cho một Activity. Khi chạy ứng dụng thì giao diện này sẽ được gọi từ phương thức onCreate().

package com.phocode;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

File MainActivity.java sẽ tạo một Activity trong phương thức onCreate() như đã nói ở trên. Mặc định phương thức này sẽ thiết lập giao diện ứng dụng là file main.xml với phương thức setContentView().

Chạy chương trình từ Android Studio

Để biên dịch và chạy ứng dụng android thì chúng ta bật máy ảo lên hoặc kết nối máy thật vào máy tính thông qua cổng USB rồi bấm nút Run có biểu tượng hình tam giác màu xanh lá cây. Android Studio sẽ hiển thị một hộp thoại cho chúng ta chọn danh sách các thiết bị có thể chạy.

Lưu ý là nếu bạn chạy trên thiết bị thật thì bạn phải bật chế độ USB Debugging trên máy thật bằng cách vào Settings → General → Developer options và check vào dòng USB Debugging. Nếu máy bạn không có tùy chọn Developer options thì tức là chế độ này đã bị ẩn, bạn phải vào Settings → About phone → Software information rồi tìm đến dòng Build number và nhấp vào đó 7 lần, sau đó tùy chọn Developer options sẽ hiện ra.

Screenshot_2016-05-05-21-18-32

Chạy chương trình từ dòng lệnh

Để có thể biên dịch và chạy từ dòng lệnh thì bạn phải tải thêm trình ant tại địa chỉ http://ant.apache.org/bindownload.cgi, sau đó giải nén và thêm đường dẫn đến thư mục bin trong thư mục ant mà bạn vừa giải nén vào biến môi trường Path.

C:\Project\Android>ant debug install

Sau đó chạy lệnh ant debug install tại thư mục chứa project để dịch chương trình. Lệnh này sẽ biên dịch và tạo ra file có tên là <tên project>-debug.apk tại thư mục bin/, ở đây là file MyFirstApp-debug.apk do chúng ta đặt tên project là MyFirstApp.

C:\Project\Android>adb devices
List of devices attached
LGD325f7d0c658  device

Để chạy ứng dụng thì chúng ta tìm các máy Android hiện đang kết nối với máy tính. Hiện tại ở đây mình sử dụng máy thật để chạy, lệnh adb devices liệt kê máy mình có tên là “LGD325f7d0c658”.

C:\Project\Android>adb install -r bin/MyFirstApp-debug.apk

Lệnh adb install <tên file apk> sẽ cài file apk vào thiết bị để chạy, tham số -r cho biết nếu trên máy đã tồn tại ứng dụng rồi thì ghi đè lên. Nếu lệnh adb devices liệt kê ra nhiều thiết bị tức là hiện tại máy bạn có nhiều thiết bị android kết nối đến, thì trong lệnh adb install bạn phải chỉ ra cả tên thiết bị đó nữa bằng tham số -s phía sau lệnh adb, ví dụ adb -s "LGD325f7d0c658" install -r bin/MyFirstApp-debug.apk.

Screenshot_2016-05-06-14-35-05

Thế là xong, bạn có thể thấy project đã được cài trên máy mình và có thể nhấp vào đó để chạy.

Screenshot_2016-05-06-14-32-19

 

Android – Giới thiệu

Android là một hệ điều hành họ Linux được thiết kế để chạy trên các thiết bị di động như smartphone, máy tính bảng, smart TV, đồng hồ thông minh, nhà thông minh… Ngôn ngữ lập trình Android là một ngôn ngữ được phát triển từ Java.

Android được bắt đầu phát triển vào năm 2003 bởi một công ty ở California, sau đó công ty này được mua lại bởi Google. Từ đó Google phát triển “Dự án Android mã nguồn mở” nhằm phát triển hệ điều hành này. Android có tốc độ phát triển rất nhanh, hầu như các bản cập nhật đều được phát hành đều đặn. Mỗi phiên bản của Android lấy tên từ một loại đồ ăn ngọt, như Donut (bánh rán), Gingerbread (bánh gừng), Jelly Bean (kẹo ngọt)… Các lập trình viên Android có thể đăng các ứng dụng mà họ viết ra lên cửa hàng ứng dụng của Google có tên là Google Play và người dùng có thể tải về cài đặt và sử dụng.

Kiến trúc của hệ điều hành Android

Android được phát triển dựa trên Linux, tầng đầu tiên của kiến trúc Android. Bộ lõi của Linux chịu trách nhiệm xử lý các công việc liên quan đến quản lý tiến trình, quản lý bộ nhớ, driver, mạng…v.v

Tầng tiếp theo nằm phía trên bộ lõi của Linux là các thư viện cơ bản và bộ thư viện Android (tiếng Anh là Android runtime). Các thư viện này được viết bằng C/C++ có nhiệm vụ cung cấp các dịch vụ như lưu trữ dữ liệu, hiển thị giao diện, xử lý đa phương tiện, duyệt web… Bộ thư viện Android lại bao gồm 2 phần là máy ảo Dalvik và các thư viện Java. Dalvik là một máy ảo có nhiệm vụ chạy các chương trình viết bằng Java trên nền Android, Dalvik khác với máy ảo Java thông thường là JVM (Java Virtual Machine).

Tầng tiếp theo là application framework, đây là một tập các hàm API cung cấp các dịch vụ cho ứng dụng Android. Các hàm API này chịu trách nhiệm xử lý các tác vụ cấp cao như quản lý Activity, quản lý Notification, quản lý Resource, hiển thị View, quản lý Package… chúng ta sẽ làm việc chủ yếu với tầng này. Không những thế Android còn cung cấp sẵn một số ứng dụng thường dùng để lập trình viên có thể sử dụng hoặc tích hợp vào chương trình của mình như trình duyệt web, SMS, lịch, bản đồ, danh sách điện thoại liên lạc…v.v.

Một số khái niệm

Một chương trình Android được nén trong một file có đuôi mở rộng là .apk.

Mỗi chương trình Android chạy trong một môi trường ảo của riêng chúng.

Một Activity một thành phần trong một ứng dụng Android chịu trách nhiệm quản lý các hành động xảy ra trên một “màn hình”, ví dụ như hiển thị một màn hình, xử lý sự kiện nhấp button…v.v một Activity được kế thừa từ lớp Activity. 

Service là các chương trình chạy ngầm bên dưới hệ điều hành, thường không tương tác trực tiếp với người dùng, kế thừa từ lớp Service. 

Content Provider là các chương trình quản lý nội dung có nhiệm vụ truy xuất dữ liệu được lưu trong file, cơ sở dữ liệu SQLite hoặc lưu trên web. Được viết từ lớp ContentProvider.

Broadcast Receiver là các chương trình quản lý các thông báo từ hệ điều hành hoặc ứng dụng, được kế thừa từ lớp BroadcastReceiver. 

Các thông báo được gửi đi là một đối tượng Intent, đối tượng này lưu thông tin về các hành động được thực hiện, thường thì Intent được dùng để thực hiện các công việc như chuyển đổi qua lại giữa các Activity.

Một View là một lớp hiển thị giao diện người dùng, lớp này có nhiệm vụ vẽ giao diện và xử lý sự kiện. Từ lớp View gốc, các lớp Widget được tạo ra kế thừa từ lớp view có nhiệm vụ hiển thị các thành phần giao diện cụ thể hơn như button, check box… Ngoài lớp View còn có lớp ViewGroup tập hợp nhiều View lại để hiển thị theo một trật tự nào đó.

Mỗi ứng dụng Android đều phải có một file tên là AndroidManifest.xml trong thư mục gốc. File này cung cấp các thông tin về ứng dụng.

Cài đặt Android

Trước tiên chúng ta phải cài JDK trong máy đã, phần này bạn tự cài, ở đây phiên bản JDK mà mình sử dụng là phiên bản 1.8.0_77.

Tiếp theo chúng ta tải và cài bộ Android SDK tại địa chỉ http://developer.android.com/sdk/index.html#downloads. Ở đây phiên bản SDK mà mình sử dụng là phiên bản r24.4.1. Lưu ý trên website download có cả phần tải Android Studio, đây là một chương trình hỗ trợ phát triển ứng dụng Android một cách nhanh chóng nhưng cũng rất nặng (cả về dung lượng lẫn cấu hình), còn riêng Android SDK chỉ nặng khoảng 144 MB. Bạn cũng có thể cài Android Studio nếu muốn, ở đây mình chỉ cài bộ SDK.

Sau khi cài xong chúng ta nên thiết lập đường dẫn đến 2 thư mục tools/ và platform-tools/ trong thư mục cài đặt SDK vào biến môi trường PATH bằng cách vào: Computer → System Properties  Advanced System Properties  Enviroment Variables, một hộp thoại hiện lên, chúng ta tìm đến biến Path trong phần System Variables và thêm vào dấu chấm phẩy “;”, sau đó là đường dẫn đến thư mục tools/ rồi thêm một dấu chấm phẩy nữa, theo sau là đường dẫn đến thư mục platform-tools/. 

Sau đó chúng ta có thể chạy SDK Manager.exe (hoặc lệnh android trong Command Linecmd nếu bạn có thiết lập biến PATH) để mở trình Android SDK Manager lên. Đây là trình quản lý các phiên bản SDK cho từng phiên bản hệ điều hành và một số công cụ thường dùng. Thường thì chúng ta sẽ cài một số phiên bản API mới nhất thôi chứ không cài hết vì chúng có dung lượng rất nặng.

Capture

Android AVD

Để chạy các ứng dụng Android thì bạn phải có một chiếc máy Android như smartphone hay tablet để chạy, nhưng nếu không có thì bạn phải dùng máy ảo. Android AVD là trình quản lý máy ảo, cho phép chúng ta tạo các thiết bị Android ảo chạy trên máy tính.

Để chạy trình AVD thì chúng ta chạy file AVD Manager.exe hoặc lệnh android avd trong Command Prompt.

Capture

Sau đó bạn bấm vào nút Create để tiến hành tạo máy ảo, bạn chọn tên và các cấu hình cần thiết. Nếu bạn không rành về các thông số như thế nào thì có thể thiết lập theo hình trên.

Sau đó AVD sẽ liệt kê chiếc máy ảo mà chúng ta vừa tạo, chúng ta có thể bấm Start để chạy chiếc máy ảo trên.

Capture

Một lựa chọn thay thế khác là bạn có thể sử dụng máy ảo Genymotion vì máy ảo mặc định của Google chiếm rất nhiều tài nguyên và mất rất nhiều thời gian để khởi động. Tuy nhiên nếu được thì chúng ta nên kiếm một chiếc máy Android thật để sử dụng thì sẽ tốt hơn.