Bài 48: Cách sử dụng Facebook SDK trong Android


Sau đây Tui sẽ trình bày các tính năng của Facebook SDK trong Android, các bạn có thể tự tìm hiểu trên internet nó có vô số ví dụ mẫu.

Tui sẽ trình bày theo cách của tui (cách của Dr Thanh), nếu các bạn hứng thú thì có thể theo dõi để viết một số App liên quan tới Facebook, vì hiện nay mạng xã hội nói chung và Facebook nói riêng nó làm thay đổi mọi hành vi của con người đặc biệt là đối với giới trẻ: ăn facebook, uống facebook, ngủ facebook, vui facebook, buồn facebook, không vui không buồn cũng facebook, cãi lộn cũng facebook, dìm hàng cũng facebook…. túm lại tình yêu đích thực của giới trẻ theo tui hình như là facebook.

- Các bạn tải Facebook SDK tại đây: https://developers.facebook.com/docs/android/

- Bạn phải biết cách đưa nó vào Eclipse để sử dụng, đây là hướng dẫn step by step bằng tiếng anh: https://developers.facebook.com/docs/android/getting-started/

- Tui sẽ trình bày lại các ví dụ mà hãng Facebook cung cấp cho các bạn hiểu cốt lõi của nó trước, sau đó Tui sẽ đưa ra các bài nâng cao để các bạn luyện công!.

Ở bài này Tui trình bày lại ví dụ hiển thị Picture Profile theo Facebook ID có giao diện của họ cung cấp như sau:

3fb0

- Ở màn hình trên, Tui sửa lại 4 Facebook ID theo nhãn: Duy Thanh, Xuân Diệu vợ Tui, Tích Đạt và Hoàng Phong là 2 người bạn.

- Hình  I’m So Cool với bộ mặt lông lá lổm chổm là của ông Hoàng Phong mà chương trình tự động lấy từ Facebook về dựa vào ID của ông Phong mà tui nhét vào Tag của Button “Hoàng Phong”.

- Các bạn tải SDK về và cố gắng đưa vào Eclipse thử xem được không, Tui nghĩ các bạn sẽ gặp một số lỗi nhưng hãy cố gắng sửa sao cho nó chạy được SDK là OK.

- Tui sẽ tiếp tục trình bày về ví dụ này cũng như Graph API để có thể lấy được danh sách bạn bè, tin nhắn…

- Các bạn chú ý theo dõi!

Bài 47: Xử lý tin nhắn SMS bằng BroadCastReceiver


Để hỗ trợ cho dự án nêu trong bài tập số 43(Đăng Ký Học Phần Bằng SMS cho các Trường Đại Học) Tui đã cung cấp hàng loạt các bài 40, 41, 44, 45, 46, 47 các bạn cần đọc kỹ lại những bài tập này trước khi bắt tay vào làm bài tập 43.

Ở bài tập 47 này, Tui muốn hướng dẫn các bạn cách sử dụng BroadCastReceiver được đăng ký chạy background trong Android Manifest, để nó có thể tự động “bắt” được tin nhắn SMS bất kỳ nào nhắn tới cho dù chúng ta không mở ứng dụng.

- Tui muốn ghi chú các bạn là:

1) Để nhận biết được đâu là Tin Nhắn đăng ký học phần thì bắt buộc các bạn phải có một CÚ PHÁP gửi tin nhắn riêng, giống như hàng ngày trên TIVI đều có hướng dẫn cú pháp đăng ký hay bỏ phiếu cho ai đó. Tương tự như vậy để nhận biết được tin nhắn đăng ký học phần thì hệ thống Website trường đại học cũng phải cung cấp CÚ PHÁP đăng ký 1 học phần như thế nào đúng không?

3) Khi 1 tin nhắn gửi tới mà ta phân tích được nó chính là tin nhắn CÚ PHÁP đăng ký học phần thì mới tiến hành xử lý đăng ký, việc xử lý đăng ký là vô cùng phức tạp vì đòi hỏi bạn phải hiểu biết cặn kẽ về quy trình xử lý học vụ, đối với trường hợp ở bài tập 43 thì bạn có thể làm ví dụ sơ sơ cũng được, nhưng theo TUI muốn làm thực tế và bán được lại cho các trường đại học muốn áp dụng công nghệ thì bạn phải đến trực tiếp trường học, liên hệ (tốt nhất là có mối quan hệ sâu sắc) để hiểu được quy trình xử lý học vụ, như vậy may ra dự án của bạn mới áp dựng thực tế còn không chỉ là làm sương sương chơi cho vui.

4) Với bài tập 47 này thì Tui chỉ làm 1 phần nhỏ: Nhận 1 tin nhắn theo cú pháp, trả lời tin nhắn có sự kiểm tra là tin nhắn đã được gửi thành công hay thất bại (dùng PendingIntent).

Công việc còn lại của bạn là sau khi nhận được tin nhắn theo cú pháp rồi, tiến hành phân tích  đưa thông tin lên  Server thông qua Webservice, kiểm tra kết quả trả về của Webservice, rồi trả lời SMS ngược lại cho người đăng ký–>có thể tự làm bài 43.

Tui có thể phác thảo mô hình phù hợp để các bạn test hệ thống này dễ dàng như sau:

3h47_0

- Dựa vào mô hình trên thì bạn có thể kiểm tra hệ thống như sau:

+ Bạn có thể biến máy tính cá nhân của bạn làm máy SERVER, CSDL + webservice được cài đặt tại máy Server này.

+ Bạn sử dụng 2 điện thoại: 1 điện thoại cài đặt phần mềm xử lý tin nhắn (gọi là Điện thoại chủ), 1 điện thoại bạn mượn đại của đứa bạn thân nhắn tin theo cú pháp vào điện thoại chủ đó. Điện thoại chủ có nhiệm vụ bắt tin nhắn và xử lý rồi gửi lên PC Server (hoặc dùng máy ảo nếu như bạn không có máy thật để test, nhưng cố gắng dùng máy thật).

- Trước khi vào ứng dụng thì tui nói CÚ PHÁP tin nhắn Tui dùng trong bài tập này để đăng ký học phần như sau:

Cú pháp:  DRTHANH MSSV MMH HK

Giải thích cú pháp:

DRTHANH là keyword đầu tiên của tin nhắn

MSSV là mã số sinh viên

MMH là mã môn học

HK là học kỳ

VÍ DỤ, nếu sinh viên gửi tin nhắn “DRTHANH 113114115 ANDROID 9″
Thì mã sinh viên =113114115
Mã môn học: ANDROID
Học kỳ 9

- Khi tin nhắn gửi tới thì ta phải phân tích nội dung tin nhắn để tiến hành xử lý cho phù hợp.

- Bạn tạo Project đơn giản như hình Tui chụp dưới đây:

3h47_1

- Bạn chú ý là thư viện KSOAP để tương tác với Webservice là bạn tự làm, Tui chủ ý không làm phần này để bạn tự tổng hợp kiến thức đưa vào đây như vậy thì mới nâng cao được kỹ năng lập trình cũng như tư duy logic cho bạn.

- Tui chỉ tiến hành làm phần BroadCastReceiver, dĩ nhiên trong này Tui có để sẵn 1 hàm Trống để bạn điền coding cập nhật vào cho dễ dàng hơn.

- Chương trình này không liên quan gì tới giao diện, vì Tui đăng ký BroadCastReceiver trong Manifest để hệ thống tự động nhận, xử lý và gửi tin nhắn (cho dù không mở ứng dụng), Nên giao diện bạn thích làm kiểu gì cũng được (tốt nhất là đừng quan tâm).

- Tui nói phần Manifest, bạn cấu hình như dưới đây:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="tranduythanh.com"
 android:versionCode="1"
 android:versionName="1.0" >
 <uses-sdk
 android:minSdkVersion="9"
 android:targetSdkVersion="18" />
 <uses-permission android:name="android.permission.SEND_SMS" />
 <uses-permission android:name="android.permission.RECEIVE_SMS" />
 <uses-permission android:name="android.permission.WRITE_SMS" />
 <uses-permission android:name="android.permission.READ_SMS" />

<application
 android:allowBackup="true"
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@style/AppTheme" >
 <activity
 android:name="tranduythanh.com.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>

<receiver android:name="MyBroadCast" >
 <intent-filter>
 <action android:name="android.provider.Telephony.SMS_RECEIVED" />
 </intent-filter>
 </receiver>
 </application>

</manifest>

- Dòng lệnh 9 ->12 là đăng ký permission cho việc Nhận tin nhắn, gửi tin nhắn, ghi tin nhắn, đọc tin nhắn.

- Dòng lệnh 29- 33 là đăng ký BroadCastReceiver trong Manifest, giúp chương trình hoạt động như service chạy nền.

- Xử lý coding MyBroadCast:


package tranduythanh.com;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.widget.Toast;

public class MyBroadCast extends BroadcastReceiver {

// All available column names in SMS table
 // [_id, thread_id, address,
 // person, date, protocol, read,
 // status, type, reply_path_present,
 // subject, body, service_center,
 // locked, error_code, seen]
 public static final String SMS_EXTRA_NAME = "pdus";
 public static final String SMS_URI = "content://sms";

public static final String ADDRESS = "address";
 public static final String PERSON = "person";
 public static final String DATE = "date";
 public static final String READ = "read";
 public static final String STATUS = "status";
 public static final String TYPE = "type";
 public static final String BODY = "body";
 public static final String SEEN = "seen";

public static final int MESSAGE_TYPE_INBOX = 1;
 public static final int MESSAGE_TYPE_SENT = 2;

public static final int MESSAGE_IS_NOT_READ = 0;
 public static final int MESSAGE_IS_READ = 1;

public static final int MESSAGE_IS_NOT_SEEN = 0;
 public static final int MESSAGE_IS_SEEN = 1;
 private Context context=null;
 @Override
 public void onReceive(Context context, Intent intent) {
 this.context=context;
 processSMS(intent);
 }
 public void processSMS(Intent intent)
 {
 // Get the SMS map from Intent
 Bundle extras = intent.getExtras();

String messages = "";

if ( extras != null )
 {
 // Get received SMS array
 Object[] smsExtra = (Object[]) extras.get( SMS_EXTRA_NAME );
 for ( int i = 0; i < smsExtra.length; ++i )
 {
 SmsMessage sms = SmsMessage.createFromPdu((byte[])smsExtra[i]);
 String body = sms.getMessageBody().toString();
 String address = sms.getOriginatingAddress();

messages += "SMS from " + address + " :\n";
 messages += body + "\n";
 //gọi hàm xử lý nội dung và gửi kết quả trả về
 doSending(address,body);
 }
 // Display SMS message từ các điện thoại khác gửi tới
 Toast.makeText( context, messages, Toast.LENGTH_SHORT ).show();
 }
 }
 public void doSending(String phoneNumber,String body)
 {
 try
 {
 //đặng ký Pending Intent để kiểm soát kết quả gửi tin nhắn trả về thành công hay không?
 final SmsManager sms = SmsManager.getDefault();
 Intent msgSent = new Intent("ACTION_MSG_SENT");
 final PendingIntent pendingMsgSent =
 PendingIntent.getBroadcast(context, 0, msgSent, 0);
 context.getApplicationContext().registerReceiver(new BroadcastReceiver() {
 public void onReceive(Context context, Intent intent) {
 int result = getResultCode();
 String msg="Gửi tin nhắn trả lời thành công";
 if (result != Activity.RESULT_OK) {
 msg="Gửi tin nhắn trả lời thất bại";
 }
 Toast.makeText(context, msg,
 Toast.LENGTH_LONG).show();
 }
 }, new IntentFilter("ACTION_MSG_SENT"));
 //nếu đúng là cú pháp đăng ký học phần.
 if(isSyntaxForRegisterCourse(body))
 {
 processRegisterCourse(body);
 sms.sendTextMessage(phoneNumber, null, "Hệ thống đã nhận được tin đăng ký học phần của bạn! chờ giây lát!",
 pendingMsgSent, null);
 }
 else
 {
 //chỉ là tin nhắn thường
 //tự động trả lời -- coi chừng tốn tiền khi dùng máy thật nhá
 sms.sendTextMessage(phoneNumber, null, "DrThanh tự động trả lời bạn! Củm ơn!",
 pendingMsgSent, null);
 }

 }
 catch(Exception ex)
 {
 Toast.makeText(context, ex.getMessage(),Toast.LENGTH_LONG).show();
 }
 }
 //Giả sử cú pháp bạn quy định là:
 //DRTHANH MSSV MMH HK
 //DRTHANH là keyword đầu tiên của tin nhắn
 //MSSV là mã số sinh viên
 //MMH là mã môn học
 //HK là học kỳ

