[AndroidAdvance] Bài 2- Broadcast Receiver trong Android, đăng ký trong AndroidMaintifest và chương trình nhận tin nhắn

Ở bài trước các bạn đã biết cách đăng ký BroadcastReceiver trong Android thông qua coding để nhận biết các sự kiện của hệ thống. Bài này mình giới thiệu tiếp tới các bạn cách thứ hai để đăng ký, sử dụng xml đăng ký trong AndroidMaintifest, cách này được sử dụng phổ biến và rộng dãi hơn bởi ngay cả khi ứng dụng đang tắt nó vẫn có thể nhận được thông tin từ hệ thống và khởi động ứng dụng.

Cách đăng ký trong Android Maintifest có vẻ đơn giản hơn chỉ với thẻ receiver và intentfilter

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <!-- Đăng ký nhận BroadcastReceiver cho class MyBroadcastReceiver-->
        <receiver
            android:name="clbtinhoc.ictu.onreceiversms.MyBroadcastReceiver"
            android:label="On Receiver SMS" >
            <!-- Đăng ký lọc hành động nhận tin nhắn -->
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver >

    </application>

Để xử lý thông tin khi nhận được sự kiện nhận tin nhắn thì trong mã java ta không cần phải tạo một Activity mà chỉ cần tạo một class extends từ BroadcastReceiver, cụ thể mình sẽ demo một chương trình nhận tin nhắn như sau:
Screenshot from 2014-07-12 16:34:47

Các bạn thấy ở hình trên có một tin nhắn đến và được hiển thị ra một Dialog, số gửi tin là 5554 đây là port của máy ảo thôi, cách gửi tin nhắn đến máy ảo mình sẽ trình bày ở cuối bài viết.

Đầu tiên các bạn tạo một Project Android rỗng không có class nào cả nhé!

 

Screenshot from 2014-07-12 12:11:26

Ta sẽ đi lần lượt từng bước một, đầu tiên các bạn nhấn chuột phải vào thư mục src sau đó chọn tạo một class đặt tên là MyBroadcastReceiver.java có nội dung như sau:

package clbtinhoc.ictu.onreceiversms;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

	// Phương thức này sẽ được gọi khi chương trình nhận được sự kiện có tin nhắn đến
	@Override
	public void onReceive(Context context, Intent intent) {

		processSMS(context, intent);
	}

	public void processSMS(Context context, Intent intent) {
		// lấy đối tượng bundle mình đã nói ở loạt bài về intent
		Bundle bundle = intent.getExtras();
		// Do hệ thống trả về một loạt các tin nhắn đến cùng lúc nên phải dùng mảng
		Object[] array = (Object[]) bundle.get("pdus"); // hành động "pdus" để lấy gói tin nhắn
	
		for (int i = 0; i < array.length; i++) {
			// lệnh này dùng được chuyển đổi Object về tin nhắn createFromPdu
			SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) array[i]);
			// lấy nội dung tin nhắn
			String msg = smsMessage.getMessageBody();
			// lấy số điện thoại tin nhắn
			String number = smsMessage.getDisplayOriginatingAddress();

			// Dùng Toast để hiển thị tin nhắn
//			Toast.makeText(context, number + "\n" + msg, Toast.LENGTH_LONG).show();
			
			// Hiển thị Tin nhắn lên một Dialog
			showDialog(context, intent, number, msg);
		}

		// Hiển thị tin nhắn cuối cùng trong số loạt tin nhắn nhận được lên Activity

	}
	
	public void showDialog(Context context, Intent intent, String number, String msg){
		/*
		 * vì MyBroadcastReceiver không kế thừa context (Activity) nên khi tạo intent mới không truyền
		 * this vào được, mà phải truyền cái context đã được gửi kèm
		 */
		// Gửi dữ liệu lên Activity mới
		Intent i = new Intent(context, MyView.class);
		Bundle bundle2 = new Bundle();
		bundle2.putString("PHONE", number);
		bundle2.putString("SMS", msg);
		i.putExtra("GOITIN", bundle2);
		/* Do đang làm việc trong BroadcastReceiver và một số vấn đề liên quan tới task 
		 * trong Android nên phải thêm cờ FLAG_ACTIVITY_NEW_TASK
		 */
		i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
		context.startActivity(i); // cũng vì lý do trên nên phải dùng context để khởi động Activity

	}
}

