干货:android实现hessian通信

转载请注明出处:http://blog.csdn.net/SCTU_vroy/article/details/49366853

本文将详述如何在android(客户端)上与服务端通过Hessian实现网络通信、数据传输。
网上关于这方面的资料并不少,但是良莠不齐,让笔者走了不少弯路。本文将先解析android端源代码(ps:web端代码各位度娘or谷歌),而后分享在android上实现hessian常见的错误和解决方法。请各位大神多多提意见,谢谢~
Step 1:新建android工程,添加权限,导入源码工程中android_hessian的jar包

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

注意:
1)hessian官网提供的jar包适用于web端开发,不适用于android端;
2)code.google提供的hessdroid包亲测是有问题的,大概是因为里面包含一些android不支持的类,
具体可见:http://hsrong.iteye.com/blog/1719996

Step 2:创建接口IHessian,前端与后端必须一致

public interface IHessian {

    String sayHello();

    void sendModel(HessianModel model);

}

Step 3:创建数据类HessianModel,前端与后端字段名(属性)必须一致,而且包名(命名空间)也必须一致,并且需要实现序列化!(因为Hessian 是一个基于 binary-RPC 实现的远程通讯)

package com.example.androidhessian;

import java.io.Serializable;
/**
 * 统一的数据包model
 * 字段名必须统一
 * 且必须实现序列化
 * @author victor shi
 * 2015/10/20
 */
public class HessianModel implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private long id;
    private String name;
    private String date;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

}

Step 4:回到MainActivity,获取服务端ip,new一个子线程实现hessian请求。这里可能有人会问,为什么不直接在主线程进行网络通信?这个会在后面解答。
1)手机连接wifi热点后,获取服务端地址,记得在AndroidManifest.xml中添加网络权限:

    /*
     * 获取服务端地址
     */
    public static String getHostIP(Context context) {
        WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        DhcpInfo dhcpInfo = wifi.getDhcpInfo();
        StringBuilder sb = new StringBuilder();
//      sb.append("网络信息:" + "\n");
//      sb.append("本机ip:" + formatIP(dhcpInfo.ipAddress) + "\n");
//      sb.append("子网掩码:" + formatIP(dhcpInfo.netmask) + "\n");
//      sb.append("网关ip:" + formatIP(dhcpInfo.gateway) + "\n");
        sb.append(formatIP(dhcpInfo.serverAddress));
        return sb.toString();
    }

    /*
     * ip格式化
     */
    private static String formatIP(int ipAddress) {
        return (ipAddress & 0xff) + "." + ((ipAddress >> 8) & 0xff) + "."
                + ((ipAddress >> 16) & 0xff) + "." + ((ipAddress >> 24) & 0xff);
    }

2)直接po出Activity的代码:

public class MainActivity extends Activity {

    private static final String TAG = "Android Hessian Test";
    private static final String PORT = "8081"; //端口号
    private static final long TIMEOUT = 5000L; //网络请求时长

    private Button button;
    private TextView tv;

    private HessianModel model = null;
    private String url = "";

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

        initView();
        initData();
        initEvent();
    }

    private void initView() {
        button = (Button) findViewById(R.id.btnHessian);
        tv = (TextView) findViewById(R.id.tvMsg);
    }

    private void initData() {
        model = new HessianModel();
        model.setDate("2015.10.20");
        model.setId(1L);
        model.setName("victor");
        /*
         * 获取服务端ip地址
         */
        url = "http://" + NetTools.getHostIP(getApplicationContext()) + ":" + PORT + "/test.hessian";
    }

    private void initEvent() {
        button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // Hessian 请求
                new Thread(runnable).start();
            }
        });
    }

    /**
     * 处理队列信息
     * 操作UI
     */
    Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tv.setText(msg.obj.toString());
        }

    };

    /**
     * 开启子线程进行网络通信
     * 自Android4.0版本以后,不支持在UI主线程中网络通信,
     * 否则会报运行异常android.os.NetworkOnMainTreadException
     */
    Runnable runnable = new Runnable() {

        @Override
        public void run() {
            HessianProxyFactory factory = new HessianProxyFactory();
            Message msg = Message.obtain();
            factory.setDebug(true);
            factory.setReadTimeout(TIMEOUT);

            try {
                IHessian service = (IHessian) factory.create(IHessian.class, url, getClassLoader());

                msg.obj = service.sayHello();
                handler.sendMessage(msg);

//              service.sendModel(model);

            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
    };
}

代码解析:
1)url中端口号PORT后面的字符串“/test.hessian”取决于后台项目的路径;
2)为什么需要new一个子线程来实现hessian通信呢?原因在于自Android4.0版本后,如果直接在主线程进行网络通信,程序运行会抛出运行异常:android.os.NetworkOnMainThreadException。解决方法有几种,可自行搜索,此处采用多线程的方法,也可直接使用AsyncTask异步处理更方便。

到这里,源代码的解析部分就结束了,最后分享一下在android上实现hessian常见的问题和解决方法:
(ps:基本都是运行异常)

问题一:java.lang.NoClassDefFoundError: com/caucho/hessian/client/HessianConnectionException
解决方法:问题出在hessian包的版本,导入本文源码工程libs下的android_hessian.jar包即可解决。

问题二:android.os.NetworkOnMainThreadException
解决方法:如果是android4.0以下版本则不会报错,4.0以上则不允许在主线程中实现网络通信,只能new子线程,在子线程中实现hessian通信。

问题三:com.caucho.hessian.client.HessianConnectionException: 500: java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
解决方法:此异常是出在已经与服务端建立网络连接的基础上,问题还是出在hessian的jar包,即便jar包可以在web端使用,但是里面包含一些android不支持的类。所以还是需要导入正确的jar包,并add to build path,可从本文源码工程中获取,或者打开链接下载:http://hsrong.iteye.com/blog/1719996

还有需要注意的地方就是:
1)传递的对象model包名(or命名空间)需要一致
2)传递的对象model需要序列化
3)传递的对象model结构一致,字段名/属性名

源码下载:http://download.csdn.net/detail/sctu_vroy/9207769

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值