 //VÍ DỤ body= DRTHANH 113114115 ANDROID 9
 //Thì mã sinh viên =113114115
 //mã môn học: ANDROID
 //học kỳ 9
 public boolean isSyntaxForRegisterCourse(String body)
 {
 String arr[]=body.split(" ");
 if(arr.length!=4)
 return false;
 if(!arr[0].equalsIgnoreCase("DRTHANH"))
 return false;
 return true;
 }
 /**
 * Các bạn xử lý đăng ký học phần tại đây
 * Phân tích và gửi dữ liệu lên Server thông qua Webservice
 * Vậy trên Server bạn viết 1 Webservice xử lý đăng ký học phần là OKÊ
 * @param body
 */
 public void processRegisterCourse(String body)
 {
 //tự viết lệnh chỗ này
 //xem lại các bài tập mà Tui hướng dẫn trước đó để làm
 //chúc bạn may mắn.
 }
}

- Bạn kiểm tra dòng lệnh 13, ta tạo 1 lớp tên là MyBroadCast kế thừa từ BroadCastReceiver.

- Dòng lệnh 43, onReceive dùng để tự động bắt tin nhắn khi có bất kỳ tin nhắn nào gửi tới. Tại một thời điểm thì có thể có nhiều tin nhắn gửi tới cùng 1 lúc nên ta dùng vòng lặp để lặp qua toàn bộ tin nhắn và xử lý.

- Dòng lệnh 73 là hàm doSending, ở đây Tui viết hàm này chủ ý xử lý tin nhắn gửi tới có đúng cú pháp đăng ký hay không, tùy loại tin nhắn mà ta xử lý khác nhau.

- Dòng lệnh 140, hàm processRegisterCourse, Tui để trông để bạn tự viết coding vào đây, sử dụng KSOAP API để gửi thông tin lên cho Webservice xử lý học vụ.

- Bây giờ bạn có thể test thử: Cài phần mềm này vào 1 điện thoại, lấy 1 điện thoại khác nhắn tin theo đúng cú pháp vào điện thoại cài phần mềm, thì sẽ có kết quả như mong muốn.

- Tui đã test thử trên các thiết bị điện thoại thật và đã thành công, bạn cũng thử cài đặt vào để Test cho hiệu quả.

- Bạn có thể tải source code mẫu ở đây: http://www.mediafire.com/download/k12pl9ccqu85dgn/LearnBroadCastReceiver_SMS_With_Manifest.rar

- Bài này có rất nhiều ứng dụng thực tế để kiếm tiền, và bạn cũng chú ý là rất nhiều phần mềm trên Google Play tải về có chức năng tự động gửi tin nhắn nên bạn phải cẩn thận kẻo bị trừ hết ráo không còn xu nào, khi cài đặt thì làm ơn đọc kỹ trước khi bấm Next hay OK. Thường thì nếu phần mềm có dùng SMS thì khi cài vào máy thật nó sẽ Cảnh báo, ta phải đọc kỹ, hãy bỏ thói quen tỏ vẻ nguy hiểm là không thèm đọc cứ bấm Next, OK… rất nguy hiểm.

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

Bài 46: Sử dụng .Net Webservice trong Android


Để làm được bài 46 thì các bạn nên xem qua trước bài tập 44 và 45.

Trong bài tập 46 này Tui muốn trình bày 4 ví dụ về cách tương tác từ Android tới .net web service thông qua thư viện KSOAP API.

Các ví dụ này lần lượt sẽ là:

1) Cách lấy dữ liệu Primitive Data từ .net webservice xuống Android

2) Cách lấy dữ liệu Complex Data từ .net webservice xuống Android

3) Cách truyền Parameter primitive data từ Android tới .net web service

4) Cách truyền Object data từ Android tới .net web service

Thư viện KSOAP  API các bạn tải ở đây (tạm thời tự nghiên cứu trước): http://www.mediafire.com/download/kmznar1je4702ga/ksoap2-android-assembly-2.6.0-jar-with-dependencies.jar

Tui sẽ tranh thủ đưa 4 ví dụ trên để các bạn có thể kịp làm bài tập 43.

——————————————————————————

Tất cả 4 ví dụ này Tui sẽ sử dụng Service Description của http://testdrthanh.somee.com/mywebservice.asmx?WSDL ở bài tập trước. Khi bạn mở với Service description thì nó cung cấp cho bạn đầy đủ thông tin như hình Tui chụp dưới đây:

2h46_0

NameSpace và tên hàm là rất quan trọng để dựa vào nó ta truy xuất dữ liệu, nên sai namespace hay method thì chắc chắn không thể truy suất.

Sau đây tui hướng dẫn các bạn những ví dụ ở trên

Các bài phải :

<uses-permission android:name=”android.permission.INTERNET” />

1) Cách lấy dữ liệu Primitive Data từ .net webservice xuống Android

- Bạn tạo một Project Android giống như hình Tui chụp dưới này:

2h46_1

Bạn chú ý là Tui đánh thứ tự từ 1, 2, 3, 4 là có ý đồ kỹ thuật. Bạn phải sắp xếp như vậy thì chương trình mới sử dụng đúng thư viện và có thể truy suất webservice, nếu đặt sai có thể nó báo lỗi không thể thực thi ứng dụng.

Mặc định khi bạn tạo Project thì nó sẽ không đúng thứ tự như vậy đâu, bạn phải tự làm lại thứ tự, cách đổi thứ tự như thế nào Tui sẽ nói rõ cho bạn.

Tiếp tới là bạn phải tham chiếu tới thự Viện KSOAP API mà tui khoanh màu đỏ, bạn lưu nó ở đâu thì bạn tham chiếu tới cho đúng, hoặc bạn có thể nhét nó vào thư viện libs. (bấm chuột phải vào Project / chọn Build Path/ chọn Add External Archives –> chọn đúng thư viện KSOAP API để add vào ứng dụng)

- Cách đổi thứ tự tham chiếu như sau:

Bấm chuột phải vào Project của bạn/ chọn Build Path/Configure build path…:

2h46_2

Cửa sổ mới hiển thị lên/chọn tab Order and export:

2h46_3

Ta sắp xếp như màn hình trên, để di chuyển thì dùng các nút : Up,down, top, bottom.

Bạn chú ý là phải đảm bảo rằng tất cả các mục trong này được CHECKED rồi mới bấm nút OK.

- Sau đây là giao diện chính (rất đơn giản) của project này như sau:

2h46_4- Nút “Get Catalog count” sẽ triệu gọi Service và trả về có bao nhiêu Danh mục trong Cơ sở dữ liệu.

- Cấu trúc XML của giao diện:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Number Of Catalog:" />

<TextView
 android:id="@+id/txtcount"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#008040"
 android:gravity="center"
 android:textColor="#FFFFFF"
 android:textSize="30sp" />

<Button
 android:id="@+id/btncount"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Get Catalog Count" />

</LinearLayout>

- Ta tiến hành xử lý coding trong MainActivity.java như sau:


package tranduythanh.com;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
 TextView txtcount;
 Button btncount;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //thiết lập Permit để kết nối internet
 StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);

 txtcount=(TextView) findViewById(R.id.txtcount);
 btncount=(Button) findViewById(R.id.btncount);
 btncount.setOnClickListener(new
 View.OnClickListener() {
 public void onClick(View arg0) {
 doCount();
 }
 });
 }
 public void doCount(){
 try{
 //khai báo namespace trong Webservice
 final String NAMESPACE="http://tranduythanh.com/";
 //hàm cần truy suất
 final String METHOD_NAME="CountCatalog";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
 //service description
 final String URL="http://testdrthanh.somee.com/mywebservice.asmx?WSDL";
 //khai báo đối tượng SoapOBject
 SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
 //thiết lập version
 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 //thiết lập output
 envelope.setOutputSoapObject(request);
 //tạo đối tượng HttpTransportSE
 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 //tiến hành triệu gọi Service
 androidHttpTransport.call(SOAP_ACTION, envelope);
 //lấy kết quả trả về SoapPrimitive, vì hàm CountCatalog chỉ trả về kiểu int (primitive data)
 SoapPrimitive response=(SoapPrimitive) envelope.getResponse();
 //hiển thị kết quả lên giao diện
 txtcount.setText(response.toString());
 }
 catch(Exception e) {
 e.printStackTrace();
 }
 }
}//end MainActivity

- Bạn quan sát dòng lệnh:


StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);

Dòng lệnh trên là cho phép ứng dụng kết nối tới internet, nhưng chú ý cách làm này là không TỐT, phải sửa lại. Từ Android 4.0 nó yêu cầu khi kết nối internet phải viết trong Tiểu Trình (dùng đa tiến trình, các bạn xem lại các ví dụ trước). Còn viết như bên trên TUI viết thì rất dở, nó làm Đơ Ứng Dụng vì phải mất Time Request, chỉ là giải pháp tình huống để các bạn dễ hiểu thôi.

Bạn nên xóa dòng lệnh bên trên đi, đưa hàm doCount() vào một tiểu trình (bạn dùng Handler class hoặc AsyncTask class), cách làm đa tiến trình Tui đã hướng dẫn rất kỹ lưỡng ở những bài trước, bài này các bạn tự làm (nếu không làm được thì chưa đạt).

Bạn tải source code ở đây (nhớ khi down về thì đổi lại tham chiếu tới thư viện KSOAP), bạn nên nhét nó vào thư mục Libs để chép tới nơi khác không phải tham chiếu lại:

http://www.mediafire.com/download/wo4211x3ra3x7q3/LearnWebservice_ForPrimitiveData.rar

Bạn phải chú ý làm nhiều lần để cho hiểu rõ vấn đề.

2) Cách lấy dữ liệu Complex Data từ .net webservice xuống Android

- Ở phần 1 Bạn đã biết cách truy suất webservice và trả về dữ liệu Primivite data, trong bài này Tui hướng dẫn các bạn lấy dữ liệu về dạng Complex Data.

- Cách cấu hình tham chiếu thư viện, đổi thứ tự tham chiếu … thì ở mục 1 tui đã nói, mục này Tui đi thẳng vào ứng dụng:

- Tui muốn tạo 1 Ứng dụng cho phép triệu gọi danh sách Danh Mục Sản phẩm từ webservice với giao diện vô cùng đơn giản như sau (bạn tạo ứng dụng tên là LearnWebservice_complex_data):

2h46_6- Ứng dụng trên sẽ triệu gọi hàm : getListCatalog.

- Nó khác biệt là nó trả về danh sách đối tượng Danh Mục, làm thế nào để ta lấy được danh sách đối tượng nafy???

- Sau đây là XML Layout của ứng dụng:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<Button
 android:id="@+id/btnlistcatalog"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Get List Catalog" />

<ListView
 android:id="@+id/lvcatalog"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </ListView>

</LinearLayout>

- Source code Xử lý trong MainActivity như sau:


package tranduythanh.com;

import java.util.ArrayList;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;

public class MainActivity extends Activity {
 Button btngetlist;
 ListView lvcatalog;
 final String URL="http://testdrthanh.somee.com/mywebservice.asmx?WSDL";
 ArrayList<String> arrCate=new ArrayList<String>();
 ArrayAdapter<String>adapter=null;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);
 lvcatalog=(ListView) findViewById(R.id.lvcatalog);
 btngetlist=(Button) findViewById(R.id.btnlistcatalog);
 btngetlist.setOnClickListener(new View.OnClickListener() {
 public void onClick(View arg0)
 {doGetList();}
 });
 adapter=new ArrayAdapter<String>
 (this, android.R.layout.simple_list_item_1, arrCate);
 lvcatalog.setAdapter(adapter);
 }
 public void doGetList() {
 try{final String NAMESPACE="http://tranduythanh.com/";
 final String METHOD_NAME="getListCatalog";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
 SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 envelope.setOutputSoapObject(request);
 //Nếu truyền số thực trên mạng bắt buộc phải đăng ký MarshalFloat
 //không có nó thì bị báo lỗi
 MarshalFloat marshal=new MarshalFloat();
 marshal.register(envelope);

 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 androidHttpTransport.call(SOAP_ACTION, envelope);
 //Get Array Catalog into soapArray
 SoapObject soapArray=(SoapObject) envelope.getResponse();
 arrCate.clear();
 //soapArray.getPropertyCount() return number of
 //element in soapArray
 //vòng lặp duyệt qua từng dòng dữ liệu
 for(int i=0; i<soapArray.getPropertyCount(); i++)
 {
 //(SoapObject) soapArray.getProperty(i) get item at position i
 SoapObject soapItem =(SoapObject) soapArray.getProperty(i);
 //soapItem.getProperty("CateId") get value of CateId property
 //phải mapp đúng tên cột:
 String cateId=soapItem.getProperty("CateId").toString();
 String cateName=soapItem.getProperty("CateName").toString();
 //đẩy vào array
 arrCate.add(cateId+" - "+cateName);
 }
 //xác nhận cập nhật giao diện
 adapter.notifyDataSetChanged();
 }
 catch(Exception e){}}
}

