Category Archives: 8. .Net Web & KSOAP API

Bài 52: Tạo định dạng JSON trong C# asp.net service vs Android


Tiếp tục bài 51, Trong bài này Tui sẽ hướng dẫn cách tạo định dạng JSON trong C# asp.net service, sau đó dùng KSOAP API để kết nối để sử dụng trong Android.

– Cái hay của bài này là Tui viết code cho phép mọi đối tượng có thể tự parser ra định dạng JSON thông qua kỹ thuật viết Extendsion Method.

– Tui sẽ cấu hình IIS local để chạy, bạn có thể demo lên somee.com để test.

– Ở đây Tui giả lập dữ liệu để cho các bạn dễ tiếp cận, Tui có mô hình lớp như sau:

android_51_18Tui sẽ viết coding cho tất cả các đối tượng đều tự có khả năng tạo ra JSON để tăng tốc độ coding cũng như giảm thiểu code.

Bạn new 1 empty asp.net project tên WebApplication_JSON:

android_52_1Lớp Sanpham:


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

namespace WebApplication_JSON
{
public class SanPham
{
public string MaSP { get; set; }
public string TenSP { get; set; }
public int SoLuong { get; set; }
public double DonGia { get; set; }
public double ThanhTien { get; set; }
public string Hinh { get; set; }
}
}

Lớp DanhMuc:


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

namespace WebApplication_JSON
{
public class DanhMuc
{
public DanhMuc()
{
Sanphams = new List<SanPham>();
}
public List<SanPham> Sanphams { get; set; }
public string MaDM { get; set; }
public string TenDM { get; set; }

}
}

– Bạn cần tạo thêm 1 static class ExtensionMethod (chú ý là đặt tên gì cũng được), mục đích của lớp này là ta cung cấp các phương thức giúp các đối tượng có thể tự gán kết thêm các phương thức:

– Quy tắc như sau:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Serialization;

namespace WebApplication_JSON
{
public static class ExtensionMethod
{
public static string ParserJSon(this object data)
{
JavaScriptSerializer sc = new JavaScriptSerializer();
string strJson=sc.Serialize(data);
return strJson;
}
}
}

– lớp bắt buộc là static

– hàm bắt buộc là static

– đối số đầu tiên của hàm là this

==> những kiểu dữ liệu nào đằng sau từ khóa this sẽ tự động có hàm ParserJSon.

Hàm ParserJSon cho phép biến mọi đối tượng thành định dạng JSON, JavaScriptSerializer  có phương thức Serialize giúp ta làm được điều này.

– Tiếp tục tạo .net webservice, Tui giả lập dữ liệu để cho lẹ:


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

namespace WebApplication_JSON
{
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tranduythanh.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 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 WebService1 : System.Web.Services.WebService
{

[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod]
public string get1SanPhamMau()
{
SanPham sp = new SanPham();
sp.MaSP = "sp_1xxx";
sp.TenSP = "DELL Inspiron 14NR";
sp.SoLuong = 100;
sp.DonGia = 150000;
sp.Hinh = "https://duythanhcse.wordpress.com/h1.png";
return sp.ParserJSon();
}
[WebMethod]
public string get1DanhMuc()
{
DanhMuc dm = new DanhMuc();
dm.MaDM = "DM1";
dm.TenDM = "Hàng máy tính";
SanPham sp1 = new SanPham();
sp1.MaSP = "sp_1xxx";
sp1.TenSP = "DELL Inspiron 14NR";
sp1.SoLuong = 100;
sp1.DonGia = 150000;
sp1.Hinh = "https://duythanhcse.wordpress.com/h1.png";
dm.Sanphams.Add(sp1);

SanPham sp2 = new SanPham();
sp2.MaSP = "sp_2yyyy";
sp2.TenSP = "HP Inspiron 113";
sp2.SoLuong = 130;
sp2.DonGia = 140000;
sp2.Hinh = "https://duythanhcse.wordpress.com/h2.png";
dm.Sanphams.Add(sp2);

return dm.ParserJSon();
}
[WebMethod]
public string getListDanhMuc()
{
List<DanhMuc> dsDM = new List<DanhMuc>();
DanhMuc dm1 = new DanhMuc();
dm1.MaDM = "DM1";
dm1.TenDM = "Hàng máy tính";
SanPham sp1 = new SanPham();
sp1.MaSP = "sp_1xxx";
sp1.TenSP = "DELL Inspiron 14NR";
sp1.SoLuong = 100;
sp1.DonGia = 150000;
sp1.Hinh = "https://duythanhcse.wordpress.com/h1.png";
dm1.Sanphams.Add(sp1);

SanPham sp2 = new SanPham();
sp2.MaSP = "sp_2yyyy";
sp2.TenSP = "HP Inspiron 113";
sp2.SoLuong = 130;
sp2.DonGia = 140000;
sp2.Hinh = "https://duythanhcse.wordpress.com/h2.png";
dm1.Sanphams.Add(sp2);
dsDM.Add(dm1);

DanhMuc dm2 = new DanhMuc();
dm2.MaDM = "DM2";
dm2.TenDM = "Hàng Điện tử";
SanPham sp3 = new SanPham();
sp3.MaSP = "sp_3jjjj";
sp3.TenSP = "Bóng đèn Lượng Tử";
sp3.SoLuong = 95;
sp3.DonGia = 13000;
sp3.Hinh = "https://duythanhcse.wordpress.com/h3.png";
dm2.Sanphams.Add(sp3);

SanPham sp4 = new SanPham();
sp4.MaSP = "sp_4aaa";
sp4.TenSP = "HP Inspiron 113";
sp4.SoLuong = 120;
sp4.DonGia = 12000;
sp4.Hinh = "https://duythanhcse.wordpress.com/h4.png";
dm2.Sanphams.Add(sp4);
dsDM.Add(dm2);

return dsDM.ParserJSon();
}
}
}

– Tiến hành cấu hình IIS, chạy lên ta được (nếu không rõ các bạn cần xem lại các bài trước Tui trình bày rất kỹ về .net webservice):

android_52_2– Test thử get1SanPhamMau:

android_52_3– Test thử get1DanhMuc:

android_52_4– Test thử getListDanhMuc:

android_52_5

– Source code: Tải source code ở đây nầy

– Tiếp theo ta cần dùng KSOAP API kết nối tới asp.net webservice để đọc ra chuỗi JSON ở trên, sau đó parser ra JSONObject để sử dụng (hoặc bạn làm cách nào cũng được, miễn là Android thấy được chuỗi kết quả với định dạng JSon như trên):

– Tui sẽ trình bày cách đọc dữ liệu trong getListDanhMuc vì nó phức tạp nhất, các dịch vụ khác các bạn tự nghiên cứu.

Bạn quan sát dữ liệu trả về trong hàm getListDanhMuc được để trong cặp ngoặc vuông –> Đó chính là mảng đối tượng JSONArray, ứng với mỗi phần tử trong JSONArray là JSONObject (Là từng danh mục) bạn quan sát nó có Sanphams[…] nó lại chứa tập các phần tử là sản phẩm…

Bạn tạo Project như sau:

android_52_6Kết quả khi chạy ứng dụng:

android_52_7Màn hình chính là 1 ListView hiển thị theo dạng custom layout, mỗi dòng sẽ có Danh mục màu đỏ và Spinner chứa sản phẩm tương ứng với Danh mục đó.

Nhớ cấp quyền Internet.

– Giao diện chính (activity_main):


<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="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="tranduythanh.com.learnjsonnetservice.MainActivity" >

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

</LinearLayout>

– Customlayout  (custom_list_product.xml):


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/txtDanhMuc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Danh mục ở đây" />

<Spinner
android:id="@+id/spinner_sanpham"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

– Xử lý coding :


