让我们谈谈:PHP和Android的高效通信,第1部分

马特Turland
分享

移动领域在过去几年中出现了爆炸式增长,促使人们认识到面向服务的体系结构是实现web和移动应用程序消费业务逻辑的好方法。虽然移动设备已经发生了巨大的变化,但它们对消费者的可用性的增加给网络和服务提供商增加了压力,这些提供商仍在努力使容量满足需求。为了降低硬件成本,开发人员现在必须压缩带宽字节,就像他们在计算早期对内存所做的那样。

这篇由两部分组成的文章将指导您构建一个高效的基于php的REST web服务,以供基于android的应用程序使用。这里提出的一些概念也适用于其他移动平台,如iOS。我假设您已经了解PHP和Android开发的基础知识,并且已经为这两者设置了合适的开发环境。我将主要介绍如何在这两种环境中处理数据序列化和压缩。

一个常见的请求

下面是我们感兴趣的典型HTTP操作的特定部分:

  1. 客户端(例如Android应用程序)向REST服务(例如服务器)发送一个HTTP请求,并使用请求头来指示它支持哪种数据序列化和压缩格式。
  2. 根据请求标头,服务器确定哪些数据序列化和压缩格式与客户端相同,从中选择一种,应用于请求的数据,并向客户端发送一个包含标头的响应,其中指定其选择和数据。
  3. 基于响应头,客户端对数据应用相应的解压缩和反序列化例程,将其恢复到原始状态,然后可以将其用于预期目的。

让我们从头开始,详细介绍每一步。

请求数据

为了发出HTTP请求,你的Android应用程序需要许可访问互联网。你需要在你的项目中声明这个AndroidManifest.xml文件是这样的:

<?XML版本="1.0"编码="utf-8"?>    . net "

然后,需要一个实际处理发出HTTP请求和处理响应的类。为此,我将使用本机AndroidHttpClient类,它带有适合大多数目的的默认配置,包括使用线程安全的连接管理器。

AndroidHttpClient类仅在Android 2.2 (API级别8)及以上版本中可用。支持旧版本,看看DefaultHttpClient类的Apache Harmony库Android从第一个版本开始就包含了这些功能。