Như vậy bạn chú ý có sự khác biệt trong Vòng lặp duyệt để lấy thông tin từng dòng đối tượng, bạn chú ý ngẫm nghĩ để tự áp dụng cho các bài toán khác (lấy danh sách sản phẩm, lấy danh sách sản phẩm theo danh mục ….)

Bạn tải source code mẫu ở đây: http://www.mediafire.com/download/r2i7sayask0m9xl/LearnWebservice_complex_data.rar

Chú ý phải làm lại nhiều lần, nhất là Tui đảm bảo các bạn còn Quáng Gà với vòng lặp lấy dữ liệu ở trên.

3) Cách truyền Parameter primitive data từ Android tới .net web service

- Hai phần trên các bạn đã biết cách lấy dữ liệu primitive data và complex data từ Server về client, phần 3 này các bạn sẽ được học cách thức truyền dữ liệu từ client lên server thông qua Webservice như thế nào.

- Giao diện của bài tập 3 như sau:

2h46_7

- Mô tả sương sương như sau: Màn hình chính cho phép hiển thị danh mục, mỗi lần nhấn vào danh mục nào đó thì hiển thị danh sách sản phẩm của danh mục này. Ở đây ta dùng hàm getListProductByCatalogId của webservice để hiển thị danh sách sản phẩm theo danh mục.

-Bạn tạo Project như dưới đây:

2h46_8

- Vậy chương trình có 2 Activity, một số class: Product, Cate…

- Layout “activity_main.xml”:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<Button
 android:id="@+id/btnlistcatalog"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Get List Catalog" />

<ListView
 android:id="@+id/lvcatalog"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </ListView>

</LinearLayout>

- Layout “activity_list_product_by_catalog.xml”:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".ListProductByCatalogActivity" >
 <ListView
 android:id="@+id/lvproduct"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >
 </ListView>

</LinearLayout>

- Lớp Product:


package tranduythanh.com;

public class Product {
 private String productId;
 private String productName;
 private int quantity;
 private double unitPrice;
 private double totalMoney;
 public String getProductId() {
 return productId;
 }
 public void setProductId(String productId) {
 this.productId = productId;
 }
 public String getProductName() {
 return productName;
 }
 public void setProductName(String productName) {
 this.productName = productName;
 }
 public int getQuantity() {
 return quantity;
 }
 public void setQuantity(int quantity) {
 this.quantity = quantity;
 }
 public double getUnitPrice() {
 return unitPrice;
 }
 public void setUnitPrice(double unitPrice) {
 this.unitPrice = unitPrice;
 }
 public double getTotalMoney() {
 return totalMoney;
 }
 public void setTotalMoney(double totalMoney) {
 this.totalMoney = totalMoney;
 }
 public Product(String productId, String productName, int quantity,
 double unitPrice, double totalMoney) {
 super();
 this.productId = productId;
 this.productName = productName;
 this.quantity = quantity;
 this.unitPrice = unitPrice;
 this.totalMoney = totalMoney;
 }
 @Override
 public String toString() {
 return this.productName+"-"+(this.totalMoney);
 }

}

- Lớp Cate:


package tranduythanh.com;

public class Cate {
 private String cateId;
 private String cateName;
 public String getCateId() {
 return cateId;
 }
 public void setCateId(String cateId) {
 this.cateId = cateId;
 }
 public String getCateName() {
 return cateName;
 }
 public void setCateName(String cateName) {
 this.cateName = cateName;
 }
 public Cate(String cateId, String cateName) {
 super();
 this.cateId = cateId;
 this.cateName = cateName;
 }
 @Override
 public String toString() {
 return this.cateId.trim()+" - "+this.cateName.trim();
 }

}

- Lớp MainActivity:


package tranduythanh.com;

import java.util.ArrayList;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
 Button btngetlist;
 ListView lvcatalog;
 final String URL="http://testdrthanh.somee.com/mywebservice.asmx?WSDL";
 ArrayList<Cate> arrCate=new ArrayList<Cate>();
 ArrayAdapter<Cate>adapter=null;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);
 lvcatalog=(ListView) findViewById(R.id.lvcatalog);
 btngetlist=(Button) findViewById(R.id.btnlistcatalog);
 btngetlist.setOnClickListener(new View.OnClickListener() {
 public void onClick(View arg0)
 {doGetList();}
 });
 adapter=new ArrayAdapter<Cate>
 (this, android.R.layout.simple_list_item_1, arrCate);
 lvcatalog.setAdapter(adapter);

 lvcatalog.setOnItemClickListener(new OnItemClickListener() {
 @Override
 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
 long arg3) {
 //xử lý hiển thị danh sách sản phẩm theo danh mục
 Cate c=arrCate.get(arg2);
 Intent in=new Intent(MainActivity.this, ListProductByCatalogActivity.class);
 in.putExtra("cateid", c.getCateId());
 startActivity(in);
 }
 });
 }

 public void doGetList() {
 try{final String NAMESPACE="http://tranduythanh.com/";
 final String METHOD_NAME="getListCatalog";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
 SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 envelope.setOutputSoapObject(request);
 //Nếu truyền số thực trên mạng bắt buộc phải đăng ký MarshalFloat
 //không có nó thì bị báo lỗi
 MarshalFloat marshal=new MarshalFloat();
 marshal.register(envelope);

 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 androidHttpTransport.call(SOAP_ACTION, envelope);
 //Get Array Catalog into soapArray
 SoapObject soapArray=(SoapObject) envelope.getResponse();
 arrCate.clear();
 //soapArray.getPropertyCount() return number of
 //element in soapArray
 //vòng lặp duyệt qua từng dòng dữ liệu
 for(int i=0; i<soapArray.getPropertyCount(); i++)
 {
 //(SoapObject) soapArray.getProperty(i) get item at position i
 SoapObject soapItem =(SoapObject) soapArray.getProperty(i);
 //soapItem.getProperty("CateId") get value of CateId property
 //phải mapp đúng tên cột:
 String cateId=soapItem.getProperty("CateId").toString();
 String cateName=soapItem.getProperty("CateName").toString();
 //đẩy vào array
 Cate c=new Cate(cateId, cateName);
 arrCate.add(c);
 }
 //xác nhận cập nhật giao diện
 adapter.notifyDataSetChanged();
 }
 catch(Exception e)
 {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
 }
 }
}

- Lớp ListProductByCatalogActivity:


package tranduythanh.com;

import java.util.ArrayList;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class ListProductByCatalogActivity extends Activity {
 ListView lvproduct;
 final String URL="http://testdrthanh.somee.com/mywebservice.asmx?WSDL";
 ArrayList<Product> arrProduct=new ArrayList<Product>();
 ArrayAdapter<Product>adapter=null;
 String cateId="";
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_list_product_by_catalog);

StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);
 lvproduct=(ListView) findViewById(R.id.lvproduct);

adapter=new ArrayAdapter<Product>
 (this, android.R.layout.simple_list_item_1, arrProduct);
 lvproduct.setAdapter(adapter);

 Intent in=getIntent();
 cateId= in.getStringExtra("cateid");
 }
 @Override
 protected void onResume() {
 // TODO Auto-generated method stub
 super.onResume();
 doGetListProduct();
 }
 public void doGetListProduct()
 {
 try{
 final String NAMESPACE="http://tranduythanh.com/";
 final String METHOD_NAME="getListProductByCatalogId";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
 SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
 request.addProperty("id", cateId);
 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 envelope.setOutputSoapObject(request);
 MarshalFloat marshal=new MarshalFloat();
 marshal.register(envelope);
 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 androidHttpTransport.call(SOAP_ACTION, envelope);

 //Get Array Catalog into soapArray
 SoapObject soapArray=(SoapObject) envelope.getResponse();
 arrProduct.clear();
 //soapArray.getPropertyCount() return number of
 //element in soapArray
 //vòng lặp duyệt qua từng dòng dữ liệu
 for(int i=0; i<soapArray.getPropertyCount(); i++)
 {
 //(SoapObject) soapArray.getProperty(i) get item at position i
 SoapObject soapItem =(SoapObject) soapArray.getProperty(i);
 //phải mapp đúng tên cột:
 String productId=soapItem.getProperty("ProductId").toString();
 String productName=soapItem.getProperty("ProductName").toString();
 String squantity=soapItem.getProperty("Quantity").toString();
 String sunitPrice=soapItem.getProperty("UnitPrice").toString();
 String stotalMoney=soapItem.getProperty("TotalMoney").toString();
 int quantity=Integer.parseInt(squantity);
 double unitPrice=Double.parseDouble(sunitPrice);
 double totalMoney=Double.parseDouble(stotalMoney);
 //đẩy vào array
 Product p=new Product(productId, productName, quantity, unitPrice, totalMoney);
 arrProduct.add(p);
 }
 //xác nhận cập nhật giao diện
 adapter.notifyDataSetChanged();
 }
 catch(Exception e) {}
 }
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.list_product_by_catalog, menu);
 return true;
 }

}

- Quan sát dòng 55-56 đó là cách truyền Primivte data từ Android lên Webservice.

- Ta nên để trong OnReSume để đảm bảo rằng mọi thứ được sẵn sàng. Trong này sẽ lọc toàn bộ sản phẩm theo danh mục.

- Source code phần 3 ở đây: http://www.mediafire.com/download/3qyns57lzd2jjss/LearnWebservice_AddParameter_Primitive.rar

Các bạn chú ý phải làm lại nhiều lần bài 3 này vì nó khó và hay!

4) Cách truyền Object data từ Android tới .net web service

- Đây là phần cuối cùng Tui muốn hướng dẫn các bạn cách truyền Object Data từ Client Android lên Server thông qua Webservice.

- Ở bài tập 4 này bạn bổ sung thêm 1 hàm InsertCatalog vào Webservice, với đối số truyền vào là đối tượng Catalog:


//10 - thêm 1 catalog vào CSDL
 [WebMethod]
 public int insertCatalog(Catalog cate)
 {
 try
 {
 cate.Products.Clear();
 db.Catalogs.InsertOnSubmit(cate);
 db.SubmitChanges();
 }
 catch
 {
 return -1;
 }
 return 1;
 }

- Tui có giao diện đơn giản để demo cho phần này như sau:

2h46_9

- Khi nhấn nút “Show List Catalog”: Chương trình sẽ triệu gọi Webservice để hiển thị danh mục sản phẩm vào ListView bên dưới.

- Khi nhấn nút “Insert Cate”: Chương trình sẽ truyền đối tượng Catalog từ client lên Server thông qua Webservice. Ở đây Tui dùng cách truyền Properties cho tiện. Bạn chú ý phải quan sát kỹ Service Description của nó để truyền cho đúng Parameter:

2h46_9 2h46_10

- Tương tự như cho các hàm mà có truyền tham số khác cũng vậy, phải đặt đúng tên trong Service Descripton.

- Ta có XML Layout của ứng dụng như sau:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TextView
 android:id="@+id/textView2"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#FFFF80"
 android:text="Input Catalog:"
 android:textSize="20sp" />

<TableLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<TableRow
 android:id="@+id/tableRow1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="#F0E7B3"
 android:text="Cate Id:" />

<EditText
 android:id="@+id/editcateid"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:ems="10"
 android:inputType="text" >

<requestFocus />
 </EditText>
 </TableRow>

<TableRow
 android:id="@+id/tableRow2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="#F0E7B3"
 android:text="Cate Name:" />

<EditText
 android:id="@+id/editcatename"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:ems="10"
 android:inputType="text" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow4"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btninsertcate"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_column="1"
 android:text="Insert Cate" />
 </TableRow>
 </TableLayout>

<TextView
 android:id="@+id/textView3"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#FF80FF"
 android:text="Show List Catalog" />

<Button
 android:id="@+id/btnshowlist"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="Show List Catalog" />

<ListView
 android:id="@+id/lvcatalog"
 android:layout_width="match_parent"
 android:layout_height="fill_parent" >
 </ListView>

</LinearLayout>

- Xử lý coding cho MainActivity như sau:


package tranduythanh.com;