package tranduythanh.com.learnjsonnetservice;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class MyAdapter extends ArrayAdapter<JSONObject>
{
private Activity context;
private int resource;
private List<JSONObject>objects;
public MyAdapter(Activity context, int resource,
List<JSONObject> objects) {
super(context, resource, objects);
this.context=context;
this.resource=resource;
this.objects=objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater= this.context.getLayoutInflater();
View custom_row= inflater.inflate(this.resource, null);
TextView txtDM=(TextView) custom_row.findViewById(R.id.txtDanhMuc);
Spinner spinner_sp=(Spinner) custom_row.findViewById(R.id.spinner_sanpham);
//Đối tượng này là DanhMujc
JSONObject jsonObj=this.objects.get(position);
try {
//Lấy thuộc tính của Danh mục
String dm=jsonObj.getString("MaDM")+" - "+jsonObj.getString("TenDM");
txtDM.setText(dm);
txtDM.setTextColor(Color.RED);
//Lấy Danh sách sản phẩm:
JSONArray arrJson=jsonObj.getJSONArray("Sanphams");
ArrayList<String>arrSanpham=new ArrayList<>();
for(int i=0;i<arrJson.length();i++)
{
//lấy từng sản phẩm theo danh mục:
JSONObject jsonSanpham=arrJson.getJSONObject(i);
String sp=jsonSanpham.getString("TenSP");
arrSanpham.add(sp);
}
ArrayAdapter<String>adapter=new ArrayAdapter<>
(this.context, android.R.layout.simple_spinner_item,
arrSanpham);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_sp.setAdapter(adapter);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return custom_row;
}

}

– Coding MainActivity:


package tranduythanh.com.learnjsonnetservice;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
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.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity {
public final static String URL="http://192.168.0.147/testjson/WebService1.asmx?WSDL";
public final static String NAMESPACE="http://tranduythanh.com/";
ListView lvDanhMuc;
ArrayList<JSONObject>arrData;
MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addControlAndEvents();
}
private void addControlAndEvents() {
lvDanhMuc=(ListView) findViewById(R.id.lvDanhMuc);
arrData=new ArrayList<>();
adapter=new MyAdapter(this,
R.layout.custom_list_product, arrData);
lvDanhMuc.setAdapter(adapter);

JSonAsyncTask task=new JSonAsyncTask();
task.execute();
}

public class JSonAsyncTask extends AsyncTask<Void, Void, ArrayList<JSONObject> >
{
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected ArrayList<JSONObject> doInBackground(Void... params) {
ArrayList<JSONObject> listJSon=new ArrayList<>();
final String METHOD="getListDanhMuc";
final String SOAPACTION=NAMESPACE+METHOD;
SoapSerializationEnvelope envelope=new
SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
SoapObject request=new SoapObject(NAMESPACE, METHOD);
envelope.setOutputSoapObject(request);
HttpTransportSE transport=new HttpTransportSE(URL);
try {
transport.call(SOAPACTION, envelope);
SoapPrimitive data= (SoapPrimitive)
envelope.getResponse();
//Chuỗi định dạng ban đầu
String jsonText=data.toString();
//Chuỗi định dạng này có kiểu JSONArray:
//nó trả về tập Danh mục
JSONArray arr=new JSONArray(jsonText);
for(int i=0;i<arr.length();i++)
{
//Lấy 1 Đối tượng danh mục ra (JSONObject):
JSONObject jsonObj=arr.getJSONObject(i);
listJSon.add(jsonObj);
}

} catch(Exception e) {
Toast.makeText(getApplicationContext(), e.toString(),
Toast.LENGTH_LONG).show();
}
return listJSon;
}
@Override
protected void onPostExecute(ArrayList<JSONObject> result) {
super.onPostExecute(result);
arrData.clear();
arrData.addAll(result);
adapter.notifyDataSetChanged();
}
}
@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;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

– Các bạn có gắng đọc hiểu coding ở trên (thực ra nó tương tự như bài 50, không có gì khó).

– Bạn nghĩ cách để tương tác nhanh gọn hơn thay vì thông qua nhiều bước như vậy, nhưng chú ý luôn phải dùng đa tiến trình.

Các bạn có thể tải Source code mẫu ở đây

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

Bài 51: Xử lý JSON trong Android


Trong bài này Tui sẽ hướng dẫn các bạn cách tương tác JSON trong Android, ở đây Tui sẽ hướng dẫn 2 cách tiếp cận:

1) Sử dụng sẵn Web Service của ai đó được viết dưới định dạng JSON

2) Tự xây dựng JSON bằng .net web service (Các bạn cần biết cách tạo cũng như cách sử dụng), bạn có thể dùng bất kỳ cái gì đó để viết ra JSON cũng được, không nhất thiết phải dùng .net web service. Ở đây Tui muốn đứng trên vai người khổng lồ Microsoft để giúp các bạn tiếp cận một cách dễ dàng hơn.

Tui chụp một số hình liên quan tới định dạng JSON để các bạn dễ mường tượng, sau đó Tui sẽ giải thích kỹ về các đối tượng cũng như cách sử dụng chúng:

Đây là hình JSON facebook của Tui do Facebook Graph API tạo ra:

android_51_1Hay facebook định dạng JSON của ngài Tổng Thống Mỹ BaracObama:

android_51_2Hay định dạng JSON tỉ giá hối đoái của Ngân Hàng Đông Á:

android_51_4Hay định dạng JSON của Hoa Hậu Kỳ Duyên:

android_51_3Bạn quan sát nó có những định dạng rất giống nhau theo 1 chuẩn nào đó, có ngoặc nhọn, ngoặc vuông, dấu 2 chấm, dấu chấm phẩy …. đó chính những chuẩn viết cho dạng JSON, sau đây Tui đi vào chi tiết lý thuyết của chúng:

Khái niệm Định Dạng JSON:

JSON (JavaScript Object Notation) được định nghĩa dữ theo ngôn ngữ JavaScript, tiêu chuẩn ECMA-262 năm 1999, cấu trúc là  một định dạng  văn bản  đơn giản với các trường dữ liệu được lồng vào nhau. JSON được sử dụng để trao đổi dữ liệu giữa các thành phần của một hệ thống  tương thích với hầu hết các ngôn ngữ C, C++, C#, Java, JavaScript, Perl, Python…

JSON được xây dựng dựa trên hai cấu trúc chính:

  • Tập hợp cặp giá trị name/value, trong nhiều ngôn ngữ khác nhau cặp giá trị này có thể là object, record, struct, dictionary,  hash table, keyed list…
  • Tập hợp danh sách các giá trị, có thể là array, vector, list hay sequence.

Và tuỳ thuộc vào dữ liệu cần trao đổi, JSON có thể có nhiều dạng khác nhau, tuy nhiên có thể tống hợp ở những hai dạng chính sau:

  • Một đối tượng Object chứa  các cặp giá trị string/value không cần thứ tự, được bao trong cặp “{}”, các giá trị bên trong được định dạng “string:value” và chia cách nhau bởi dấu “,”.  Value ở đây có thể là chuỗi, số, true- false, null…Có thể xem mô tả cùng ví dụ sau:

android_51_5Ví dụ:

{
   "id": "100005823642721",
   "first_name": "Duy Thanh",
   "gender": "male",
   "last_name": "Trần",
   "link": "https://www.facebook.com/duythanhcse",
   "locale": "en_US",
   "birthday": "20/12/1961",
  "name": "Duy Thanh Trần", 
   "username": "duythanhcse" 
}
  • Một đối tượng mảng có bao gồm nhều phần tử con có thứ tự. Các phần từ con được bao trong cặp “[]” và chia cách nhau bởi dấu “,”. Mỗi phần tử con có thể là một giá trị đơn lẻ như: số, chuỗi, true-false, null hoặc một object khác, thậm chí có thể là một mảng.

android_51_6Ví dụ:

{
"Sanphams":
[
{"MaSP":"sp_1xxx","TenSP":"DELL Inspiron 14NR","SoLuong":100,
"DonGia":150000,"ThanhTien":0,
"Hinh":"https://duythanhcse.wordpress.com/h1.png"
},
{"MaSP":"sp_2yyyy","TenSP":"HP Inspiron 113","SoLuong":130,
"DonGia":140000,"ThanhTien":0,
"Hinh":"https://duythanhcse.wordpress.com/h2.png"
}
],
"MaDM":"DM1",
"TenDM":"Hàng máy tính"
}