Tại mã java xử lý trên chúng ta thấy nó không được kế thừa từ Activity như thông thường mà lại kế thừa từ BroadcastReceiver do đó để khởi động một Activity khi nhận được tin nhắn ta phải thông qua context mà được gửi kèm theo.
Đoạn mã trên có lệnh mở một Activity mang tên MyView.class nên ta sẽ tạo một class MyView nằm trong cùng package với MyBroadcastReceiver có nội dung như sau:

Class này chỉ làm nhiệm vụ đọc lại dữ liệu gửi từ MyBroadcastReceiver sau đó hiển thị lên giao diện.

package clbtinhoc.ictu.onreceiversms;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MyView extends Activity{

	@Override
	public void onCreate(Bundle bundle){
		super.onCreate(bundle);
		setContentView(R.layout.layout_dialog);
		
		final TextView textView = (TextView) findViewById(R.id.textView1);
		
		Intent intent = getIntent();
		Bundle b = intent.getBundleExtra("GOITIN");
		String sms = b.getString("SMS");
		String number = b.getString("PHONE");
		
		this.setTitle(number);
		textView.setText(sms);
		
		((Button) findViewById(R.id.button)).setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				finish();
			}
		});
	}
	
}

Đoạn code trên đã quá quen thuộc nên mình cũng không giới thiệu nhiều nữa.

Việc quan trọng nhất khi xây dựng ứng dụng nhận tin nhắn bạn phải đăng ký hành động nhận tin trong AndroidMaintifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="clbtinhoc.ictu.onreceiversms"
    android:versionCode="1"
    android:versionName="1.0" >

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

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <!-- Đăng ký nhận thông báo từ BroadcastReceiver cho class MyBroadcastReceiver-->
        <receiver
            android:name="clbtinhoc.ictu.onreceiversms.MyBroadcastReceiver"
            android:label="On Receiver SMS" >
            <!-- Đăng ký lọc hành động nhận tin nhắn -->
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver >

        <activity 
            android:name="clbtinhoc.ictu.onreceiversms.MyView"
            android:label="SMS"
            android:theme="@android:style/Theme.Dialog">
        </activity>
    </application>

</manifest>

Bình thường một ứng dụng sẽ không được phép truy cập ngẫu nhiên vào các thành phần mà hệ thống “cấm” như: Nhận tin nhắn, gửi tin, gọi điện,… do đó, ngoài việc đăng ký broadcastReceiver nhận tin nhắn bằng thẻ receiver ta còn phải đăng ký với hệ thống cho phép ứng dụng được nhận tin nhắn.

Ở trên ta có tạo một Activity MyView, nó sẽ được khởi động khi ứng dụng nhận được tin nhắn do đó trong AndroidMaintifest cũng phải đăng ký bằng thẻ . Thể hiện tính chuyên nghiệp của ứng dụn nhắn tin ta sẽ cho tin nhắn hiển thị thông qua Dialog bằng cách đặt Theme cho Activity MyView: “@android:style/Theme.Dialog”.

Ngay bây giờ bạn hãy chạy ứng dụng, khi chạy bạn sẽ không thấy có hiện tượng gì, tìm trong menu app cũng không thấy app vừa cài đâu cả là vì ứng dụng của ta không đăng ký là một chương trình laucher. Bạn thử gửi một tin nhắn vào máy mình xem, nếu mà không hiện tin nhắn bạn hãy vào phần quản lý ứng dụng xóa mặc định của các chương trình đọc tin nhắn khác đi nhé!

Note:
Với những bạn sử dụng máy ảo để test thì cách gửi tin nhắn vào máy ảo cũng khá đơn giản:
Bước 1: tại thẻ window của eclipse chọn Open Perspective\DDMS sẽ ra giao diện như hình dưới.

Screenshot from 2014-07-12 17:22:44

Bước 2: Tại thẻ Emulator trong mục Telephony Actions phần Incoming number bạn nhập số điện thoại của máy ảo. Máy ảo coi số hiệu port là số điện thoại luôn, để xem số hiệu port của máy ảo bạn mở máy ảo lên nhìn vào thanh tiêu đề ấy.

Screenshot from 2014-07-12 17:25:02

Như hình trên thì số hiệu cổng của máy ảo là 5554.

Bước 3: Chọn mục SMS sau đó nhập tin nhắn vào ô Message rồi ấn nút send là được.

Các bạn có thể download code mẫu ở đây:
https://www.dropbox.com/sh/11chl5lrj3xxg98/AAAHvHjcZ3-WXnH_6XGJfxHHa

Share this:

Thích bài này:

Thích

Đang tải…