进口android.net.http.AndroidHttpClient;进口java.io.IOException;进口org.apache.http.HttpResponse;进口org.apache.http.client.methods.HttpGet;公共类DataModel {protected AndroidHttpClient httpClient;HttpGet httpRequest;public DataModel() {this。httpClient = AndroidHttpClient。newInstance("Android " + Android .os. build . version . release //你的应用名称在这里也是一个可接受的值);} public DataValueObject getData()抛出IOException {HttpGet httpRequest =新的HttpGet("http://10.0.2.2/php-android/"); httpRequest.addHeader("Accept", "application/json;q=1,application/x-msgpack;q=0.9"); httpRequest.addHeader("Accept-Encoding", "bzip2,gzip,deflate"); HttpResponse httpResponse = this.httpClient.execute(httpRequest); // ... } }

的实例化该类时,它在内部创建AndroidHttpClient.当getData ()方法来请求数据时,它将创建一个的实例HttpGet,用请求数据填充它,并使用AndroidHttpClient实例发送它。请求数据包括以下内容:

  1. 被请求资源的URL(即REST端点)。如果你在同一台机器上托管你的Android开发环境,你可以从模拟器中使用IP地址10.0.2.2访问它(如上例所示),从物理设备中通过USB插入IP地址10.0.1.2访问它。
  2. 在本例中,是客户机支持的数据序列化格式JSON而且MessagePack,以及它们各自的质量因子,0到1之间的浮点数,数字越大表示对特定格式的偏好越高。关于这些的更多信息可以在RFC 2616第12节。
  3. 在本例中是客户机支持的数据编码格式bzip2gzip,缩小.关于这些的更多信息可以在RFC 2616章节3.5
  4. 这是可能的AndroidHttpClient实例将遇到问题,例如服务器不可用。它的execute ()方法可以抛出IOException来表示这个,这是代码调用getData ()可以适当地捕捉和处理。

    我们会回到剩下的getData ()方法,但目前我们需要在类中实现该类的使用Android的活动

    执行后台任务

    在移动应用程序上下文中请求和处理数据是一种异步操作。也就是说,我们希望应用程序发送对数据的请求,然后在收到响应后采取一些操作,例如用数据填充用户界面。

    默认情况下,Android包含每个单独的应用程序在它自己过程而且线程后者通常被称为UI线程,因为用户界面操作运行在它上面。因此,像从web服务获取和处理数据这样的密集操作应该在单独的线程上运行,以免阻塞UI操作,这通常会导致用户恼火。的子类来实现这一点AsyncTask封装流程。

    进口java.io.IOException;进口android.app.Activity;进口android.app.AlertDialog;进口android.app.ProgressDialog;进口android.content.DialogInterface;进口android.os.AsyncTask;公共类GetDataTask extends AsyncTask {ProgressDialog ProgressDialog;活动活动;字符串错误;public GetDataTask(Activity Activity) {super(); this.activity = activity; } protected String getString(int id) { return this.activity.getResources().getString(id); } @Override protected void onPreExecute() { progressDialog = ProgressDialog.show( this.activity, "", getString(R.string.loading), true, false ); } @Override protected DataValueObject doInBackground(Void... params) { DataModel dataModel = new DataModel(); DataValueObject dvo = null; try { dvo = dataModel.getData(); } catch (IOException e) { this.error = getString(R.string.error); // or e.getMessage() when debugging } return dvo; } @Override protected void onPostExecute(DataValueObject dvo) { if (dvo != null) { // Do something useful with dvo here // Dismiss the progress dialog when done progressDialog.dismiss(); } else { // Dismiss the progress dialog progressDialog.dismiss(); // Display a simple error dialog to the user new AlertDialog.Builder(this.activity) .setMessage(this.error) .setNeutralButton( getString(R.string.ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } } ) .create() .show(); } } }

    作为扩展的一部分AsyncTask类的实例,此类指定操作的结果将是DataValueObject类。getData ()方法DataModel类的回报。类构造函数将调用它的活动实例作为唯一参数。稍后将用于访问本地化的字符串并在其他特定于上下文的任务中使用该活动。

    onPreExecute ()而且onPostExecute ()方法将根据您在后台操作开始之前和之后想要做的事情而有所不同。我上面的例子展示了一个简单的用例,在发生错误时显示一个进度对话框和潜在的警告对话框。

    doInBackground ()包含需要在后台线程中运行的逻辑,在本例中调用getData ().的实例DataValueObject如果发生错误,则为null。然后将该值传递给onPostExecute ()当它被调用时,您可以用它做一些有用的事情。

    执行后台任务

    现在我们已经正确地封装了希望运行以获取数据的后台任务,我们需要在活动中实际调用它。这需要检查网络连接是否可用,以便数据请求能够实际到达服务器。这样做需要向您的AndroidManifest.xml文件:

    <?XML版本="1.0"编码="utf-8"?>    . ACCESS_NETWORK_STATE" />  . ACCESS_NETWORK_STATE

    创建activity时启动后台任务的activity类可能是这样的:

    进口android.app.Activity;进口android.content.Context;进口android.net.ConnectivityManager;进口android.net.NetworkInfo;进口android.os.Bundle;公共类MyActivity扩展活动{@覆盖公共无效onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (networkIsAvailable()) {new GetDataTask(this).execute();} else{//向用户显示关于网络不可用的错误}}public boolean networkIsAvailable() {ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);NetworkInfo NetworkInfo = cm.getActiveNetworkInfo();返回networkInfo != null && networkInfo. isconnected (); } }

    networkIsAvailable ()方法只查询适当的服务,以确定网络连接是否可用。如果你的应用程序有一个基活动类,这可能是一个有用的方法,包括在其中。的onCreate ()活动钩子使用networkIsAvailable ()执行后台任务或向用户显示适当的错误消息。执行任务只是简单地用活动引用实例化它并调用它execute ()方法。

    下次

    本文的第1部分主要讨论了如何设置Android应用程序来发出请求。在本文的第2部分中,我们将讨论如何在这两种环境中处理数据序列化和压缩。请继续关注!

    图像通过Fotolia

Baidu