Việc đọc và ghi định dạng JSON được tích hợp sẵn trong Android SDK (nó nằm trong thư viện org.json) hoặc bạn có thể sử dụng thư viện độc lập ở trên mạng Link đây nầy để viết cho java thuần túy cũng được (Tui đã test thử và chạy OK)

  • JSONObject: đối tượng quản lý JSON ở dạng một Object.
  • JSONArray: đối  tượng quản lý JSON ở dạng tập hợn các Object hoặc
    Array.
  • JSONStringer: đối tượng chuyển dữ liệu JSON thành dạng chuỗi.
  • JSONTokener: chuyển đổi đối tượng JSON (chuẩn RFC-4627) mã hoá chuỗi một thành đối tượng tương ứng.

Để cho dễ hiểu thì Tui sẽ hướng dẫn các bạn đọc thông tin từ service với định dạng JSON: http://graph.facebook.com/duythanhcse, Bạn quan sát trong JSON này thì chỉ có 1 đối tượng duy nhất (được đóng khung trong cặp ngoặc nhọn), với các thuộc tính : id, first_name, username…. bên trái dấu 2 chấm là thuộc tính và bên phải dấu 2 chấm là giá trị của thuộc tính. Bạn cần chú ý là phải dùng Đa Tiến Trình để tương tác dữ liệu trên Internet, dữ liệu được xử lý trong tiểu trình (lý do Tui đã giải thích ở các bài trước).

Giả sử Bạn cần phải đọc thông tin JSON và hiển thị lên giao diện như sau:

android_51_7Sau đó thử Facebook của Ngài Tổng Thống Barac Obama:

android_51_8Và cuối cùng là của Hoa Hậu Cao Kỳ Duyên:

android_51_9Bấm vào nút Xem hình để tự động đọc link hình của Hoa Hậu trong Facebook (mở 1 Activity mới và dùng 1 tiểu trình khác để đọc):

android_51_10– Để làm được như trên thì bạn tiến hành thực hiện theo các bước sau:

 Bước 1:

Tạo một Project tên là LearnJSON:

android_51_11Tiến hành cấp quyền sử dụng Internet cho ứng dụng trong AndroidManifest.xml:


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

