巧用Android网络通信技术,在网络上直接传输对象

要做一个优秀的Android应用,Android开发中就会经常使用到网络通信技术是必不可少的,很难想象一款没有网络交互的软件最终能发展得多成功。那么我们来看一下,一般Android应用程序里都是怎么实现网络交互的,这里拿一个Boook对象为例:

如上图所示,首先在手机端生成一个Book对象,里面包含书名、作者、价格等数据。为了要将这些数据发送到服务器端,我们要从Book对象中把数据取出,然后组装成XML格式的字符串。接着通过网络API,把组装好的XML字符串发送到服务器端。服务器端接到了客户端发来的XML字符串,就要对该XML进行解析。然后把解析出的数据重新组装成Book对象,之后服务器端就可以对该对象进行一系列其它的操作了。

当然XML格式的数据量比较大,现在很多Android应用为了节省流量,都改用JSON格式来传输数据了。不过不管是使用XML还是JSON,上图中描述的步骤总是少不了的。

感觉使用这种方式来传输数据,每次封装和解析XML的过程是最繁琐的,那么能不能把这最繁琐的过程绕过去呢?

如上图所示,如果可以调用网络API,直接把Book对象发送到服务器端,那么整个网络交互过程就会变得非常简单,下面我们就来看看如何实现。

新建一个Android工程,命名为ClientTest作为客户端工程。这里第一个要确定的就是待传输的对象,我们新建一个Book类,代码如下:

[java] 

  1. package com.test;
  2. import java.io.Serializable;
  3. public class Book implements Serializable {
  4.     private String bookName;
  5.     private String author;
  6.     private double price;
  7.     private int pages;
  8.     public String getBookName() {
  9.         return bookName;
  10.     }
  11.     public void setBookName(String bookName) {
  12.         this.bookName = bookName;
  13.     }
  14.     public String getAuthor() {
  15.         return author;
  16.     }
  17.     public void setAuthor(String author) {
  18.         this.author = author;
  19.     }
  20.     public double getPrice() {
  21.         return price;
  22.     }
  23.     public void setPrice(double price) {
  24.         this.price = price;
  25.     }
  26.     public int getPages() {
  27.         return pages;
  28.     }
  29.     public void setPages(int pages) {
  30.         this.pages = pages;
  31.     }
  32. }

这个类就是一个简单的POJO,但是要注意一点,它实现了Serializable接口,如果想在网络上传输对象,那么该对象就一定要实现Serializable接口。

 

接下来打开或新建activity_main.xml作为程序的主布局文件,加入如下代码:

[html] 

  1. <RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
  2.     xmlns:tools=”http://schemas.android.com/tools”
  3.     android:layout_width=”match_parent”
  4.     android:layout_height=”match_parent”
  5.     android:background=”#000″
  6.     tools:context=”.MainActivity” >
  7.    <Button
  8.      android:id=”@+id/send”
  9.      android:layout_width=”fill_parent”
  10.      android:layout_height=”wrap_content”
  11.      android:text=”发送”
  12.      />
  13. </RelativeLayout>

这个布局里面就是包含了一个按钮,点击这个按钮就去发出网络请求。

 

接下来打开或新建MainActivity作为程序的主Activity,其中加入如下代码:

[java] 

  1. public class MainActivity extends Activity implements OnClickListener {
  2.     private Button send;
  3.     @Override
  4.     protected void onCreate(Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         setContentView(R.layout.activity_main);
  7.         send = (Button) findViewById(R.id.send);
  8.         send.setOnClickListener(this);
  9.     }
  10.     @Override
  11.     public void onClick(View v) {
  12.         Book book = new Book();
  13.         book.setBookName(“Android高级编程”);
  14.         book.setAuthor(“Reto Meier”);
  15.         book.setPages(398);
  16.         book.setPrice(59.00);
  17.         URL url = null;
  18.         ObjectOutputStream oos = null;
  19.         try {
  20.             url = new URL(“http://192.168.1.103:8080/ServerTest/servlet/TestServlet”);
  21.             HttpURLConnection connection = (HttpURLConnection) url.openConnection();
  22.             connection.setDoInput(true);
  23.             connection.setDoOutput(true);
  24.             connection.setConnectTimeout(10000);
  25.             connection.setReadTimeout(10000);
  26.             connection.setRequestMethod(“POST”);
  27.             oos = new ObjectOutputStream(connection.getOutputStream());
  28.             oos.writeObject(book);
  29.             InputStreamReader read = new InputStreamReader(connection.getInputStream());
  30.             BufferedReader br = new BufferedReader(read);
  31.             String line = “”;
  32.             while ((line = br.readLine()) != null) {
  33.                 Log.d(“TAG”, “line is ” + line);
  34.             }
  35.             br.close();
  36.             connection.disconnect();
  37.         } catch (Exception e) {
  38.             e.printStackTrace();
  39.         } finally {
  40.         }
  41.     }
  42. }

我们可以看到,在onClick方法中处理了按扭的点击事件。这里首先new出了一个Book对象作为待传输数据,接着new出了一个URL对象,指明了服务器端的接口地址,然后对HttpURLConnection的一些可选参数进行配置。接着通过调用ObjectOutputStream的writeObject方法,将Book对象发送到服务器端,然后等服务器端返回数据,最后关闭流和连接。

 

注意由于我们使用了网络功能,因此需要在AndroidManifest.xml中加入如下权限:

[html] 

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

好了,目前Android端的代码已经开发完成,我们现在开始来编写服务器端代码。

 

新建一个名为ServerTest的Web Project,要做的第一件事就在Web Project下建立一个和Android端一样的Book类。这里有个非常重要的点大家一定要注意,服务器端的Book类和Android端的Book类,包名和类名都必须相同,否则会出现类型转换异常。这里由于两个Book类的内容是完全一样的,我就不再重复贴出。

然后新建一个Java Servlet作为网络访问接口,我们重写它的doPost方法,具体代码如下:

[java]

  1. public class TestServlet extends HttpServlet {
  2.     public void doPost(HttpServletRequest request, HttpServletResponse response)
  3.             throws ServletException, IOException {
  4.         ObjectInputStream ois = null;
  5.         try {
  6.             ois = new ObjectInputStream(request.getInputStream());
  7.             Book book = (Book) ois.readObject();
  8.             System.out.println(“书名是: ” + book.getBookName());
  9.             System.out.println(“作者是: ” + book.getAuthor());
  10.             System.out.println(“价格是: ” + book.getPrice());
  11.             System.out.println(“页数是: ” + book.getPages());
  12.             PrintWriter out = response.getWriter();
  13.             out.print(“success”);
  14.             out.flush();
  15.             out.close();
  16.         } catch (Exception e) {
  17.             e.printStackTrace();
  18.         } finally {
  19.             ois.close();
  20.         }
  21.     }
  22. }

可以看到,我们首先通过调用HttpServletRequest的getInputStream方法获取到输入流,然后将这个输入流组装成ObjectInputStream对象。接下来就很简单了,直接调用ObjectInputStream的readObject方法,将网络上传输过来的Book对象获取到,然后打印出Book中携带的数据,最后向客户端返回success。

 

现在我们来运行一下程序,首先将ServerTest这个项目布置到服务器上,并开启服务器待命。接着在手机上打开ClientTest这个应用程序,如下图所示:

点击发送发出网络请求,可以看到服务器端打印结果如下:

而Android端打印结果如下:

由此我们可以看出,网络上进行对象传输已经成功了!不需要通过繁琐的XML封装和解析,我们也成功将Book中的数据完整地从Android端发送到了服务器端。

标签