import java.util.ArrayList;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.MarshalFloat;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.Bundle;
import android.os.StrictMode;
import android.renderscript.Mesh.Primitive;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity
 implements OnClickListener{
 EditText txtcateid,txtcatename;
 Button btninsertcate,btnlistcate;
 ListView lvlistcatalog;
 final String NAMESPACE="http://tranduythanh.com/";
 final String URL="http://testdrthanh.somee.com/mywebservice.asmx?WSDL";
 ArrayList<String> arrCate=new ArrayList<String>();
 ArrayAdapter<String>adapter=null;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

StrictMode.ThreadPolicy policy = new
 StrictMode.ThreadPolicy.Builder()
 .permitAll().build();
 StrictMode.setThreadPolicy(policy);

txtcateid=(EditText) findViewById(R.id.editcateid);
 txtcatename=(EditText) findViewById(R.id.editcatename);
 btninsertcate=(Button) findViewById(R.id.btninsertcate);
 btnlistcate=(Button) findViewById(R.id.btnshowlist);
 btninsertcate.setOnClickListener(this);
 btnlistcate.setOnClickListener(this);
 lvlistcatalog=(ListView) findViewById(R.id.lvcatalog);

adapter=new ArrayAdapter<String>
 (this, android.R.layout.simple_list_item_1, arrCate);
 lvlistcatalog.setAdapter(adapter);
 }

@Override
 public boolean onCreateOptionsMenu(Menu menu) {
 // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.activity_main, menu);
 return true;
 }

@Override
 public void onClick(View v) {
 if(v==btnlistcate)
 {
 showlistcate();
 }
 else if(v==btninsertcate)
 {
 insertcate1();
 }
 }
 public void insertcate1()
 {
 try
 {
 final String METHOD_NAME="insertCatalog";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;

 SoapObject request=new SoapObject
 (NAMESPACE, METHOD_NAME);
 //tạo đối tượng SoapObject với tên cate như parameter trong service description
 SoapObject newCate=new
 SoapObject(NAMESPACE, "cate");
 //truyền giá trị cho các đối số (properties) như service desctiption
 newCate.addProperty("CateId",
 txtcateid.getText()+"");

 newCate.addProperty("CateName",
 txtcatename.getText()+"");
 request.addSoapObject(newCate);

 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 envelope.setOutputSoapObject(request);

 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 androidHttpTransport.call(SOAP_ACTION, envelope);
 //vì hàm insertCatalog trả về kiểu int
 SoapPrimitive soapPrimitive= (SoapPrimitive)
 envelope.getResponse();
 //chuyển về int để kiểm tra insert thành công hay thất bại
 int ret=Integer.parseInt(soapPrimitive.toString());

 String msg="Insert Cate Successful";
 if(ret<=0)
 msg="Insert Cate Failed";
 Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
 }
 catch(Exception e)
 {

}
 }//end insert cate
 public void showlistcate() {
 try
 {
 final String METHOD_NAME="getListCatalog";
 final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
 SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);
 SoapSerializationEnvelope envelope=
 new SoapSerializationEnvelope(SoapEnvelope.VER11);
 envelope.dotNet=true;
 envelope.setOutputSoapObject(request);
 MarshalFloat marshal=new MarshalFloat();
 marshal.register(envelope);
 HttpTransportSE androidHttpTransport=
 new HttpTransportSE(URL);
 androidHttpTransport.call(SOAP_ACTION, envelope);
 //Get Array Catalog into soapArray
 SoapObject soapArray=(SoapObject) envelope.getResponse();
 arrCate.clear();
 //soapArray.getPropertyCount() return number of
 //element in soapArray
 for(int i=0; i<soapArray.getPropertyCount(); i++)
 {
 //(SoapObject) soapArray.getProperty(i) get item at position i
 SoapObject soapItem =(SoapObject) soapArray.getProperty(i);
 //soapItem.getProperty("CateId") get value of CateId property
 String cateId=soapItem.getProperty("CateId").toString();
 String cateName=soapItem.getProperty("CateName").toString();
 arrCate.add(cateId+" - "+cateName);
 }
 arrCate.add(soapArray.getPropertyCount()+" -- cate");
 adapter.notifyDataSetChanged();
 }
 catch(Exception e)
 {

}
 }
}

- Bạn có thể tải source code mẫu ở đây: http://www.mediafire.com/download/pvp59a21hc5fjhn/LearnWebservice_AddParameter_ObjectData.rar

- Như vậy Tui đã hướng dẫn đầy đủ 4 trường hợp thường gặp phải khi các bạn lập trình Android với .Net Webservice. Các bạn cần chú tâm nghiên cứu, ngoài ra cần tự học thêm JSON (JavaScript Object Notation) cho đủ bộ.

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

Bài 45: Sử dụng .Net Webservice trong C#


Ở bài tập 44, Tui đã trình bày cách tạo web service và cách đưa lên internet như thế nào.

Trong bài tập 45 này, Tui sẽ dùng C# để lấy dữ liệu từ server thông qua các service đã được cung cấp ở bài tập 44. Vậy những bạn nào chưa xem bài tập 44 thì bắt buộc phải xem lại.

Lý do Tui dùng C# trước là để các bạn dễ tưởng tượng ra cách thức lấy dữ liệu trên Webservice trước khi dùng KSOAP API trong Android để tương tác (vì tui cảm thấy nó hơi khó 1 xí).

Từ WebProject ở bài tập 44, bạn tạo thêm 1 Windows Form Project để lấy dữ liệu từ Service đó như sau:

1h45_0- Khi bấm Nút “Get List Catalog”: Chương trình sẽ triệu gọi web service (hàm getListCatalog) lưu trên http://testdrthanh.somee.com/mywebservice.asmx và hiển thị vào ListBox (listbox_cate)

- Khi chọn Catalog bất kỳ trong listbox_cate thì sẽ hiển thị danh sách sản phẩm thuộc danh mục đang chọn vào listbox_product.

- Khi bấm nút “Delete Selected Product”: Sẽ xóa Product đang chọn trong listbox_product.

Sau đây là cách lấy dữ liệu từ webservice ở trên:

1- Bấm chuột phải vào Project/ chọn Add Service Reference:

1h45_1

2- Màn hình chọn WebService hiển thị ra như bên dưới đây:

1h45_2

3- Bấm chọn nút “Advanced“:

1h45_3

4- Ở màn hình trên ta chọn “Add Web Reference…“:

1h45_4

Mục số 1: Ta copy dán đường dẫn webservice vào

Mục số 2 đặt tên cho Web Reference rồi nhấn nút “Add Reference“.

Sau khi bạn nhấn nút “Add Reference” thì Project sẽ được thay đổi như sau:

1h45_5

File app.config tự động xuất hiện và bên trong nó có thông tin sau:

1h45_6

- Bây giờ ta tiến hành Coding cho các control trên giao diện như sau:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestWebService
{
 public partial class Form1 : Form
 {
 public Form1()
 {
 InitializeComponent();
 }
 bool isFinish = false;
 com.somee.testdrthanh.mywebservice test = new com.somee.testdrthanh.mywebservice();
 //Nút hiển thị danh sách Catalog
 private void button1_Click(object sender, EventArgs e)
 {
 isFinish = false;

 List<com.somee.testdrthanh.Catalog> listCate = test.getListCatalog().ToList();
 listbox_cate.DataSource = listCate;
 listbox_cate.DisplayMember="CateName";
 listbox_cate.ValueMember="CateId";
 isFinish = true;
 }
 //xử lý hiển thị danh sách sản phẩm theo danh mục
 private void listbox_cate_SelectedIndexChanged(object sender, EventArgs e)
 {
 if (!isFinish) return;
 if (listbox_cate.SelectedItem != null)
 {
 com.somee.testdrthanh.Catalog cate = listbox_cate.SelectedItem as com.somee.testdrthanh.Catalog;
 List<com.somee.testdrthanh.Product> listProduct = test.getListProductByCatalogId(cate.CateId).ToList();
 listbox_product.DataSource = listProduct;
 listbox_product.DisplayMember = "ProductName";
 listbox_product.ValueMember = "ProductId";
 }
 }
 //xử lý nút xóa Product
 private void button2_Click(object sender, EventArgs e)
 {
 if (listbox_product.SelectedItem == null)
 return;
 DialogResult ret = MessageBox.Show("Muốn xóa Product này hả?", "Xác nhận xóa", MessageBoxButtons.YesNo);
 if (ret == DialogResult.Yes)
 {
 com.somee.testdrthanh.Product p = listbox_product.SelectedItem as com.somee.testdrthanh.Product;
 bool isDelete= test.deleteProduct(p.ProductId);
 if (isDelete)
 {
 com.somee.testdrthanh.Catalog cate = listbox_cate.SelectedItem as com.somee.testdrthanh.Catalog;
 List<com.somee.testdrthanh.Product> listProduct = test.getListProductByCatalogId(cate.CateId).ToList();
 listbox_product.DataSource = listProduct;
 listbox_product.DisplayMember = "ProductName";
 listbox_product.ValueMember = "ProductId";
 }
 else
 {
 MessageBox.Show("Không xóa được");
 }
 }
 }
 }
}

Khi thực thi thì ta có kết quả như sau:

1h45_7

- Bạn cố gẳng thử cho hết các Servive  được cung cấp ở trên.

- Các bạn có thể tải source code và CSDL ở đây: http://www.mediafire.com/download/9dubk49ukme269k/code_bai44_bai45.rar

- Bài tập sau các bạn sẽ được học cách lấy dữ liệu từ Web Service bằng thự viện KSOAP API trong Android.

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

 

Bài 44: Cách tạo Webservice


Tui rất lấy làm xin lỗi vì đã để một thời gian dài mới quay lại hướng dẫn bài tập 43, vì lý do phải bận viết giáo trình một số môn học.

Để làm được “bài 43 – quản lý đăng ký học phần bằng sms cho các trường đại học”, Tui sẽ cung cấp từng kỹ năng độc lập sau đó quay lại bài 43 các bạn có thể tự làm được một cách dễ dàng.

Trong bài tập 44 này Các bạn sẽ được học:

1) Cách tạo 1 CSDL trong SQL Server

2) Cách viết .net Webservice để tương tác với CSDL

3) Cách thức đưa CSDL và .net webservice lên somee.com

——————————————————————–

1) Cách tạo 1 CSDL trong SQL Server:

- CSDL trong bài tập này sẽ được sử dụng trong hàng loạt các bài tiếp theo

- Tui muốn tạo 1 CSDL tên là dbProductManager với cấu trúc như dưới đây:

0h41_1-0h41_2- Hiển nhiên các bạn phải tự tạo được CSDL như trên.

- Bạn có thể dùng bất kỳ Version SQL Server nào cũng được (2005, 2008, 2012…)

- Tui chụp hình cấu trúc cây DB và version mà Tui Demo cho bài tập này như sau:

0h41_3

2) Cách viết .net Webservice để tương tác với CSDL

- Tui sử dụng Visual Studio 2010 để tạo Webservice, bạn có thể dùng 2012, 2013 cũng được không sao.

- Từ menu File/ chọn New/ chọn Website (hoặc nhấn tổ hợp phím Shift +ATL+ N) để tạo một website trong visual studio:

0h41_4

- Màn hình chọn Project xuất hiện: Ta chọn Empty Website như hình dưới đây rồi nhấn nút OK:

0h41_5

- Sau khi bấm OK, ta có giao diện như dưới đây:

0h41_6

- Bây giờ ta tiến hành viết .net webservice để tương tác tới CSDL tạo ở mục số 1 như sau:

- Tui muốn dùng LinQ to SQL để viết code cho lẹ và giúp các bạn dễ hiểu hơn, ta làm như sau:

Từ menu View/ chọn Server Explorer để mở cửa sổ kết nối CSDL như bến dưới đây:

0h41_7

- Trong màn hình Server Explorer/ ta bấm chọn biểu tượng kết nối mà Tui tô vòng tròn màu đỏ.

- Màn hình kết nối được hiển thị ra như dưới đây:

0h41_8

- Tui đánh theo thứ tự từ 1->5:

1) Server name: Nhập tên Server của máy bạn vào đây, trên kia thì máy của tui tên là drthanh.

2) Chọn kiểu Authentication, bạn chọn loại nào cũng được, trên kia tui chọn Windows Authentication.

3) Chọn CSDL, dĩ nhiên ta phải chọn đúng CSDL dbproductmanager.

4) Test connection để kiểm tra xem có kết nối thành công hay không, khi bạn test mà nó ra cửa sổ sau là OK:

0h41_9

5) Bấm OK để chấp nhận Kết nối.

Kết quả như sau:

0h41_10

- Bây giờ ta tiến hành dùng LinQ to SQL để tương tác tới CSDL này như sau:

Bấm chuột phải vào Project website tạo ở bước trên/ chọn Add New Item:

0h41_11

Trong màn hình New Item ta chọn LINQ to SQL Classes như hình dưới đây, đặt tên ProductManager.dbml rồi nhấn nút Add:

0h41_13

- Sau khi bấm nút Add, ta được thông tin như hình dưới:

0h41_14

- Tui đánh dấu hình trên thành 4 vùng : 1,2,3,4.

Vùng 1: là vùng CSDL

Vùng 2: Là vùng ta kéo thả CSDL vào

Vùng 3: là vùng ta kéo thả các Store Procedure vào

Vùng 4: Vùng cấu trúc tập tin, lớp mà ta lập trình.