Tiến hành thiết kế giao diện chính như sau (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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="tranduythanh.com.MainActivity" >

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

<TextView
android:id="@+id/txtId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Id ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="first_name:" />

<TextView
android:id="@+id/txtFirstName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="First Name ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="gender:" />

<TextView
android:id="@+id/txtGender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Gender ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="last_name:" />

<TextView
android:id="@+id/txtLastName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Last Name ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="link:" />

<TextView
android:id="@+id/txtLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="link ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView11"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="locale:" />

<TextView
android:id="@+id/txtLocale"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="locale ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="name:" />

<TextView
android:id="@+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="name ở đây"
android:textColor="#FF0000" />

<TextView
android:id="@+id/textView15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="username:" />

<TextView
android:id="@+id/txtUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="username ở đây"
android:textColor="#FF0000" />

<Button
android:id="@+id/btnShowImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Xem hình" />

</LinearLayout>

Giao diện của nó sẽ như sau:

android_51_13Bước 2 – Tạo lớp MyJsonReader để đọc định dạng JSON:


package tranduythanh.com;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;

import org.json.JSONException;
import org.json.JSONObject;

public class MyJsonReader {
public static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
/**
* Hàm trả về JSONObject
* @param url - Truyền link URL có định dạng JSON
* @return - Trả về JSONOBject
* @throws IOException
* @throws JSONException
*/
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
InputStream is = new URL(url).openStream();
try {
//đọc nội dung với Unicode:
BufferedReader rd = new BufferedReader
(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
}

Bước 3- Xử lý MainActivity:


package tranduythanh.com;

import java.io.IOException;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

TextView txtId;
TextView txtFirstName;
TextView txtLastName;
TextView txtGender;
TextView txtName;
TextView txtLocale;
TextView txtLink;
TextView txtUserName;

Button btnShowImage;
public TextView findTextView(int id)
{
return (TextView) findViewById(id);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

addControlAndEvents();
}
private void addControlAndEvents() {
txtId=findTextView(R.id.txtId);
txtFirstName=findTextView(R.id.txtFirstName);
txtLastName=findTextView(R.id.txtLastName);
txtName= findTextView(R.id.txtName);
txtLink= findTextView(R.id.txtLink);
txtGender =findTextView(R.id.txtGender);
txtLocale= findTextView(R.id.txtLocale);
txtUserName=findTextView(R.id.txtUserName);
btnShowImage=(Button) findTextView(R.id.btnShowImage);
btnShowImage.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
//Code xem hình ở đây
}
});
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
new MyJsonTask().execute("http://graph.facebook.com/duythanhcse");
//new MyJsonTask().execute("http://graph.facebook.com/barackobama");
//new MyJsonTask().execute("http://graph.facebook.com/kyduyenhoahau");
}
//Lớp xử lý đa tiến trình:
public class MyJsonTask extends AsyncTask<String, JSONObject, Void>
{
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected Void doInBackground(String... params) {
//Lấy URL truyền vào
String url=params[0];
JSONObject jsonObj;
try {
//đọc và chuyển về JSONObject
jsonObj = MyJsonReader.readJsonFromUrl(url);
publishProgress(jsonObj);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(JSONObject... values) {
super.onProgressUpdate(values);
//ta cập nhật giao diện ở đây:
JSONObject jsonObj=values[0];
try {
//kiểm tra xem có tồn tại thuộc tính id hay không
if(jsonObj.has("id"))
txtId.setText(jsonObj.getString("id"));
if(jsonObj.has("first_name"))
txtFirstName.setText(jsonObj.getString("first_name"));
if(jsonObj.has("gender"))
txtGender.setText(jsonObj.getString("gender"));
if(jsonObj.has("last_name"))
txtLastName.setText(jsonObj.getString("last_name"));
if(jsonObj.has("link"))
txtLink.setText(jsonObj.getString("link"));
if(jsonObj.has("locale"))
txtLocale.setText(jsonObj.getString("locale"));
if(jsonObj.has("name"))
txtName.setText(jsonObj.getString("name"));
if(jsonObj.has("username"))
txtUserName.setText(jsonObj.getString("username"));
} catch (JSONException e) {
Toast.makeText(MainActivity.this, e.toString(),
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
@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;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

Bạn quan sát:

if(jsonObj.has(“id”)) –> dùng để kiểm tra thuộc tính có tồn tại hay không
txtId.setText(jsonObj.getString(“id”));–> Nếu tồn tại thì lấy thông tin

jsonObj.getXXX(Thuộc_Tính) –> lấy giá trị của thuộc tính. với XXX là phương thức tương ứng với Kiểu dữ liệu được JSON trả về.

Như vậy bạn đã đọc được thông tin từ JSON lên giao diện.

Bạn cố gắng chạy thành công việc đọc dữ liệu đơn giản từ JSON, sau đó mới qua mục bên dưới:

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

– Bây giờ ta tiến hành đọc hình ảnh của Hoa Hậu Kỳ Duyên (http://graph.facebook.com/kyduyenhoahau), bạn nhớ đổi link đọc JSON qua Kỳ Duyên nhé:

android_51_14Bạn Thấy hình trên Tui chụp JSON của Kỳ Duyên, cover là thuộc tính và nó trả về 1 đối tượng JSONObject, trong đối tượng do cover trả về thì nó có thuộc tính source để lưu hình ảnh của Kỳ Duyên. Ta có thể đọc và xử lý hình ảnh như sau:

– Làm để đọc được source hình của Hoa Hậu từ JSon ở trên?

– Khi có source hình rồi thì làm sao để hiển thị lên giao diện của Android?

trước tiên ta cần bổ sung thêm lớp ImageLoadTask để tạo tiểu trình tải hình ảnh theo link bất kỳ và màn hình XemHinhActivity để hiển thị hình ảnh lên:

android_51_15Màn hình hiển thị hình ảnh đơn giản như sau (activity_xem_hinh.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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="tranduythanh.com.XemHinhActivity" >

<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />

</LinearLayout>

– Tiến hành xử lý tải hình ảnh từ URL (ImageLoadTask.java):


package tranduythanh.com;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {

//Link url hình ảnh bất kỳ
private String url;
//Control ImageView bất kỳ
private ImageView imageView;

public ImageLoadTask(String url, ImageView imageView) {
this.url = url;
this.imageView = imageView;
}

@Override
protected Bitmap doInBackground(Void... params) {
try {
//Tiến hành tạo đối tượng URL
URL urlConnection = new URL(url);
//Mở kết nối
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
//Đọc dữ liệu
InputStream input = connection.getInputStream();
//Tiến hành convert qua hình ảnh
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
//lấy kết quả hiển thị lên giao diện:
imageView.setImageBitmap(result);
}

}

– Tiếp theo tiến hành hiển thị hình ảnh lên giao diện (XemHinhActivity), lớp này sẽ sử dụng lại ImageLoadTask:


package tranduythanh.com;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ImageView;

public class XemHinhActivity extends Activity {

ImageView imgView;
String urlImage="";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xem_hinh);
imgView=(ImageView) findViewById(R.id.imageView1);
//Lấy Intent từ MainActivity
Intent in= getIntent();
//Lấy link hình ảnh ra được truyền từ MainActivity
urlImage=in.getStringExtra("URL_IMG");
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//Tiến hành tải hình theo urlImage và hiển thị lên giao diện:
new ImageLoadTask(urlImage, imgView).execute();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.xem_hinh, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

-Bạn để ý dòng 20 và dòng 22 ở trên, nó được lấy thông tin từ dòng 39 ở lớp dưới đây:

– Tiến hành sửa coding lại cho MainActivity, vì ở trên ta chưa xử lý đọc link hình ảnh truyền qua màn hình XemHinhActivity:


package tranduythanh.com;

import java.io.IOException;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

String urlImage;

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

addControlAndEvents();
}
private void addControlAndEvents() {
btnShowImage=(Button) findTextView(R.id.btnShowImage);
btnShowImage.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent in=new Intent
(MainActivity.this, XemHinhActivity.class);
in.putExtra("URL_IMG", urlImage);
startActivity(in);
}
});
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
new MyJsonTask().execute("http://graph.facebook.com/kyduyenhoahau");
}
//Lớp xử lý đa tiến trình:
public class MyJsonTask extends AsyncTask<String, JSONObject, Void>
{
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
@Override
protected Void doInBackground(String... params) {
//Lấy URL truyền vào
String url=params[0];
JSONObject jsonObj;
try {
//đọc và chuyển về JSONObject
jsonObj = MyJsonReader.readJsonFromUrl(url);
if(jsonObj.has("cover"))
{
JSONObject objCover= jsonObj.getJSONObject("cover");
if(objCover.has("source"))
{
urlImage=objCover.getString("source");
}
}
publishProgress(jsonObj);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(JSONObject... values) {
super.onProgressUpdate(values);

}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
}

– Tui xóa hết những code cũ, chỉ giữ lại code xử lý xem hình ảnh, quan quan sát Tui  bổ sung những lệnh sau:

+Biến urlImage để lưu được link hình ảnh của Hoa Hậu Kỳ Duyên

+ xử lý đọc hình (dòng 66 tới 72)

+ Xử lý gửi link hình qua màn hình xem hình ảnh (dòng 39)

Sau khi sửa xong và chạy phần mềm ta được kết quả như sau:

android_51_16Bạn có thể tải source code mẫu đầy đủ tại đây:

Tải Link ở đây nầy bạn!

Tương tự, nếu bạn đổi qua link của Ngài Tổng Thống Barac Obamá thì tự động bạn cũng có được hình ảnh như sau:

android_51_17Bài tiếp theo Tui sẽ hướng dẫn các bạn cách tạo JSON trong .net webservice và cách tương tác với chúng

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

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

Bài 50: Cách sử dụng Google Cloud Message trong Android


Bạn muốn xây dựng ứng dụng để gửi thông báo tới khoảng 1000 máy client có kết nối internet cùng một lúc mà không tốn phí thì có thể nghiên cứu cách sử dụng Google Cloud Message (GCM), trong bài tập này Tui sẽ hướng dẫn các bạn từng bước xây dựng ứng dụng sử dụng GCM. Trước tiên Tui vẽ lại quy trình sơ lược cách thức vận hành của GCM như  hình dưới đây:

android_50_1

– Bạn chú ý là số 1,2,3,4 Tui để cùng màu đỏ

– Số 5,6 Tui để cùng màu xanh.

– Trung tâm Tui để Google Developer vì nó là điều phối cho các bước.

Quy trình hoạt động như  sau (số thứ tự là bước):

Bước 0:

– Phải tạo một Project trên https://console.developers.google.com trước để có được Sender IdApplication Id

– Xây dựng Server và WebService của ta với CSDL phù hợp để lưu trữ Registration Id.

Bước 1:

– Các thiết bị  Mobile Android sẽ gửi Sender Id và Application Id lên GCM server để đăng ký (chú ý là Sender Id được cung cấp từ  Google Developers).

Bước 2:

– Nếu đăng ký thành công thì GCM Server sẽ tạo ra một mã đăng ký gọi là Registration Id và gửi ngược về cho thiết bị Android.

Bước 3:

– Sau khi nhận được Registration Id GCM Server gửi về, mỗi thiết bị Android này sẽ gửi Registration Id lên Server thông qua Web Service (chú ý là Server này do ta xây dựng, tức nó là độc lập với GCM Server của Google).

Bước 4:

– Sau khi Server của ta nhận được Registration Id (mỗi Android device sẽ được cung cấp Id riêng, theo từng session do GCM Server tạo ra) sẽ tiến hành lưu vào CSDL (do ta xây dựng) để sử dụng cho các lần sau này (gửi tin nhắn hàng loạt).

Bước 5:

– Xây dựng ứng dụng trên Server để cho phép gửi Tin nhắn hàng loạt (có thể gửi tới 1000  Android device mà không tốn phí), ở bước này cũng phải lấy Sender Id và Application Id do bước 0 tạo ra. Định dạng gửi tin sẽ theo JSON format, có thể gửi cả dấu Tiếng Việt.

– Tin nhắn ở bước này sẽ được gửi lên GCM Server.

Bước 6:

– Sau khi GCM Server nhận được tin nhắn theo định dạng JSON ở bước 5, nó sẽ tiến hành gửi tơi tất cả các máy trạm được đăng ký trong gói JSON này và gần như ngay lập tức các Client đều nhận được.

Bài này rất hay và có thể áp dụng được thực tế để giúp giảm thiểu chi phí nhắn tin SMS, vì về sau nhân viên sử dụng Smart Phone rất nhiều và dường như  WIFI có trong mọi ngóc nghách hẻm hóc….. nên có thể triển khai để nhắn tin cho nhân viên thông báo họp hay đi ăn nhậu…. Đối với Trường học cũng vậy có thể áp dụng để nhắn tin cho học sinh , sinh viên lên tới 1000 người mà không tốn phí (Vì theo Tui càng về sau giới trẻ sẽ ưa chuộng Smart Phone hơn là cục gạch Nồi Đồng Cối Đá được sản xuất từ kiếp trước).

Bước 0, 5, 6 là xây dựng cho Server Side (CSDL, Webserver, WebService, Webform…)

Bước 1,2,3,4 là xây dựng cho Client Side (Android Application).

Chi tiết từng bước Tui sẽ hướng dẫn cụ thể để bạn có thể triển khai thực tế:

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

Bây giờ bạn cần làm theo từng bước dưới đây nhé:

Bước 0, 5,6: – Xây dựng Server Side

– Phải tạo một Project trên https://console.developers.google.com trước để có được Sender IdApplication Id

– Xây dựng Server và WebService của ta với CSDL phù hợp để lưu trữ Registration Id.

Như  vậy ở  bước 0 bạn phải xử  lý 2 công việc chính đó là tạo project trên developer của google + xây dựng Server, bước này khá vất vả. Ngoài ra Tui sẽ dựng Webservice và CSDL ở trên Server miễn phí http://www.somee.com mà trong bài 44 Tui đã đề cấp tới, nếu bạn chưa rõ có thể vào bài này để xem lại (vì Tui sẽ không hướng dẫn lại nữa, chỉ hiển thị kết quả do đó bạn nào chưa học thì phải xem lại bài 44 thì mới hiểu được).

– Trước tiên cần phải tạo Project trên https://console.developers.google.com trước để có được Sender Id và Application Id. Sau khi bạn vào trang developer này và đăng nhập thì có giao diện như  sau(dĩ nhiên google sẽ thay đổi nếu như có version mới):

Ở đây Tui dùng email tdthanh@t3h.hcmus.edu.vn để hướng dẫn.

android_50_2Ở màn hình trên bạn nhấn vào nút “Create Project” để tạo google project, màn hình sau xuất hiện:

android_50_3Mục 1: Nhập vào tên Project, ở trên Tui đặt là drthanh

Mục 2: Nhập vào Project ID, nếu muốn nó tự tạo thì bạn nhấn mục số 3

Mục 3: Nhờ Google tạo ID

Mục 4: Bấm vào Create để chấp nhận tạo Project, chú ý bạn phải checked vào “I have read and agree to all”.

Sau khi bấm “Create“, bạn chờ giây lát google sẽ tạo project cho bạn như màn hình dưới đây:

android_50_4Ở màn hình trên bạn nhìn vào chỗ Tui khoanh vòng tròn màu đỏ:

Project Number: 1009585144224

Đây chính là Sender ID, bạn cần nhớ chỗ này để copy + paste vào Client side (android) và Server side của bạn.

Bạn nhớ đừng có dùng Sender ID này của Tui nhé, nếu có quá nhiều người sài, mỗi người gửi 1000 client…. Google nói Tui Spam họ…. họ ngắt tài khoản của Tui…. Tui sẽ buồn man  mác đó….Không hướng dẫn thêm được.

Nếu bạn bấm lung tung 1 hồi không tìm thấy Sender Id này thì nhớ bấm vào Overview để thấy lại nó nhé:

android_50_5Như vậy ta đã có Sender Id, giờ Tui hướng dẫn các bạn tìm Application ID:

Bạn vào APIs & auth/ chọn Credentials:

android_50_6Sau khi bạn nhấn vào “Credentials”, màn hình Credentials sẽ hiển thị ra như trên. Bạn nhấm vào mục số 2 “Create new Key” màn hình sau xuất hiện:

android_50_7Ở màn hình trên bạn chọn “Server Key” thì màn hình tạo Key sau xuất hiện:

android_50_8Tại màn hình này bạn để trống mặc định, chỉ việc bấm nút “Create“, ta có kết quả sau:

android_50_9Ta thấy API key: AIzaSyCjjq8EvQQdwmKb9rolWnun_hf8zq2nTa8

API key chính là Application ID.

Như vậy bạn đã có được Sender ID và Application ID. Bạn cũng chú ý đừng sử dụng của Tui nhé, cố gắng tự tạo theo các bước Tui hướng dẫn mà sử dụng.

– Tiếp theo của bước 0, Ta cần xây dựng Webservice, CSDL trên Server. Ở đây Tui dùng http://somee.com để tải dịch vụ lên sử dụng. Bước này Tui sẽ hướng dẫn bạn 2 cách tạo Server để truyền tin tới client: Dùng Webservice và dùng Desktop Application để bạn có nhiều lựa chọn cũng như tăng thêm vốn kiến thức về vận hành GCM.

– Mọi thứ bạn nên tạo tại máy của bạn trước, sau khi test OK mới đưa lên Server.

Bây giờ bạn tạo cơ sở dữ liệu trong SQL Server với tên “dbDrThanhGCM“, với 2 bảng:

android_50_10Bảng TinTuc:

Tên cột Kiểu loại Ghi chú
NewsID varchar(50) Mã tin tức, khóa chính
Title nvarchar(MAX) Tiêu đề tin tức
IsDeleted int 1 là xác nhận sọt rác, 0 là còn sử dụng

Bảng TinTuc mục đích để thêm danh sách tin tức tại máy Server, mỗi lần thêm Tin nó sẽ tự  động thông báo cho toàn bộ máy Client:

Bảng GCMRegistration:

Tên cột Kiểu loại Ghi chú
RegNo int No (tự động tăng), khóa chính
RegID nvarchar(MAX) Mã Registration ID của thiết bị do GCM server gửi về
DateCreate date Ngày tạo
IsDeleted int 1 là xác nhận sọt rác, 0 là còn sử dụng

Bảng GCMRegistration dùng để lưu trữ  các Registration Id của các Thiết bị đăng  ký thành công trên GCM Server. Ta cần tạo bảng này để lưu trữ lại toàn bộ Registration Id của các thiết bị để sử dụng cho việc thông báo hàng loạt ở các lần khác nhau. Thường các ID này mặc định được lưu trữ khoảng 4 tuần trên GCM Server.

Chú ý bảng GCMRegistration bạn có thể bỏ cột RegNo, dùng RegID làm khóa chính luôn. Nhưng tại vì Tui sợ Google thay đổi cơ chế làm tăng chiều dài của RegID sẽ vượt qua ràng buộc khóa chính nên Tui dùng RegNo tự  động tăng, và bạn cũng chỉ quan tâm tới RegID vì nó là duy nhất (không quan tâm RegNo).

– Bạn tiến hành Tạo WebService để tương tác với 2 bảng dữ liệu như  dưới đây (Tui tạo Solution để nó chứa luôn 2 Project: Webservice và Desktop Application): Tạo solution tên GCMSolution

android_50_11Bấm OK để tạo Solution:

android_50_14Tiến hành tạo ASP.NET project: Bấm chuột phải vào GCMSolution/chọn Add/New Project, màn hình sau xuất hiện:

android_50_12 Ta chọn cấu hình giống như mô tả ở trên, nhập tên “GCMWebService” rồi nhấn nút ok:

android_50_13Trong màn hình New ASP.NET Project/chọn Empty rồi nhấn nút OK như hình.

android_50_15– Bây giờ ta tiến hành tạo WebService tên drthanhgcmservice.asmx:

Bấm chuột phải vào GCMWebService/chọn Add/ Chọn Web Service (ASMX), xuất hiện màn hình sau cho phép nhập tên:

android_50_16Nhập tên rồi bấm OK ta có kết quả mặc định như  sau:

android_50_17Giờ ta tiến hành tương tác CSDL để viết các dịch vụ.

Ta dùng LINQ để tương tác CSDL, bấm chuột phải vào GCMWebService/chọn Add/ chọn LINQ to SQL classes: android_50_18Sau đó tiến hành kết nối tới CSDL tạo ở trên (bạn nào không rõ thì xem lại các bài trước (bài 43, 44, 45, 46), Tui không muốn nói lại vì mất thời gian), sau khi cấu hình và kéo thả xong ta được như sau:

android_50_19Bạn chú ý là chuỗi kết nối sẽ tự  động được tạo trong file “Web.config“, và khi đưa lên server Somee thì ta chỉ việc đổi chuỗi kết nối trong file này là xong (bạn cũng xem lại các bài trước tui đã đề cập).

Ta tiến hành viết lệnh cho lớp drthanhgcmservice:


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

namespace GCMWebService
{
/// <summary>
/// Summary description for drthanhgcmservice
/// </summary>
[WebService(Namespace = "http://tranduythanh.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 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 drthanhgcmservice : System.Web.Services.WebService
{

[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
/// <summary>
/// Hàm này dùng để lưu RegistrationId từ GCM gửi về cho mỗi thiết bị
/// </summary>
/// <param name="regId"></param>
/// <returns></returns>
[WebMethod]
public bool insertRegID(string regId)
{
try
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
GCMRegistration reg = db.GCMRegistrations.FirstOrDefault(c => c.RegID == regId);
if (reg == null)
{
reg = new GCMRegistration();
reg.RegID = regId;
reg.IsDeleted = 0;
db.GCMRegistrations.InsertOnSubmit(reg);
}
reg.DateCreate = DateTime.Now;
db.SubmitChanges();
return true;
}
catch (Exception ex)
{

}
return false;
}
/// <summary>
/// Hàm dùng để trả về danh sách Registration đã được lưu vào Server của ta
/// để cung cấp cho việc gửi tin nhắn hàng loạt, chú ý là danh sách không nằm trong sọt rác
/// </summary>
/// <param name="isDeleted">isDeleted=0 là sẵn sàng, isDeleted=1 là bị nằm trong sọt rác</param>
/// <returns></returns>
[WebMethod]
public GCMRegistration[] getListRegIDs(int isDeleted)
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
var  listc = db.GCMRegistrations.Where(x => x.IsDeleted == isDeleted);
return listc.ToArray();
}
/// <summary>
/// Hàm này dùng để lưu Registration vào sọt rác, thiết lập IsDeleted=1
/// </summary>
/// <param name="regId"></param>
/// <returns></returns>
[WebMethod]
public bool moveRegToRecycleBin(string regId)
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
GCMRegistration x = db.GCMRegistrations.FirstOrDefault(c => c.RegID == regId);
if (x != null)
{
x.IsDeleted = 1;
db.SubmitChanges();
return true;
}
return false;
}
/// <summary>
/// hàm dùng để xóa vĩnh viễn Registration ra khỏi CSDL
/// </summary>
/// <param name="regId"></param>
/// <returns></returns>
[WebMethod]
public bool permanentlyRemoveReg(string regId)
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
GCMRegistration x = db.GCMRegistrations.FirstOrDefault(c => c.RegID == regId);
if (x != null)
{
db.GCMRegistrations.DeleteOnSubmit(x);
db.SubmitChanges();
return true;
}
return false;
}
/// <summary>
/// Hàm trả về danh sách tin tức, mục đích là mỗi lần thêm 1 tin tức thì thông báo cho
/// máy client biết và cho phép mở xem danh sách tin mới.
/// </summary>
/// <param name="isDeleted"></param>
/// <returns></returns>
[WebMethod]
public TinTuc[] getListTinTuc(int isDeleted)
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
var ds=  db.TinTucs.Where(x =>  x.IsDeleted == 0);

return ds.ToArray() ;
}
/// <summary>
/// Hàm dùng để thêm mới 1 tin tức
/// </summary>
/// <param name="ma"></param>
/// <param name="title"></param>
/// <returns></returns>
[WebMethod]
public bool insertTinTuc(string ma,string title)
{
try
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
TinTuc t = db.TinTucs.FirstOrDefault(c => c.NewsID == ma);
if (t == null)
{
t = new TinTuc();
t.NewsID = ma;

t.IsDeleted = 0;
db.TinTucs.InsertOnSubmit(t);
}
t.Title = title;
db.SubmitChanges();
return true;
}
catch (Exception ex)
{

}
return false;
}
}
}

-Tiếp theo ta tạo 1 Webform để gửi thông báo tới các máy trạm bằng cách bấm chuột phải vào GCMWebService/chọn Add/ chọn Web Form: android_50_20Cửa sổ tạo Webform hiển thị lên, bạn tạo tên như  sau:

android_50_21Tui đặt là “DrThanhWebForm” rồi nhấn nút OK, bạn nhấn nút Cancel cũng được nhưng mà phải làm lại.

Bạn thiết kế giao diện cho DrThanhWebForm như hình dưới đây:

android_50_22txtThongBao: Nhập tin muốn thông báo xuống các máy trạm

btnGuiThongBao: Nút lệnh để bắt đầu thực hiện lệnh gửi tin

txtKetQua: Ô hiển thị kết quả sau khi gửi thông báo.

Tiến hành viết coding cho nút “Gửi Thông báo”, bạn double click vào nó để viết lệnh như  dưới đây:


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace GCMWebService
{
public partial class DrThanhWebForm : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

protected void btnGuiThongBao_Click(object sender, EventArgs e)
{
try
{
DrThanhGCMDataContext db = new DrThanhGCMDataContext();
//đây chính là API Key: (copy paste từ Google developer nhé)
string applicationID = "<Bạn copy API KEY vào đây nha>";
//lấy danh sách Registration Id
string[] arrRegid = db.GCMRegistrations.Where(c => c.IsDeleted == 0).Select(c => c.RegID).ToArray();

//đây chính là Sender ID: (copy paste từ Google developer nhé)
string SENDER_ID = "<Bạn copy Sender ID vào đây nha>";
//lấy nội dung thông báo
string value = txtThongBao.Text;
WebRequest tRequest;
//thiết lập GCM send
tRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
tRequest.Method = "POST";
tRequest.UseDefaultCredentials = true;

tRequest.PreAuthenticate = true;

tRequest.Credentials = CredentialCache.DefaultNetworkCredentials;

//định dạng JSON
tRequest.ContentType = "application/json";
//tRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8";
tRequest.Headers.Add(string.Format("Authorization: key={0}", applicationID));

tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));

string RegArr = string.Empty;

RegArr = string.Join("\",\"", arrRegid);
//Post Data có định dạng JSON như sau:
/*
*  { "collapse_key": "score_update",     "time_to_live": 108,       "delay_while_idle": true,
"data": {
"score": "223/3",
"time": "14:13.2252"
},
"registration_ids":["dh4dhdfh", "dfhjj8", "gjgj", "fdhfdjgfj", "đfjdfj25", "dhdfdj38"]
}
*/
string postData = "{ \"registration_ids\": [ \"" + RegArr + "\" ],\"data\": {\"message\": \"" + value + "\",\"collapse_key\":\"" + value + "\"}}";

Console.WriteLine(postData);
Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
tRequest.ContentLength = byteArray.Length;

Stream dataStream = tRequest.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

WebResponse tResponse = tRequest.GetResponse();

dataStream = tResponse.GetResponseStream();

StreamReader tReader = new StreamReader(dataStream);

String sResponseFromServer = tReader.ReadToEnd();

txtKetQua.Text = sResponseFromServer; //Lấy thông báo kết quả từ GCM server.
tReader.Close();
dataStream.Close();
tResponse.Close();

Response.Write(@"<script language='javascript'>alert('Tui đã nói bạn đừng test mà....\nduythanhcse@gmail.com')</script>");
}
catch(Exception ex)
{
//Response.Write(ex.ToString());
string msgError = ex.ToString();
Response.Write(@"<script language='javascript'>alert('" + msgError + "')</script>");
}
}
}
}

– Bây giờ ta cần đưa toàn bộ CSDL và Web application này lên server somee để sử dụng chung (khi ta cấu hình trên này thì bất kỳ nơi đâu ta cũng có thể tương tác miễn là có Internet, bạn chú ý là khi đưa lên server somee thì họ yêu cầu 1 tháng phải tối thiểu 5 lần tương tác nhé nếu không họ sẽ xóa tài khoản.

– Các bước đưa lên somee.com Tui đã trình bày rất kỹ lưỡng trong các bài tập trước đó (Tui có đề cập ở trên) bạn phải tự xem lại và cấu hình để biết cách đưa lên, Tui chỉ hiển thị kết quả sau khi cấu hình xong (Chú ý nếu bạn không tự xem lại các bài trước thì hãy ngừng luôn tại đây đừng có đọc tiếp nữa vì sẽ vô ích do không hiểu, bạn không thể lấy cái không biết này để thực hiện cái không biết khác). Bạn chú ý sau khi cấu hình để đưa CSDL lên somee bạn cần đổi lại chuỗi kết nối trong web.config để cho giống với somee cung cấp trước khi đưa lên máy chủ Somee (Nếu bạn có riêng HOsting thì tự  cấu hình, không cần dùng somee):

android_50_23

– Test Kết quả:

http://drthanhgcm.somee.com/DrThanhWebForm.aspx (link này để gửi thông báo đến hàng loạt client):

android_50_26Bạn thấy đó, ở trên Tui nhập vào cụm từ “DrThanh đẹp trai”, khi bạn thấy phần kết quả thông báo danh chuỗi như trên và có success:(n) tức là đã gửi tới client thành công, lúc Tui bấm nút Gửi thông báo thì điện thoại của Tui cũng nhận được tin này. Nếu bây giờ bạn gõ chuỗi bất kỳ và bấm gửi Thông báo thì điện thoại của Tui cũng nhận được (do đó bạn đừng có SPAM nhé.. Tội nghiệp Tui…).

http://drthanhgcm.somee.com/drthanhgcmservice.asmx (dùng để tương tác thông tin giữa Client và Server của ta: Lưu Registration ID từ  GCM server về, quản lý tin tức cũng như  Registration (thêm mới, hiển thị danh sách):

android_50_25Như  vậy ta đã tạo xong bước Server Side, bạn có thể tải source code mẫu Server side ở đây:

Cơ sở dữ liệu: http://download855.mediafire.com/cwhped1w6dhg/cjc26c2bmia2276/dbDrThanhGCM.sql

Source code : http://download1501.mediafire.com/5dm93jhg9h7g/56azkjufqybm6lz/GCMSolution.rar

Chú ý Source code bạn cần sửa 2 file:

– File DrThanhWebForm.aspx.cs: Copy + paste lại Application ID và Sender Id của bạn

– File Web.config: Copy + paste lại chuỗi kết nối.

Tui đã test chạy thành công hết rồi mới đưa lên đây nhé các bạn, chú ý sửa 2 file lại cho đúng.

Chú ý là ở bước số 0 Tui sẽ quay lại sau để hướng dẫn cách viết Desktop application để tương tác sử dụng GCM Server nhé, tạm thời dùng Webform (vì Tui sợ nhiều quá các bạn sẽ rối).

Bước 1, 2, 3, 4: – Xây dựng Client Side

Bước này chính là xây dựng Android Application để:

– Gửi thông tin đăng ký lên GCM Server để nhận Registration Id

– Lưu Registration Id vào CSDL trên server (của ta xây dựng)

– Nhận thông báo từ  Server (GCM Server)

Bạn tạo 1 Project mới với tên “DrThanhAndroidTestGCM“, Project này có 2 chức năng chính đó là:

– Tự động lắng nghe thông báo từ Server gửi về (Push Notification – GCM )

– Đọc danh sách Tin tức từ Server thông qua WebService.

Bạn chú ý là chương trình sẽ tự động nhận thông tin từ Server trong cả trường hợp Ứng dụng đã bị tắt.

Giao diện vô cùng tầm thường như sau:

android_50_27

XML layout 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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="tranduythanh.com.MainActivity" >

<Button
android:id="@+id/btnDangKyGCM"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đăng ký GCM Server" />

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

</LinearLayout>

Bạn cần tham chiếu tới thư viện KSOAP API   để tương tác tới .Net Webservice đã tạo ở trên.

Và tải thư viện GCM để tương tác GCM Server của Google rồi chép cả 2 thư viện KSOAP, GCM vào thư mục libs như hình Tui chụp dưới đây:

android_50_1– Sau đó tiến hành tạo và sửa các lớp như sau:

1) Tạo GCMIntentService – Lắng nghe Push Notification để thông báo cho Client

2) Sửa MainActivity – Màn hình chính để cho phép đăng ký Registration GCM Id cũng như hiển thị danh sách tin tức

