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

1,515 阅读5分钟

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

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

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

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

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

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

package com.test;
 
import java.io.Serializable;
 
public class Book implements Serializable {
 
	private String bookName;
 
	private String author;
 
	private double price;
 
	private int pages;
 
	public String getBookName() {
		return bookName;
	}
 
	public void setBookName(String bookName) {
		this.bookName = bookName;
	}
 
	public String getAuthor() {
		return author;
	}
 
	public void setAuthor(String author) {
		this.author = author;
	}
 
	public double getPrice() {
		return price;
	}
 
	public void setPrice(double price) {
		this.price = price;
	}
 
	public int getPages() {
		return pages;
	}
 
	public void setPages(int pages) {
		this.pages = pages;
	}
 
}

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

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

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000"
    tools:context=".MainActivity" >
 
   <Button 
     android:id="@+id/send"  
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:text="发送"
     />
 
</RelativeLayout>

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

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

public class MainActivity extends Activity implements OnClickListener {
 
	private Button send;
 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		send = (Button) findViewById(R.id.send);
		send.setOnClickListener(this);
	}
 
	@Override
	public void onClick(View v) {
		Book book = new Book();
		book.setBookName("Android高级编程");
		book.setAuthor("Reto Meier");
		book.setPages(398);
		book.setPrice(59.00);
		URL url = null;
		ObjectOutputStream oos = null;
		try {
			url = new URL("http://192.168.1.103:8080/ServerTest/servlet/TestServlet");
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setDoInput(true);
			connection.setDoOutput(true);
			connection.setConnectTimeout(10000);
			connection.setReadTimeout(10000);
			connection.setRequestMethod("POST");
			oos = new ObjectOutputStream(connection.getOutputStream());
			oos.writeObject(book);
			InputStreamReader read = new InputStreamReader(connection.getInputStream());
			BufferedReader br = new BufferedReader(read);
			String line = "";
			while ((line = br.readLine()) != null) {
				Log.d("TAG", "line is " + line);
			}
			br.close();
			connection.disconnect();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
 
		}
	}
 
}

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

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

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

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

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

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

public class TestServlet extends HttpServlet {
 
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(request.getInputStream());
			Book book = (Book) ois.readObject();
			System.out.println("书名是: " + book.getBookName());
			System.out.println("作者是: " + book.getAuthor());
			System.out.println("价格是: " + book.getPrice());
			System.out.println("页数是: " + book.getPages());
			PrintWriter out = response.getWriter();
			out.print("success");
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			ois.close();
		}
	}
	
}

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

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

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

而 Android 端打印结果如下:

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

好了,今天的讲解到此结束,有疑问的朋友请在下面留言。

源码下载,请点击这里

关注我的技术公众号“郭霖”,每天都有优质技术文章推送。