- Bây giờ ta tiến hành kéo thả CSDL vào vùng số 1 như sau:

+ Đè phím Ctrl + click chuột vào 2 bảng Catalog và Product rồi kéo vào vùng số 2, ta được giao diện:

0h41_15

Ở bước trên, hệ thống đã tự phát sinh các lớp, hàm (CRUD) cho phép chúng ta tương tác tới CSDL một cách dễ dàng. Ở đây nó tự động sinh ra lớp ProductManagerDataContext và các lớp tương ứng với mỗi bảng (tức là có 2 lớp tự động được phát sinh: Catalog Product). Thông qua các lớp này chúng ta có thể tương tác được với CSDL. Các bạn cần học thêm phần LINQ to SQL ở mục LinQ trong menu lập trình tiên tiến: http://duythanhcse.wordpress.com/lttt/ Tui không có thời gian để nói thêm phần này.

- Tiếp tục tạo Webservice để cung cấp các hàm lấy dữ liệu, ta cũng bấm chuột phải vào Project/ chọn Add new Item để hiển thị màn hình dưới đây:

0h41_12

- Ở màn hình trên ta chọn Web Service, đặt tên cho nó (mywebservice) rồi nhấn nút Add.

- Khi nhấn nút Add, mặc định ta có thông tin của web service như sau:

0h41_16

- Ta tiến hành thêm một số hàm để sử dụng cho bài tập này như sau:

1- Hàm đếm xem có bao nhiêu danh mục trong bảng catalog

2- Hàm trả về danh sách Catalog

3- Hàm trả về thông tin của 1 Catalog theo Id

4- Hàm trả về danh sách Product

5- Hàm trả về danh sách Product theo Catalog Id

6- Hàm trả về thông tin của một Product theo Id

7- Hàm xóa Catalog theo ID

8- Hàm xóa Product theo ID.

9- Xuất tổng tiền của các mặt hàng

Ta lần lượt viết các hàm này như sau:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

/// <summary>
/// Summary description for mywebservice
/// </summary>
[WebService(Namespace = "http://tranduythanh.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class mywebservice : System.Web.Services.WebService {

ProductManagerDataContext db = null;
 public mywebservice () {

//Uncomment the following line if using designed components
 //InitializeComponent();
 db = new ProductManagerDataContext();
 }

[WebMethod]
 public string HelloWorld() {
 return "Hello World";
 }
 //Hàm đếm xem có bao nhiêu danh mục trong bảng catalog
 [WebMethod]
 public int CountCatalog()
 {
 return db.Catalogs.Count();
 }
 //2- Hàm trả về danh sách Catalog
 [WebMethod]
 public List<Catalog> getListCatalog()
 {
 List<Catalog> listCate = db.Catalogs.ToList();
 foreach (Catalog c in listCate)
 c.Products.Clear();
 return listCate;
 }
 //3- Hàm trả về thông tin của 1 Catalog theo Id
 [WebMethod]
 public Catalog getCatalog(string id)
 {
 Catalog c=db.Catalogs.FirstOrDefault(x => x.CateId == id);
 c.Products.Clear();
 return c;
 }
 //4- Hàm trả về danh sách Product
 [WebMethod]
 public List<Product> getListProduct()
 {
 List<Product> listPro = db.Products.ToList();
 foreach (Product p in listPro)
 p.Catalog = null;
 return listPro;
 }
 //5- Hàm trả về danh sách Product theo Catalog Id
 [WebMethod]
 public List<Product> getListProductByCatalogId(string id)
 {
 List<Product> listPro=db.Products.Where(x => x.CateId == id).ToList();
 foreach(Product p in listPro)
 p.Catalog=null;
 return listPro;
 }
 //6- Hàm trả về thông tin của một Product theo Id
 [WebMethod]
 public Product getProduct(string id)
 {
 Product p = db.Products.FirstOrDefault(x => x.ProductId == id);
 p.Catalog = null;
 return p;
 }
 //7- Hàm xóa Catalog theo ID
 [WebMethod]
 public bool deleteCatalog(string id)
 {
 try
 {
 Catalog cate = getCatalog(id);
 db.Catalogs.DeleteOnSubmit(cate);
 db.SubmitChanges();
 }
 catch (Exception ex)
 {
 return false;
 }
 return true;
 }
 //8- Hàm xóa Product theo ID.
 [WebMethod]
 public bool deleteProduct(string id)
 {
 try
 {
 Product p = getProduct(id);
 db.Products.DeleteOnSubmit(p);
 db.SubmitChanges();
 }
 catch (Exception ex)
 {
 return false;
 }
 return true;
 }
 //9- Xuất tổng tiền của các mặt hàng
 [WebMethod]
 public double getToTalMoney()
 {
 return db.Products.Sum(x => x.TotalMoney).Value;
 }
}

- Bạn chú ý đoạn code ở trên tui gán =null nhiều chỗ lý do để xử lý việc Loop trong thao tác Webservice, nếu có sự loop (hay đệ quy) thì nó không chấp nhận. Nếu viết bằng Winform hay Webform bình thường thì không sao.

- Ta tiến hành kiểm tra webservice trên máy cục bộ như sau (nhấn F5 để chạy):

0h41_17

bạn Thấy đấy, các hàm được hiển thị ra ở đây. Để test thì bạn chỉ cần bấm vào hàm rồi chọn Invoke là OK. Tui ví dụ chọn hàm CountCatalog và getListCatalog, getListProductByCatalogId:

0h41_18

0h41_190h41_20

Mục đích của chúng ta là kết nối từ Android tới Webservice này để tương tác. Bạn có thể cấu hình IIS để chạy trên máy cục bộ, nhưng ở đây TUI muốn hướng dẫn các bạn đưa nó lên Internet (trang Somee) để demo thực tế, tại vì thực tế là nó nằm trên internet. Android chỉ là Client.

3) Cách thức đưa CSDL và .net webservice lên somee.com

- Bước 1: Vào https://somee.com

- Bước 2: Chọn Free .Net hosting như hình dưới đây:

0h41_21

Bấm chọn Learn More để qua bước 3.

Bước 3: Chọn Order để mua gói miễn phí này:

0h41_22

Bước 4: Nhập các thông số cần thiết để tạo tạo tài khoản:

0h41_23- Bấm Register new user and continue để đăng ký và tiếp tục với màn hình checkout.

0h41_24

Bước 5: – Chọn các thông số rồi bấm Continue, màn hình Create Website sẽ hiển thị ra như bến dưới, ta nhập các thông tin rồi bấm:

0h41_25Màn hình thông báo thành công hiển thị ra dưới đây:

0h41_26- Tiếp theo ta tạo CSDL cho trang testdrthanh.somee.com

- Bấm chọn mục Databases ở bên tay trái trên màn hình ở trên:

0h41_27

Màn hình trên nó nút “Create” mà Tui khoanh màu đỏ, ta bấm vào nó. Màn hình tạo CSDL hiển thị ra, ở đây ta nên đặt cùng tên với CSDL mà ta tạo ở máy Client để dễ dàng Backup, Restore .

0h41_28

Sau khi nhập đầy đủ thông tin, bấm chọn “Create empty database”.

sau khi tạo thành công thì ta có màn hình như dưới đây:

0h41_29

Bạn để ý dòng Tui tô xanh lè, đó chính là chuỗi kết nối tới CSDL, bạn có thể copy paste chuỗi này dán vào chuỗi kết nối ở máy Local của bạn thì khi chạy website nó sẽ kết nối tới CSDL ở trên trang somee này.

workstation id=dbproductmanager.mssql.somee.com;packet size=4096;user id=drthanh_SQLLogin_1;pwd=7szjt75abq;data source=dbproductmanager.mssql.somee.com;persist security info=False;initial catalog=dbproductmanager

- testdrthanh.somee.com chính là sub domain mà nó cung cấp cho mình, dựa vào đây để ta lấy thông tin.

- Bây giờ ta tiến hành đưa dữ liệu từ máy Local lên Trang somee, làm như sau:

1- Backup lại CSDL tại máy Local của bạn:

Bấm chuột phải vào CSDL/ chọn Tasks/ Chọn Backup:

0h41_30

Màn hình chọn Backup hiển thị ra như dưới đây, ta tiến hành nhập thông số rồi bấm OK:

0h41_31

Giờ bạn kiểm tra ổ đĩa D:/ xem có tập tin này hay chưa, nếu có tức là đã backup thành công.

2- Đưa file Backup này lên Server somee:

0h41_32Ta chọn Restore database, rồi chọn “Choose File“, chọn đúng tập tin vừa backup ở trên rồi bấm “Upload the file and restore it“.

Chờ báo thành công là OK:

0h41_33Để test coi nó có chạy được hay không thì ta chọn mục “New SQL Query” ở màn hình trên, nó sẽ hiển thị ra cửa sổ cho phép ta nhập câu SQL:

0h41_34

- Như hình trên thì đã thành công.

3- Tiếp tục ta đưa Webservice lên somee để Test như sau:

- Dùng Win Zip  của hệ điều hành Windows, nén lại source code và đẩy lên server. Dĩ nhiên ta cần sửa chuỗi kết nối lại. Như mục trên Tui đã nói là copy paste chuỗi kết nối :

workstation id=dbproductmanager.mssql.somee.com;packet size=4096;user id=drthanh_SQLLogin_1;pwd=7szjt75abq;data source=dbproductmanager.mssql.somee.com;persist security info=False;initial catalog=dbproductmanager

Thay thế cho chuỗi có sẵn ở máy Local như sau (dĩ nhiên khi bạn tạo thì chuỗi nó phải khác và bạn phải lấy theo chuỗi của bạn):

Trong Project Web Service, mở tập tin Web.config và thay thế bằng chuỗi trên:

0h41_36

- Sau đó tiến hành zip như sau:

0h41_37

- Ở hình trên là ta Ctrl+ A để chọn toàn bộ tập tin và thư mục/sau đó ta bấm chuột phải vào 1 tập tin bất kỳ trong thư mục chứa source code/ chọn Send to / chọn Compressed… như hình bên trên, nó phát sinh ra một file zip chứa toàn bộ source code trong này (ta chọn tập tin nào để bấm chuột phải cũng được).

- Sau khi có file zip, ta quay lại màn hình somee server để đưa source code lên như sau:

1- Chọn File Manager/ cửa sổ hiển thị lên chọn nút Upload như hình bên dưới:

0h41_38

Sau khi chọn nút Upload thì nó xuất hiện cho chúng ta nút Choose File để đưa file từ client lên Server/ ta chọn đúng file zip lúc này rồi bấm Upload and Unzip archives:

0h41_39

- Sau khi bấm Upload and unzip archives thì ta có kết quả như sau:

0h41_40- Bạn thấy đấy, toàn bộ source code đã được đưa lên server.

- Bây giờ ta tiến hành kiểm tra Webservice có chạy hay không như sau:

http://testdrthanh.somee.com/mywebservice.asmx :

0h41_41

Như vậy là đã thành công, bạn có thể tiến hành kiểm tra từng Service trong này.

Bài tập này Tui đã hướng dẫn chi tiết cách tạo Webservice, cách tạo CSDL, cách đưa dữ liệu lên Server somee, cách sử dụng LinQtoSQL…

Bạn cần thực hành nhiều lần và cố gắng hiểu nó.

Trong bài tập kế tiếp Tui sẽ hướng dẫn các bạn cách dùng Android kết hợp với KSOAP API để lấy dữ liệu từ webservice này.

Bài tập này rất quan trọng, nó rất hữu ích cho các bạn đặc biệt là khi triển khai dự án thực.

Các bạn có thể tải source code và CSDL ở đây, nhớ đổi lại chuỗi kết nối khi thử trên máy tính cá nhân của bạn: http://www.mediafire.com/download/xsuou1aakukrlep/Hoc_Webservice.rar

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

Bài 43: Android vs .net Web Services


1) Có cách nào Tương Tác giữa chú Dế Yêu với Máy Tính của bạn không?

2) Có cách nào Tương Tác giữa chú Dế Yêu với một Server gì đó ở trên Internet hay không?

3) Có cách nào truyền tải dữ liệu qua lại giữa  Dế Yêu và Máy Tính hay không?

4) Có cách nào biến Dế Yêu thành người đều phối dữ liệu giữa Nhiều Mobile khác với 1 Server nào đó hay không?

Câu trả lời của tui là được.

Dưới đây là hình tui chụp sự tương tác giữa Dế yêu của Tui với Laptop của Tui:

connect_mobile_pc

Để thực hiện được 4 câu hỏi của Tui ở trên thì bắt buộc các bạn phải có các kiến thức sau (Nếu chưa có thì khoan hay theo dõi bài này nếu không sẽ bị Tẩu Hỏa Nhập Ma):