3) Thêm ServerTask – Để lưu Registration GCM ID gửi về lên Server riêng để sử dụng cho lần khác

4) Thêm TinTucAsyncTask – Để đọc danh sách tin tức từ Server – dùng đa tiến trình

Bổ sung thêm ic_bell (ic_bell)vào thư mục drawable (bạn tự new 1 thư mục y xì tên này, khác là bị báo lỗi):

android_50_2Tiếp theo bổ sung danh sách các chuỗi sau vào strings.xml để sử dụng cho các thông báo:


<?xml version="1.0" encoding="utf-8"?>
<resources>

<string name="app_name">DrThanhAndroidTestGCM</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="server_register_error">Could not register device on Demo Server after %1$d attempts.</string>
<string name="server_registering">Đang thử (lần %1$d/%2$d) để đăng ký thiết bị trên GCM Server.</string>
<string name="server_registered">From Demo Server: successfully added device!</string>
<string name="gcm_registered">From GCM: device successfully registered!</string>
<string name="gcm_unregistered">From GCM: device successfully unregistered!</string>
<string name="gcm_message">From GCM: you got message!</string>
<string name="gcm_error">From GCM: error (%1$s).</string>
<string name="gcm_recoverable_error">From GCM: recoverable error (%1$s).</string>
<string name="gcm_deleted">From GCM: server deleted %1$d pending messages!</string>

</resources>

Cuối cùng cấu hình AndroidManifest 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="19" />

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

<permission
android:name="tranduythanh.com.permission.C2D_MESSAGE"
android:protectionLevel="signature" />

<uses-permission android:name="tranduythanh.com.permission.C2D_MESSAGE" />
<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />

<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="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />

<category android:name="tranduythanh.com" />
</intent-filter>
</receiver>

<service android:name="tranduythanh.com.GCMIntentService" />
</application>

</manifest>

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

Giờ ta tiến hành coding cho từng class:

Lớp  GCMIntentService:


package tranduythanh.com;

import tranduythanh.com.R;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.util.Log;
import com.google.android.gcm.GCMBaseIntentService;
import com.google.android.gcm.GCMRegistrar;

import static tranduythanh.com.ServerTask.*;

public class GCMIntentService extends GCMBaseIntentService{
private static final String TAG = "GCMIntentService";

public GCMIntentService() {
super(SENDER_ID);
}

@Override
protected void onRegistered(Context context, String registrationId) {
Log.i(TAG, "Device registered: regId = " + registrationId);
displayMessage(context, getString(R.string.gcm_registered));
ServerTask.register(context, registrationId);
}

@Override
protected void onUnregistered(Context context, String registrationId) {
Log.i(TAG, "hủy đăng ký unregistered");
displayMessage(context, getString(R.string.gcm_unregistered));
if (GCMRegistrar.isRegisteredOnServer(context)) {
//Call bỏ đăng ký ở đây
GCMRegistrar.setRegisteredOnServer(context, false);
//ServerTask.post_unregister(context, registrationId);
} else {
Log.i(TAG, "Ignoring unregister callback");
}
}

@Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
//String message = getString(R.string.gcm_message);
String message = intent.getStringExtra("message");
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}