1) Có kiến thức về .net Webservices (biết tạo webservices với Asp.net, C# , biết cấu hình IIS)

2) Biết Microsoft SQL Server

3) Có kiến thức về SOAP

4) Biết xử lý một số lỗi liên quan tới Internet

5) …..và biết gì thêm nữa càng tốt….

Trong bài tập này tui muốn hướng dẫn các bạn thật nhiều thứ theo từng bước, các bạn cần Chăm Chỉ, Cần Mẫn đọc từng dòng lệnh và những hướng dẫn của tui. Sau khi Bạn hiểu bài này Tui sẽ làm một ứng dụng “Đăng Ký Học Phần Bằng SMS cho các Trường Đại Học“.

Tui sẽ chuẩn bị những kiến thức sau:

1) Làm sao để viết được .net Webservices

2) Làm sao cấu hình được IIS

3) Dùng .Net Webservices để tương tác với SQL Server

4) Đưa Webservice lên Server Miễn Phí để test thực tế (trang http://somee.com/)

5) Những cách kết nối giữa Mobile và PC

6) KSOAP API để truyền tải dữ liệu giữa Mobile với PC Server

Vậy trong thời gian chờ Tui viết hướng dẫn, các bạn hãy tự xem trước những kiến thức cần thiết (ví dụ như Asp.net, C#, Sqlserver…)

Các bạn chú ý theo dõi bài tập vô cùng phức tạp và vô cùng hay ho này, tui nghĩ nó sẽ hớp hồn các bạn

Các bạn muốn củng cố thêm kiến thức về Java thì có thể vào học lớp BoiDuong_MSP Lịch giảng dạy, lớp này giảng dạy miễn phí về kỹ thuật lập trình hướng đối tượng cho sinh viên thuộc khoa Công Nghệ Thông Tin.

Bài 42: Đáp án mẫu đề thi cuối kỳ Android


Dưới đây là đáp án mẫu cho 2 đề thi cuối kỳ Android của lớp 13DTH1LT2

Đề 1:LTDiDong_12DTH1LT3_DeThiCuoiKy_2013_MD001

Đề 2:LTDiDong_12DTH1LT3_DeThiCuoiKy_2013_MD002

Ở đây Tôi chỉ giải câu 1 của các đề trên, câu 2 Sqlite các bạn tự làm vì nó rất dễ, các bài tập trước đó đều đã làm qua.

Câu 1 – đề 1:

s1Tôi sẽ xử lý lệnh vẽ Button và căn lề Button theo vị trí xuất hiện (tính từ vị trí 0)

- XML Layout cho câu hỏi này là:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btnDrawButton"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Draw Button:" />

<EditText
 android:id="@+id/editNumber"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:ems="10" />

</LinearLayout>

<ScrollView
 android:id="@+id/scrollView1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<LinearLayout
 android:id="@+id/layout_draw_button"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

</LinearLayout>

 </ScrollView>

&nbsp;

</LinearLayout>

Source xử lý:


package tranduythanh.com;

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.graphics.Point;
import android.view.Display;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;

public class MainActivity extends Activity {

Handler handlerMain;
 AtomicBoolean atomic=null;
 LinearLayout layoutdevebutton;
 Button btnOk;
 EditText edtOk;
 int sizehalf=0;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 //lấy LinearLayout chứa Button ra
 layoutdevebutton=(LinearLayout) findViewById(R.id.layout_draw_button);
 final Random rd=new Random();
 btnOk=(Button) findViewById(R.id.btnDrawButton);
 edtOk=(EditText) findViewById(R.id.editNumber);
 handlerMain=new Handler()
 {
 @Override
 public void handleMessage(Message msg) {
 // TODO Auto-generated method stub
 super.handleMessage(msg);
 //Nhận nhãn của Button được gửi về từ tiến trình con
 int v=rd.nextInt(100);
 String nhan_button=v+"";
 //khởi tạo 1 Button
 Button b=new Button(MainActivity.this);
 //thiết lập nhãn cho Button
 b.setText(nhan_button);
 //thiết lập kiểu Layout : Width, Height
 LayoutParams params=new
 LayoutParams(LayoutParams.WRAP_CONTENT,
 LayoutParams.WRAP_CONTENT);
 if(msg.arg1%2==0)
 params.gravity=Gravity.LEFT;
 else
 params.gravity=Gravity.RIGHT;
 //thiết lập layout cho Button

 b.setWidth(sizehalf);
 b.setLayoutParams(params);
 //đưa Button vào layoutdevebutton
 layoutdevebutton.addView(b);

 }
 };
 btnOk.setOnClickListener(new OnClickListener() {

@Override
 public void onClick(View arg0) {
 // TODO Auto-generated method stub
 doStart();
 }
 });
 }
 @Override
 protected void onResume() {
 // TODO Auto-generated method stub
 super.onResume();
 //lấy màn hình điện thoại đang sử dụng
 Display display = getWindowManager().getDefaultDisplay();
 Point size = new Point();
 display.getSize(size);
 sizehalf=size.x/2;
 }
 private void doStart()
 {
 layoutdevebutton.removeAllViews();
 atomic=new AtomicBoolean(false);
 final int sobutton=Integer.parseInt(edtOk.getText()+"");
 Thread thCon=new Thread(new Runnable() {

 @Override
 public void run() {
 // TODO Auto-generated method stub

 for(int i=0;i<sobutton && atomic.get();i++)
 {
 //nghỉ 200 mili second
 SystemClock.sleep(200);
 //lấy message từ Main Thread
 Message msg=handlerMain.obtainMessage();
 //gán dữ liệu cho msg Mainthread, lưu vào biến obj
 //chú ý ta có thể lưu bất kỳ kiểu dữ liệu nào vào obj
 msg.arg1=i;
 //gửi trả lại message cho Mainthread
 handlerMain.sendMessage(msg);
 }
 }
 });
 atomic.set(true);
 //thực thi tiến trình
 thCon.start();
 }

}

- Câu 1 – đề 2:

s3

 

Xml Layout:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btnDrawButton"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Draw View:" />

<EditText
 android:id="@+id/editNumber"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:ems="10" />

</LinearLayout>

<ScrollView
 android:id="@+id/scrollView1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<LinearLayout
 android:id="@+id/layout_draw_button"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

</LinearLayout>

 </ScrollView>

&nbsp;

</LinearLayout>

Xử lý source code:


package tranduythanh.com;

import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.graphics.Point;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

public class MainActivity extends Activity {

Handler handlerMain;
 AtomicBoolean atomic=null;
 LinearLayout layoutdevebutton;
 Button btnOk;
 EditText edtOk;
 int sizehalf=0;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 //lấy LinearLayout chứa Button ra
 layoutdevebutton=(LinearLayout) findViewById(R.id.layout_draw_button);
 final Random rd=new Random();
 btnOk=(Button) findViewById(R.id.btnDrawButton);
 edtOk=(EditText) findViewById(R.id.editNumber);
 handlerMain=new Handler()
 {
 @Override
 public void handleMessage(Message msg) {
 // TODO Auto-generated method stub
 super.handleMessage(msg);
 //Nhận nhãn của Button được gửi về từ tiến trình con
 int v=rd.nextInt(100);
 String nhan_button=v+"";
 //khởi tạo 1 Button
 View vv=null;
 if(msg.arg1%2==0)
 {
 vv=new Button(MainActivity.this);
 ((Button) vv).setText(nhan_button);
 }
 else
 {

 vv=new EditText(MainActivity.this);
 ((EditText) vv).setText(nhan_button);
 }

 LayoutParams params=new
 LayoutParams(LayoutParams.MATCH_PARENT,
 LayoutParams.WRAP_CONTENT);
 vv.setLayoutParams(params);

 //đưa Button vào layoutdevebutton
 layoutdevebutton.addView(vv);

 }
 };
 btnOk.setOnClickListener(new OnClickListener() {

@Override
 public void onClick(View arg0) {
 // TODO Auto-generated method stub
 doStart();
 }
 });
 }
 @Override
 protected void onResume() {
 // TODO Auto-generated method stub
 super.onResume();
 Display display = getWindowManager().getDefaultDisplay();
 Point size = new Point();
 display.getSize(size);
 sizehalf=size.x/2;
 }
 private boolean isPrime(int n)
 {
 if(n<2)return false;
 for(int i=2;i<=Math.sqrt(n);i++)
 if(n%i==0)return false;
 return true;
 }
 private void doStart()
 {
 layoutdevebutton.removeAllViews();
 atomic=new AtomicBoolean(false);
 final int sobutton=Integer.parseInt(edtOk.getText()+"");
 Thread thCon=new Thread(new Runnable() {

 @Override
 public void run() {
 // TODO Auto-generated method stub

 for(int i=0;i<sobutton && atomic.get();i++)
 {
 //nghỉ 200 mili second
 SystemClock.sleep(200);
 //lấy message từ Main Thread
 Message msg=handlerMain.obtainMessage();
 //gán dữ liệu cho msg Mainthread, lưu vào biến obj
 //chú ý ta có thể lưu bất kỳ kiểu dữ liệu nào vào obj
 msg.arg1=i;
 //gửi trả lại message cho Mainthread
 handlerMain.sendMessage(msg);
 }
 }
 });
 atomic.set(true);
 //thực thi tiến trình
 thCon.start();
 }

}

Các bạn có thể tải đáp án mẫu tại đây:

Đáp án mẫu câu 1 đề 1: https://www.mediafire.com/download/ob6mc2webu37usb/ThiCuoiKy_De1_Cau1.rar

Đáp án mẫu câu 1 đề 2: http://www.mediafire.com/download/w3rn3thi7bqh1gk/ThiCuoiKy_De2_Cau1.rar

Bài 41: Phần mềm xử lý tin nhắn rắc


Ở bài tập 40 Tui đã trình bày cách đăng ký BroadCast Receiver để lắng nghe tin nhắn gửi tới trong Coding, Ở  bài tập này Tui sẽ trình bày cách đăng ký và xử lý BroadCast Receiver bằng Manifest. Ứng dụng này là thực tế, các bạn có thể cài đặt vào thiết bị thật để kiểm tra.

Bài này Tui sẽ lấy kết quả bài làm của Sinh viên học lớp Tui để demo cho các bạn xem, các bạn có thể liên hệ với bạn này để trao đổi học thuật. Tên của bạn là Nguyễn Tấn Nhân, email Nhan.NguyenTan@uni.dntu.edu.vn

Bài Tui yêu cầu các bạn làm bài như sau:

-          Viết ứng dụng Android xử lý tin nhắn rác.

-          Hiện nay rất nhiều tin nhắn quẳng cáo gửi vô tội vạ, cái Alô của bạn phải nhận rất nhiều tin nhắn như thế gây phiền hà và mất thời gian cho bạn.

-          Hãy viết chương trình để giải quyết vấn đề này, yêu cầu như sau:

  • Chương trình có giao diện thêm, sửa, xóa các đầu số mà bạn cho là đầu số rác. Như vậy nên dùng SQLite hoặc XML để lưu các đầu số rác.
  • Chương trình phải tự động nhận tin nhắn và phát hiện ra được tin nhắn nào là gửi đi từ các đầu số rác đó.
  • Nếu phát hiện ra đó là đầu số rác  thì xóa nó khỏi inbox của messaging đồng thời phát ra Audio là “đây là tin nhắn rác, đã bị xử” để người sử dụng không phải mở điện thoại lên xem.

-          Yêu cầu viết theo 2 cách (tức là bài tập này làm thành 2 Project khác nhau):

  • Đăng ký Broadcast Receiver để nhận tin nhắn tới trong coding
  • Đăng ký Broadcast Receiver để nhận tin nhắn tới trong Manifest XML

-          Sau khi làm xong theo 2 cách trên, hãy so sánh sự khác biệt giữa chúng. Và kết luận chúng ta nên chọn cách nào?

-          Chương trình phải cài đặt và chạy được trên điện thoại Android thiệt.

rac1

-          Khi nhấn thật lâu vào 1 đầu số trong ListView thì số này sẽ tự động Remove khỏi CSDL

- Dưới đây là kết quả bài làm mà sinh viên trên đã tự thực hiện:

- Tôi sẽ để nguyễn mẫu và không giải thích, các bạn nếu không hiểu thì hãy email trực tiếp để hỏi sinh viên này:

s0

XML Layout của màn hình chính:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="2dp"
    android:paddingLeft="2dp"
    android:paddingRight="2dp"
    android:paddingTop="2dp"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#008000"
        android:gravity="center_horizontal"
        android:text="Quản lý tin nhắn rác"
        android:textColor="#FFF"
        android:textSize="26sp" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#FFFF00"
        android:text="Nhập vào số rác:"
        android:textSize="18sp" />

    <EditText
        android:id="@+id/editPrefixPhoneNum"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/btnSave"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Lưu số rác này"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFF00"
        android:gravity="center_horizontal"
        android:text="Danh sách số phone rác"
        android:textSize="18sp" />

    <ListView
        android:id="@+id/lstviewList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