@Override
protected void onDeletedMessages(Context context, int total) {
Log.i(TAG, "Received deleted messages notification");
String message = getString(R.string.gcm_deleted, total);
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}

@Override
public void onError(Context context, String errorId) {
Log.i(TAG, "Received error: " + errorId);
displayMessage(context, getString(R.string.gcm_error, errorId));
}

@Override
protected boolean onRecoverableError(Context context, String errorId) {
// log message
Log.i(TAG, "Received recoverable error: " + errorId);
displayMessage(context, getString(R.string.gcm_recoverable_error,
errorId));
return super.onRecoverableError(context, errorId);
}

/**
* Issues a notification to inform the user that server has sent a message.
*/
private static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_bell;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, MainActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notification.sound=alarmSound;
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}
}

Coding ServerTask:


package tranduythanh.com;
import java.util.Random;
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 tranduythanh.com.R;

import com.google.android.gcm.GCMRegistrar;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public final class ServerTask {
//Biến lưu namespace do bạn cấu hình trong Webservice
public static final String NAMESPACE="http://tranduythanh.com/";
//Biến lưu WSDL của server URL
public static final String SERVER_URL ="http://drthanhgcm.somee.com/drthanhgcmservice.asmx?WSDL";
//biến lưu Sender ID
public static final String SENDER_ID = "1050525163328";
//biến lưu log lại khi có sự kiện sảy ra
public static final String TAG = "DrthanhGCM_LOG";
/**
* Intent sử dụng để hiển thị lên màn hình
*/
public static final String DISPLAY_MESSAGE_ACTION = "tranduythanh.com.DISPLAY_MESSAGE";

/**
* Thông tin (message) để intent hiển thị
*/
public static final String EXTRA_MESSAGE = "message";
/**
* Hàm dùng để hiển thị Message lên màn hình (chú ý là nó chạy background)
*
* @param context
*            application's context.
* @param message
*            thông báo hiển thị ở màn hình.
*/
public static void displayMessage(Context context, String message) {
Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
intent.putExtra(EXTRA_MESSAGE, message);
context.sendBroadcast(intent);
}

public  static final int MAX_ATTEMPTS = 5;
public  static final int BACKOFF_MILLI_SECONDS = 2000;
public  static final Random random = new Random();

public static boolean post(final Context context, final String regId)
{
try{
final String METHOD_NAME="insertRegID";
final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);

request.addProperty("regId", regId);
SoapSerializationEnvelope envelope=
new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
MarshalFloat marshal=new MarshalFloat();
marshal.register(envelope);
HttpTransportSE androidHttpTransport=
new HttpTransportSE(SERVER_URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive response=(SoapPrimitive) envelope.getResponse();
String s=response.toString();
Toast.makeText(context, "kết quả ="+s, Toast.LENGTH_LONG).show();
Log.i(TAG, "Ghi Registration lên Server:\n"+s);
return true;
}
catch(Exception e)
{
Toast.makeText(context, "kết quả =\n"+e.toString(), Toast.LENGTH_LONG).show();
Log.i(TAG, "Lỗi post:\n"+e.toString());
}
return false;
}
public static boolean post_unregister(final Context context, final String regId)
{
try{
final String METHOD_NAME="deleteRegid";
final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
SoapObject request=new SoapObject(NAMESPACE, METHOD_NAME);

request.addProperty("regId", regId);
SoapSerializationEnvelope envelope=
new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
MarshalFloat marshal=new MarshalFloat();
marshal.register(envelope);
HttpTransportSE androidHttpTransport=
new HttpTransportSE(SERVER_URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive response=(SoapPrimitive) envelope.getResponse();
String s=response.toString();
//Toast.makeText(context, "kết quả ="+s, Toast.LENGTH_LONG).show();
Log.i(TAG, "Hủy Registration lên Server:\n"+s);
return true;
}
catch(Exception e)
{
//Toast.makeText(context, "kết quả =\n"+e.toString(), Toast.LENGTH_LONG).show();
Log.i(TAG, "Lỗi post2_unregister:\n"+e.toString());
}
return false;
}
public static boolean register(final Context context, final String regId) {
Log.i(TAG, "registering device (regId = " + regId + ")");

long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
// Once GCM returns a registration id, we need to register it in the
// demo server. As the server might be down, we will retry it a couple
// times.
for (int i = 1; i <= MAX_ATTEMPTS; i++) {
Log.d(TAG, "Attempt #" + i + " to register");
try {
displayMessage(context, context.getString(
R.string.server_registering, i, MAX_ATTEMPTS));
boolean b=post(context,regId);

GCMRegistrar.setRegisteredOnServer(context, true);

String message = context.getString(R.string.server_registered);

displayMessage(context, message);
if(b)
return true;
} catch (Exception e) {
// Here we are simplifying and retrying on any error; in a real
// application, it should retry only on unrecoverable errors
// (like HTTP error code 503).
Log.e(TAG, "Failed to register on attempt " + i, e);
if (i == MAX_ATTEMPTS) {
break;
}
try {
Log.d(TAG, "Sleeping for " + backoff + " ms before retry");
Thread.sleep(backoff);
} catch (InterruptedException e1) {
// Activity finished before we complete - exit.
Log.d(TAG, "Thread interrupted: abort remaining retries!");
Thread.currentThread().interrupt();
return false;
}
// increase backoff exponentially
backoff *= 2;
}
}
String message = context.getString(R.string.server_register_error,
MAX_ATTEMPTS);
displayMessage(context, message);
return false;
}
}

Code lớp TinTucAsyncTask:


package tranduythanh.com;

import java.util.ArrayList;

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

import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import static tranduythanh.com.ServerTask.*;

public class TinTucAsyncTask extends AsyncTask<Void, Void, ArrayList<String>>{

MainActivity context=null;
public TinTucAsyncTask(MainActivity context)
{
this.context=context;
}
@Override
protected void onPostExecute(ArrayList<String> result) {
super.onPostExecute(result);
try
{
Toast.makeText(
this.context,
"onPostExecute "+result.size(),
Toast.LENGTH_LONG)
.show();
context.dsTin.clear();
context.dsTin.addAll(result);
context.adapter.notifyDataSetChanged();
}
catch(Exception ex)
{
Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
}
}

@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(
this.context,
"onPreExecute",
Toast.LENGTH_LONG)
.show();
}

@Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
//Toast.makeText(context, values[0].getId()+"-"+values[0].getTitle(), Toast.LENGTH_LONG).show();
}
@Override
protected ArrayList<String> doInBackground(Void... params) {
ArrayList<String>arr=new ArrayList<String>();
try{
//hàm cần truy suất
final String METHOD_NAME="getListTinTuc";
final String SOAP_ACTION=NAMESPACE+METHOD_NAME;
//service description
//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(SERVER_URL);
//tiến hành triệu gọi Service
androidHttpTransport.call(SOAP_ACTION, envelope);

SoapObject soapArray=(SoapObject) envelope.getResponse();
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 id=soapItem.getProperty("NewsID").toString();
String title=soapItem.getProperty("Title").toString();
String tin=id+" - "+title;
arr.add(tin);
}
}
catch(Exception e)    {
//Toast.makeText(context, e.toString(), Toast.LENGTH_LONG).show();
Log.i("LOI_DOC_TIN", e.toString());
}
return arr;
}

}

Coding lớp MainActivity:


package tranduythanh.com;

import java.util.ArrayList;

import tranduythanh.com.R;

import com.google.android.gcm.GCMRegistrar;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;
import static tranduythanh.com.ServerTask.*;
public class MainActivity extends Activity {

Button btnDangKyGCM;

ListView lvTinTuc;
public ArrayList<String> dsTin;
public ArrayAdapter<String>adapter;

AsyncTask<Void, Void, Void> gcmRegisterTask;

final BroadcastReceiver handleMessageReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
Toast.makeText(MainActivity. this, newMessage, Toast.LENGTH_LONG).show();
Log.i(TAG, newMessage);
}
};

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

addControlAndEvents();

try
{
xemTinTuc();
}
catch(Exception ex)
{

}
}
private void xemTinTuc() {
TinTucAsyncTask task=new TinTucAsyncTask(this);
task.execute();
}

private void addControlAndEvents() {
btnDangKyGCM=(Button) findViewById(R.id.btnDangKyGCM);
lvTinTuc=(ListView) findViewById(R.id.lvTinTuc);
dsTin=new ArrayList<String>();
adapter=new ArrayAdapter<String>
(this,
android.R.layout.simple_list_item_1,
dsTin);
lvTinTuc.setAdapter(adapter);

btnDangKyGCM.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View arg0) {
xuLyDangKyGCMServer();
}
});
}

//Chỉ cần đăng ký 1 lần, các lần khác không cần--> tự động nhận biết rồi
protected void xuLyDangKyGCMServer() {
// Make sure the device has the proper dependencies.
GCMRegistrar.checkDevice(this);
// Make sure the manifest was properly set - comment out this line
// while developing the app, then uncomment it when it's ready.
GCMRegistrar.checkManifest(this);

//msg = (TextView) findViewById(R.id.display);

registerReceiver(handleMessageReceiver,
new IntentFilter(DISPLAY_MESSAGE_ACTION));
final String regId = GCMRegistrar.getRegistrationId(this);
Toast.makeText(this, "REGID của bạn = \n"+regId, Toast.LENGTH_LONG).show();
if (regId.equals("")) {
// Automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM, check server.
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
//msg.append(getString(R.string.already_registered) + "\n");
Toast.makeText(this, "REGID của bạn đã được đăng ký", Toast.LENGTH_LONG).show();
Log.i(TAG, "đã đăng ký :\n"+regId+"\n Thành công");
final Context context = this;
gcmRegisterTask = new AsyncTask<Void, Void, Void>() {

@Override
protected Void doInBackground(Void... params) {
boolean registered =
ServerTask.register(context, regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}

@Override
protected void onPostExecute(Void result) {
gcmRegisterTask = null;
}

};
gcmRegisterTask.execute(null, null, null);
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
gcmRegisterTask = new AsyncTask<Void, Void, Void>() {

@Override
protected Void doInBackground(Void... params) {
boolean registered =
ServerTask.register(context, regId);
// At this point all attempts to register with the app
// server failed, so we need to unregister the device
// from GCM - the app will try to register again when
// it is restarted. Note that GCM will send an
// unregistered callback upon completion, but
// GCMIntentService.onUnregistered() will ignore it.
if (!registered) {
GCMRegistrar.unregister(context);
}
return null;
}

@Override
protected void onPostExecute(Void result) {
gcmRegisterTask = null;
}

};
gcmRegisterTask.execute(null, null, null);
}
}
}

@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;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

Bạn có thể tham khảo Source code đầy đủ ở đây: http://download1516.mediafire.com/38l17dust0og/b7u58q8rp5ukql9/DrThanhAndroidTestGCM.rar

Chú ý bạn phải cấu hình cho đúng CSDL cũng như Webservice, APPI Key, Sender ID thì mới có thể chạy ứng dụng

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_10h41_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: https://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_19– 0h41_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.