Để tương tác với SMS thì ta cấu hình trong Manifest như sau:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="vn.edu.it.nguyentannhan.id1200911"
 android:versionCode="1"
 android:versionName="1.0" >

<uses-sdk
 android:minSdkVersion="8"
 android:targetSdkVersion="17" />
 <uses-permission android:name="android.permission.RECEIVE_SMS"/>
 <uses-permission android:name="android.permission.WRITE_SMS"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
 android:allowBackup="true"
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@style/AppTheme" >
 <activity
 android:name="vn.edu.it.nguyentannhan.id1200911.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>
 <receiver android:name="MySmsReceive">
 <intent-filter>
 <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
 </intent-filter>
 </receiver>
 </application>

</manifest>

Xử lý coding:

MainActivity:


package vn.edu.it.nguyentannhan.id1200911;
import java.util.ArrayList;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {

SQLiteDatabase sqlite;
 Button btnSave;
 EditText editFrefixNum;
 ListView lstPreNum;
 //
 //String idUpdate="";
 //
 ArrayList<String>arrPreNum;
 ArrayAdapter<String>adapter = null;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 //deleteDatabase();
 createDatabase();
 init();
 event();
 loaddata();
 }
 void loaddata()
 {
 try {
 arrPreNum = new ArrayList<String>();
 sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
 final String []columns ={"id","prefixNum"};
 //Cursor cusor = sqlite.query("tblGarbage", columns , "id,prefixNum", null, null, null, "prefixNum");
 Cursor cusor = sqlite.query("tblGarbage", columns , null, null, null, null, null);
 cusor.moveToFirst();
 String data="";
 while(cusor.isAfterLast()==false)
 {
 data= (String) cusor.getString(0).toString();//+" - " + (String)cusor.getString(1).toString();
 arrPreNum.add(data);
 cusor.moveToNext();
 }
 adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, arrPreNum);
 lstPreNum.setAdapter(adapter);
 //adapter.notifyDataSetChanged();

 } catch (Exception e)
 {
 // TODO: handle exception
 Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_SHORT).show();
 }

 }
 void cleartext()
 {
 editFrefixNum.setText("");
 }
 void init()
 {
 btnSave = (Button) findViewById(R.id.btnSave);
 editFrefixNum = (EditText) findViewById(R.id.editPrefixPhoneNum);
 lstPreNum = (ListView) findViewById(R.id.lstviewList);
 }
 void event()
 {
 btnSave.setOnClickListener(new OnClickListener() {

 @Override
 public void onClick(View v) {
 // TODO Auto-generated method stub
 insertData(editFrefixNum.getText().toString());
 loaddata();
 }
 });

 lstPreNum.setOnItemClickListener(new OnItemClickListener()
 {

@Override
 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {
 // TODO Auto-generated method stub
 editFrefixNum.setText((String)arrPreNum.get(arg2).toString());
 //idUpdate =(String)arrPreNum.get(arg2).toString();
 }
 });

 lstPreNum.setOnItemLongClickListener(new OnItemLongClickListener()
 {
 @Override
 public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
 // TODO Auto-generated method stub
 AlertDialog.Builder bui = new AlertDialog.Builder(MainActivity.this);
 bui.setTitle("Cảnh báo !");
 //final int index = arg2;
 final String id= (String)arrPreNum.get(arg2).toString().trim();
 bui.setPositiveButton("OK", new AlertDialog.OnClickListener() {

 @Override
 public void onClick(DialogInterface dialog, int which) {
 // TODO Auto-generated method stub
 //arrPreNum.remove(index);
 sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
 if(sqlite.delete("tblGarbage", "id=?", new String []{id}) != -1)
 {
 loaddata();
 cleartext();
 Toast.makeText(MainActivity.this, "Xóa thành công !", Toast.LENGTH_SHORT).show();
 }
 else
 Toast.makeText(MainActivity.this, "Xóa thất bại !", Toast.LENGTH_SHORT).show();
 }
 });
 bui.setNegativeButton("Cancel", new AlertDialog.OnClickListener() {

 @Override
 public void onClick(DialogInterface dialog, int which) {
 // TODO Auto-generated method stub
 dialog.cancel();
 }
 });

 bui.create().show();

 return false;
 }

 });
 }
 void createDatabase()
 {
 String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/smsgarbage.db";
 sqlite = openOrCreateDatabase(path, MODE_PRIVATE, null);

 try
 {
 String query = "Create table tblGarbage(id text primary key , prefixNum text)";
 sqlite.execSQL(query);
 } catch (Exception e) {
 // TODO: handle exception
 }
 }

 void insertData(String PrefixNum)
 {
 try {
 //sqlite = openOrCreateDatabase("qlsach.db", MODE_PRIVATE, null);
 ContentValues _values = new ContentValues();
 _values.put("id", PrefixNum);
 _values.put("prefixNum", PrefixNum);
 if(sqlite.insert("tblGarbage", null, _values) != -1)
 {
 Toast.makeText(MainActivity.this, "Thêm thành công !", Toast.LENGTH_SHORT).show();
 cleartext();
 }
 else
 Toast.makeText(MainActivity.this, "Thất bại !", Toast.LENGTH_SHORT).show();
 } catch (Exception e) {
 // TODO: handle exception
 Toast.makeText(MainActivity.this, "Thất bại hoàn toàn !", Toast.LENGTH_SHORT).show();
 }

 }

 void update(String idUpdate)
 {
 sqlite = openOrCreateDatabase("smsgarbage.db", MODE_PRIVATE, null);
 ContentValues values = new ContentValues();
 //values.put("id", idUpdate);
 values.put("prefixNum", editFrefixNum.getText().toString());
 if(sqlite.update("tblGarbage", values, "id=?", new String[]{idUpdate}) != -1)
 {
 loaddata();
 Toast.makeText(MainActivity.this, "Cập nhật thành công !", Toast.LENGTH_SHORT).show();
 }
 else
 Toast.makeText(MainActivity.this, "Cập nhật thất bại !", Toast.LENGTH_SHORT).show();
 }
 void deleteDatabase()
 {
 if(deleteDatabase("smsgarbage.db") == true)
 Toast.makeText(MainActivity.this, "Xóa database [smsgarbage] thành công !", Toast.LENGTH_LONG).show();
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
 // Inflate the menu; this adds items to the action bar if it is present.
 getMenuInflater().inflate(R.menu.main, menu);
 return true;
 }

/*************************************************************************************************************************/
 MediaRecorder audioRecorder = null;
 public void doStartRecord()
 {
 try
 {
 if(audioRecorder == null)
 audioRecorder = new MediaRecorder();//step1
 String saveto=Environment.getDataDirectory().getAbsolutePath()+"/myrecord.mp5";
 audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//step 2
 audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);//step3
 audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//step4
 audioRecorder.setOutputFile(saveto);
 audioRecorder.prepare();//step 6
 audioRecorder.start();//step 7
 } catch (Exception e)
 {
 // TODO: handle exception
 }
 }
 public void doStopRecording()
 {
 if(audioRecorder != null)
 {
 audioRecorder.stop();//step 8
 audioRecorder.release();
 audioRecorder = null;
 }
 }

 void doPlayMusic()
 {
 MediaPlayer player = new MediaPlayer();
 try
 {
 String saveto= Environment.getDataDirectory().getAbsolutePath()+"/myaudio.mp3";
 player.setDataSource(saveto);
 player.prepare();
 player.start();

 /*
 * player.stop();
 * player.release();
 * player = null;
 * */

 } catch (Exception e)
 {
 // TODO: handle exception
 }
 }

 /*************************************************************************************************************************/

}

Broadcast Receiver:


package vn.edu.it.nguyentannhan.id1200911;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.telephony.SmsMessage;
import android.widget.Toast;
import android.database.sqlite.SQLiteDatabase;

&nbsp;

&nbsp;

public class MySmsReceive extends BroadcastReceiver {
 public static final String SMS_URI= "content://sms/inbox";
 public static final String BODY= "body";
 public static final String ADDRESS= "address";
 //BroadcastReceiver receive =null;
 void BroadCastReceive()
 {
 //IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
 /*receive = new BroadcastReceiver()
 {

@Override
 public void onReceive(Context context, Intent intent) {
 // TODO Auto-generated method stub

 }

 };*/
 //receive = new BroadcastReceiver();
 }
 @Override
 public void onReceive(Context context, Intent intent)
 {
 // TODO Auto-generated method stub
 processReceive(context, intent);

}
 void processReceive(Context context, Intent intent)
 {
 Bundle extras = intent.getExtras();
 String message ="";
 if(extras != null)
 {
 Object []smsExtra = (Object[])extras.get("pdus");
 for (int i = 0; i < smsExtra.length; i++)
 {
 SmsMessage sms = SmsMessage.createFromPdu((byte[])smsExtra[i]);
 String body = sms.getMessageBody();
 String address = sms.getOriginatingAddress();
 message +="SMS From: "+ address +" :\n"+body+"\n";
 XoaToanBoSms(context, address);
 }
 Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
 }
 }

public boolean checkDumpNumber(String f)
 {
 SQLiteDatabase sqlite;
 String path= Environment.getExternalStorageDirectory().getAbsolutePath()+"/smsgarbage.db";
 sqlite= SQLiteDatabase.openOrCreateDatabase(path, null);
 Cursor c = sqlite.query("tblGarbage", null, "prefixNum=?", new String[]{f}, null, null, null, null);
 c.moveToFirst();
 return c.isAfterLast();
 }
 void XoaToanBoSms(Context con, String phoneNumber)
 {
 try {
 /*for (int i = 0; i < msgs.length; i++)
 {
 if(msgs.getOriginatingAddress().equals(phoneNumber)==false)
 {
 continue;
 }*/
 if(checkDumpNumber(phoneNumber))
 {
 con.getContentResolver().delete(Uri.parse("content://sms"), "address=?", new String[]{phoneNumber});
 Toast.makeText(con, "Xóa rồi đó " + phoneNumber, Toast.LENGTH_SHORT).show();
 }
 else
 {
 Toast.makeText(con, "Khong tìm thấy !" + phoneNumber, Toast.LENGTH_SHORT).show();
 }
 //}
 } catch (Exception e) {
 // TODO: handle exception
 Toast.makeText(con, "Xóa rồi đó " + e, Toast.LENGTH_SHORT).show();
 }
 }

 void XoaSmsMoiNhat(Context con, SmsMessage[]msgs, String phoneNumber)
 {
 try {
 for (int i = 0; i < msgs.length; i++) {
 if(msgs[i].getOriginatingAddress().equals(phoneNumber)==false)
 {
 continue;
 }
 con.getContentResolver().delete(Uri.parse("content://sms"), "address=? and date=?",
 new String []{phoneNumber,String.valueOf(msgs[i].getTimestampMillis())});
 Toast.makeText(con, "Xóa rồi đó "+msgs[i].getOriginatingAddress(), Toast.LENGTH_SHORT).show();
 }
 } catch (Exception e) {
 // TODO: handle exception
 Toast.makeText(con, "Xóa rồi đó "+e, Toast.LENGTH_SHORT).show();
 }
 }

}

Chương trình này sẽ chạy giống như Services nếu như nó bị tắt.

Khi lưu dữ liệu thì nó sẽ được lưu vào SDCARD, bất cứ khi nào có tin nhắn gửi tới thì Broadcast Receiver sẽ bắt lệnh và tiến hành xử lý.

Bạn có thể tải source code đầy đủ ở đây: https://www.mediafire.com/download/ulycc5263nvle1d/Broadcast_recieve_message_garbage.rar

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

Bài 40: Tìm hiểu Broadcast Receiver, ứng dụng viết phần mềm xử lý tin nhắn rác


Tui đã trình bày “Sương Sương” xong phần cơ bản loanh quanh của Android, từ bài tập 40 trở đi Tui muốn trình bày về các kiến thức chuyên sâu bên trong hệ điều hành Android. Bạn cần phải hiểu thật rõ những phần “Sương Sương” trước đó để áp dụng tốt cho những phần chuyên sâu về sau.

- BroadCast Receiver rất phức tạp và rất hữu dụng, thông qua nó mà ta có thể viết các Services cho điện thoại, trước khi tìm hiểu BroadCast Receiver thì bạn cần hiểu sơ qua về Intent – Filter, Uri parse và một số kiến thức khác.

broadcast1

- Intent‐filter giống như bộ lọc, giúp ta chọn đúng tác vụ để thực thi, chi tiết bạn xem tại http://developer.android.com/reference/android/content/IntentFilter.html

broadcast2

- Ta có 2 cách đăng ký Broadcast Receiver:

1) Đăng ký trong coding: Lắng nghe mọi thứ trong Intent- filter (nếu tắt ứng dụng sẽ không lắng nghe)

2) Đăng ký trong Manifest: Nó trở thành dịch vụ, tự động lắng nghe mọi thứ trong Intent – filter (kể cả khi đã đóng ứng dụng)

Tui sẽ làm ví dụ về BroadCast Receiver trong trường hợp số 1 trước, trường hợp số 2 Tui sẽ lấy 1 bài tập mà Tui yêu cầu sinh viên của tui thực hiện, sinh viên này rất khá, các bạn có thể trao đổi học tập với bạn này.

Ở ví dụ này đơn giản chỉ là yêu cầu ứng dụng lắng nghe tin nhắn gửi tới, nếu như có bất kỳ tin nhắn nào đó gửi tới thì hiển thị lên TextView của ứng dụng.

Bạn tạo Project như sau:

broadcast3giao diện vô cùng đơn giản tới mức tầm thường như sau:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:text="TextView" />

</LinearLayout>

Vì lắng nghe tin nhắn gửi tới nên bắt buộc trong Manifest ta phải cấp quyền cho ứng dụng như sau:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="tranduythanh.com"
 android:versionCode="1"
 android:versionName="1.0" >

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

<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" >
 <activity
 android:name="tranduythanh.com.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>

Bạn chú ý dòng lệnh 11, đó là cách đăng ký nhận tin nhắn. Chú ý là bạn có thể dùng giao diện để chọn cho tiện vì bạn không thể nhớ hết được (xem lại các bài trước Tui đã trình bày).

- Source code trong MainActivity để xử lý tin nhắn gửi tới:


package tranduythanh.com;

import tranduythanh.com.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.SmsMessage;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
 BroadcastReceiver receiver=null;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //tạo bộ lọc để lắng nghe tin nhắn gửi tới
 IntentFilter filter=new IntentFilter
 ("android.provider.Telephony.SMS_RECEIVED");
 //tạo bộ lắng nghe
 receiver=new BroadcastReceiver() {
 //hàm này sẽ tự động được kích hoạt khi có tin nhắn gửi tới
 public void onReceive(Context arg0, Intent arg1) {
 //Tui tách ra hàm riêng để xử lý
 //chú ý là dữ liệu trong tin nhắn được lưu trữ trong arg1
 processReceive(arg0, arg1);
 }
 };
 //đăng ký bộ lắng nghe vào hệ thống
 registerReceiver(receiver, filter);
 }
 protected void onDestroy() {
 super.onDestroy();
 //hủy bỏ đăng ký khi tắt ứng dụng
 unregisterReceiver(receiver);
 }
 public void processReceive(Context context, Intent intent)
 {
 Toast.makeText(context, "Hello .. có tin nhắn tới đó", Toast.LENGTH_LONG).show();
 TextView lbl=(TextView) findViewById(R.id.textView1);
 //pdus để lấy gói tin nhắn
 String sms_extra="pdus";
 Bundle bundle=intent.getExtras();
 //bundle trả về tập các tin nhắn gửi về cùng lúc
 Object []objArr= (Object[]) bundle.get(sms_extra);
 String sms="";
 //duyệt vòng lặp để đọc từng tin nhắn
 for(int i=0;i<objArr.length;i++)
 {
 //lệnh chuyển đổi về tin nhắn createFromPdu
 SmsMessage smsMsg=SmsMessage.
 createFromPdu((byte[]) objArr[i]);
 //lấy nội dung tin nhắn
 String body=smsMsg.getMessageBody();
 //lấy số điện thoại tin nhắn
 String address=smsMsg.getDisplayOriginatingAddress();
 sms+=address+":\n"+body+"\n";
 }
 //hiển thị lên giao diện
 lbl.setText(sms);
 }
}

broadcast4

- Bạn mở DDMS hoặc mở thêm 1 máy ảo nữa (xem bài tập số 2) để gửi tin nhắn vào đây. Bạn cũng có thể cài phần mềm vào Máy thật để Test, bạn sẽ có kể quả như trên.

- Bạn chú ý là thông số của Tin nhắn rất nhiều, bạn tìm hiểu thêm trên mạng, ở đây Tui chỉ lấy nội dung và số điện thoại ra mà thôi.

- Bạn có thể tải coding mẫu ở đây: http://www.mediafire.com/download/ri8kb7fec3my7x9/LearnBroadCastReceiver_sms_code.rar

- Tui tính viết phần mềm xử lý tin nhắn rác ở đây nhưng vì thấy dài quá nên Tui tách ra làm bài mới để các bạn tiện theo dõi.

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

Bài 39: Kết hợp AsyncTask và Handler class


Trong bài này Tui sẽ đưa ra 1 ví dụ cuối cùng về cách xử lý đa tiến trình, bài này tương đối phức tạp, bạn phải tập trung làm đi làm lại để hiểu thêm.

Giao diện chính của chương trình như sau:

async5- Mô tả sơ sơ: Khi nhấn nút Start, chương trình sẽ vẽ bên màn hình bên trái điện thoại là danh sách các số ngẫu nhiên, sau khi vẽ xong (hoặc là đồng thời) chương trình sẽ vẽ danh sách các số là số nguyên tố nằm bên màn hình trái vào màn hình bên phải.

- Bạn tạo project như hình dưới đây:

async6

- Giao diện hơi phức tạp 1 xíu, ở đây Tui chia màn hình ra làm hai, bạn xem XML Resource:


<LinearLayout xmlns:android="http://splashurl.com/ot4qqf8
 xmlns:tools="http://splashurl.com/qzxkn3a
 android:id="@+id/LinearLayout1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:context=".MainActivity" >

<LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content" >

<Button
 android:id="@+id/btnstart"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="Start:" />

<EditText
 android:id="@+id/editnumber"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:ems="10"
 android:hint="enter number of here"
 android:inputType="number" >

<requestFocus />
 </EditText>
 </LinearLayout>

<TableLayout
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" >

<TableRow
 android:id="@+id/tableRow1"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content" >

<TextView
 android:id="@+id/textView1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:background="#008000"
 android:gravity="center"
 android:text="Random Number:"
 android:textColor="#FFFFFF" />

<TextView
 android:id="@+id/textView2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_weight="1"
 android:background="#8000FF"
 android:gravity="center"
 android:text="List Prime:"
 android:textColor="#FFFFFF" />
 </TableRow>

<TableRow
 android:id="@+id/tableRow2"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content" >

<ScrollView
 android:id="@+id/scrollView1"
 android:layout_width="wrap_content"
 android:layout_weight="1"
 android:layout_height="wrap_content" >

<LinearLayout
 android:id="@+id/llrandomnumber"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 </LinearLayout>
 </ScrollView>

<ScrollView
 android:id="@+id/scrollView2"
 android:layout_width="wrap_content"
 android:layout_weight="1"
 android:layout_height="wrap_content" >

<LinearLayout
 android:id="@+id/llprimenumber"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >

</LinearLayout>
 </ScrollView>
 </TableRow>
 </TableLayout>

</LinearLayout>

- Xử lý coding, bạn xem MyAsyncTask: 

Class này Tui kế thừa từ: AsyncTask<Integer, Integer, ArrayList<Integer>>

Integer ở đối số 1: Được truyền vào khi ta thực thi tiến trình.

Integer ở đối số 2: Được truyền vào để tiến hành cập nhật giao diện trong hàm publishProgress

ArrayList<Integer>: Kết quả trả về sau khi thực hiện xong tiến trình.

Việc đưa control động cũng tương tự như các bài trước.


package tranduythanh.com;

import java.util.ArrayList;
import java.util.Random;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.SystemClock;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

public class MyAsyncTask extends
 AsyncTask<Integer, Integer, ArrayList<Integer>>
{
 private LinearLayout llrandom,llprime;
 private Random rd=new Random();
 private Activity context;
 public MyAsyncTask(Activity context)
 {
 //lấy các control trong MainThread
 this.llrandom=(LinearLayout)
 context.findViewById(R.id.llrandomnumber);
 this.llprime=(LinearLayout)
 context.findViewById(R.id.llprimenumber);;
 this.context=context;
 }
 //Begin - can use UI thread here
 protected void onPreExecute() {
 super.onPreExecute();
 Toast.makeText(context, "Start here",
 Toast.LENGTH_SHORT).show();
 //khi bắt đầu thực thi tiến trình thì tiến hành xóa toàn bộ control bên trong
 this.llrandom.removeAllViews();
 this.llprime.removeAllViews();
 }
 protected ArrayList<Integer> doInBackground(Integer... params) {
 int step=1;
 ArrayList<Integer>list=new ArrayList<Integer>();
 //vòng lặp chạy hết n số button truyền vào
 int n=params[0];
 while(isCancelled()==false && step<=n)
 {
 step++;
 SystemClock.sleep(100);
 //lấy số ngẫu nhiên
 int x=rd.nextInt(100)+1;
 //gọi cập nhật giao diện
 publishProgress(x);
 //nếu là số nguyên tố thì lưu vào danh sách
 if(isPrime(x))
 list.add(x);
 }
 //trả về danh sách số nguyên tố
 return list;
 }
 @Override
 protected void onProgressUpdate(Integer... values) {
 super.onProgressUpdate(values);
 //lấy giá trị truyền vào trong doinbackground
 Integer item=values[0];
 //tạo Button với Text có giá trị là số ngẫu nhiên
 Button btn=new Button(context);
 btn.setWidth(100);
 btn.setHeight(30);
 btn.setText(item+"");
 //đưa button lên view bên trái màn hình
 this.llrandom.addView(btn);
 }
 public void doRawPrime(int x)
 {
 //hàm vẽ các Button là chứac các số nguyên tố
 Button btn=new Button(context);
 btn.setWidth(100);
 btn.setHeight(30);
 btn.setText(x+"");
 //đưa Button vào view bên phải màn hình
 this.llprime.addView(btn);
 }
 //hàm kiểm tra số nguyên tố
 public boolean isPrime(int x)
 {
 if(x<2)return false;
 for(int i=2;i<=Math.sqrt(x);i++){
 if(x%i==0)return false;}
 return true;
 }
 @Override
 protected void onPostExecute(ArrayList<Integer> result) {
 super.onPostExecute(result);
 //sau khi tiến trình kết thúc thì hàm này sẽ được thực thi
 //lấy về danh sách các số nguyên tố
 final ArrayList<Integer>list=result;
 //tiến hành dùng Handler class để thực hiện
 final Handler handler=new Handler();
 Thread th=new Thread(new Runnable() {
 public void run() {
 //lặp để vẽ các Button là số nguyên tố
 for(int i=0;i<list.size();i++){
 final int x=list.get(i);
 SystemClock.sleep(100);
 handler.post(new Runnable() {
 public void run() {
 doRawPrime(x);}
 });
 }
 handler.post(new Runnable() {
 public void run() {
 Toast.makeText(context, "Finish",
 Toast.LENGTH_SHORT).show();
 }
 });
 }
 });
 th.start();
 }}//end MyAsyncTask

Mục đích của bài này là Tui muốn nói rằng chúng ta có thể kết hợp các kỹ thuật xử lý đa tiến trình với nhau.

Ở đây Tui có 1 câu hỏi nhỏ là, nếu trong hàm onPostExecute Tui muốn sử dụng lại MyAsyncTask thì viết coding như thế nào là hớp lý (ý của tui là chỉ sử dụng 1 class MyAsyncTask, nhưng ta có thể thông qua nó để tạo nhiều tiến trình khác nhau với những chức năng khác nhau). Bạn hãy suy nghĩ và làm thử.

Tiếp tục xem MainActivity:


package tranduythanh.com;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity {
 Button btnstart;
 MyAsyncTask task;
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 btnstart=(Button) findViewById(R.id.btnstart);

 btnstart.setOnClickListener(new
 View.OnClickListener() {
 public void onClick(View arg0) {
 doStart();
 }
 });
 }
 public void doStart()
 {
 String s=((EditText)
 this.findViewById(R.id.editnumber))
 .getText().toString();
 //lấy số lượng từ EditText
 int n=Integer.parseInt(s);
 task=new MyAsyncTask(this);
 task.execute(n);
 }
}

- Bài này có 1 chút phức tạp, bạn cố gắng đọc hiểu.

- Bạn có thể tải coding mẫu ở đây: http://www.mediafire.com/download/1m270fb1zpdw628/LearnMultiThreading_AsyncTask_Handler.rar

- Bài kết tiếp Tui sẽ trình bày về BroadCastReceiver và cách xử lý khi có tin nhắn gửi tới, bạn có thể ứng dụng nó để viết phần mềm Xử Lý Tin Nhắn Rác. Bạn chú ý theo dõi.

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

Follow

Get every new post delivered to your Inbox.

Join 404 other followers

%d bloggers like this: