WebSocket Android client implementation and code encapsulation

Source: Internet
Author: User
Tags getmessage eventbus
Websocketdemo

WebSocket How to implement the Android client. introduce

If you do not want to understand the principle can be directly pulled to the end of the use of the chapter, according to the tutorial can be used, or directly open the demo view Code, code address:.
Https://github.com/0xZhangKe/WebSocketDemo

This article uses a background service to establish a WebSocket connection, and the activity and the Fragment need to bind only the service when using the WebSocket interface.
After receiving the data, Websocketservice will notify each activity and Fragment that bind the Websocketservice service, and its own can also judge the returned data, and how to operate according to the business requirements.
The following figure is the Websocketservice workflow diagram

Websocketservice is responsible for establishing the WebSocket connection, receiving the returned data, sending the received data through Eventbus, and automatically reconnecting after the connection failure.
The following diagram is the work flow chart of the activity

Activity/fragment bind the WebSocket service, which can be directly invoked to send data to the Websocketservice object when the binding succeeds. Websocketservice Add the necessary dependencies

First add WebSocket framework dependencies:

Compile ' com.neovisionaries:nv-websocket-client:2.3 '

This is also the framework I found on the Github after a circle selected, the use of a lot of people, the document is complete, and continue to maintain.
Also add a Eventbus and Ali JSON framework:

Compile ' com.alibaba:fastjson:1.2.33 '
compile ' org.greenrobot:eventbus:3.0.0 '

All right, Bob, let's get started. defines the interfaces provided by WebSocket

First, you create a WebSocket interface that defines several public methods that WebSocket must provide:

Public interface Iwebsocket {

    /**
     * Send data
     *
     * @param text required to send the
     data
    /void SendText (String text);

    /**
     * 0-Not connected
     * 1-Connecting
     * 2-connected
    /int getconnectstatus ();

    /**
     * Reconnect
    /void Reconnect ();

    /**
     * Close connection
    /void Stop ();
}

Websocketservice needs to implement this interface, which can be created directly by Iwebsocket after binding Websocketservice. Abswebsocketservice

I am here to strip the code (interface address, data processing, distribution, etc.) associated with the business logic from the WebSocket connection, sending data, etc. to reduce the coupling of the codes, so the time created here is an abstract class Abswebsocketservice To implement code unrelated to the business logic.
You only need to create a websocketservice and inherit the Abswebsocketservice in actual use, and you don't have to change the code in it.
First look at the Abswebsocketservice code:

Public abstract class Absbasewebsocketservice extends Service implements Iwebsocket {private static final String TAG
    = "Absbasewebsocketservice";
    private static final int time_out = 15000;

    private static Websocketfactory factory = new Websocketfactory (). Setconnectiontimeout (Time_out);
    Private Absbasewebsocketservice.websocketthread Websocketthread;

    Private WebSocket WebSocket;

    Private Absbasewebsocketservice.servicebinder Servicebinder = new Absbasewebsocketservice.servicebinder (); public class Servicebinder extends Binder {public Absbasewebsocketservice GetService () {return ABSBA
        Sewebsocketservice.this;
    } private Boolean stop = false; /** * 0-Not Connected * 1-Connecting * 2-connected/private int connectstatus = 0;//is connected @Override public VO
        ID onCreate () {super.oncreate ();

        LOG.D (TAG, "onCreate ()");
        Proxysettings settings = Factory.getproxysettings (); Settings.aDdheader ("Content-type", "Text/json");
        Connectstatus = 0;
        Websocketthread = new Absbasewebsocketservice.websocketthread ();

        Websocketthread.start ();
    LOG.I (TAG, "oncreated");
            @Nullable @Override public IBinder onbind (Intent Intent) {if (Servicebinder = null) {
        Servicebinder = new Absbasewebsocketservice.servicebinder ();
        LOG.I (TAG, "Onbind");
    return servicebinder;
        @Override public void OnDestroy () {Super.ondestroy ();
        Stop = true;
        Websocket.disconnect ();
        Websocket.flush ();
        WebSocket = null;
        Connectstatus = 0;
    LOG.I (TAG, "OnDestroy");

    /** * Get server address/protected abstract String getconnecturl ();

    /** * Distribute Response data * * protected abstract void Dispatchresponse (String textresponse); /** * Connection successfully sent Websocketconnectedevent event, * Request successfully sent Commonresponse event, * request failed to send WebSocketsEnddataerrorevent event.  * * Private class Websocketthread extends Thread {@Override public void run () {log.i TAG,
            "Websocketthread->run ()");
        Setupwebsocket ();
        } private void Setupwebsocket () {if (connectstatus!= 0) return;
        Connectstatus = 1;
            try {webSocket = Factory.createsocket (Getconnecturl ()); Websocket.addlistener (New Websocketadapter () {@Override public void Ontextmessage (Websock
                    Et websocket, String text) throws Exception {super.ontextmessage (websocket, text);
                    if (debug ()) {log.i (TAG, String.Format ("ontextmessage->%s", text);
                } dispatchresponse (text);  @Override public void Ontextmessageerror (WebSocket WebSocket, websocketexception cause,
  Byte[] data) throws Exception {                  Super.ontextmessageerror (WebSocket, cause, data);
                    LOG.E (TAG, "Ontextmessageerror ()", cause);
                Eventbus.getdefault (). Post (New Websocketsenddataerrorevent ("", "", "Ontextmessageerror ():" + cause.tostring ())); @Override public void ondisconnected (WebSocket WebSocket, Websocketframe server Closeframe, Websocketframe clientcloseframe, Boolean closedbyserver) throws Exception {Super.ondiscon
                    Nected (WebSocket, Servercloseframe, Clientcloseframe, closedbyserver);
                    Eventbus.getdefault (). Post (New Disconnectedevent ());
                    LOG.E (TAG, "ondisconnected ()");
                    Connectstatus = 0;
                    if (!stop) {//disconnect automatically after Setupwebsocket (); @Override public void onconnected (WebSocket WebSocket, Map<striNg, list<string>> headers) throws Exception {super.onconnected (websocket, headers);
                    LOG.I (TAG, "onconnected ()");
                    Connectstatus = 2;
                Eventbus.getdefault (). Post (New Websocketconnectedevent ()); @Override public void OnError (WebSocket WebSocket, websocketexception cause) throws exc
                    eption {super.onerror (websocket, cause);
                    LOG.E (TAG, "OnError ()", cause);
                Eventbus.getdefault (). Post (new Websocketconnectionerrorevent ("OnError:" + cause.getmessage ()));
            }
            });
            try {websocket.connect ();
                catch (NullPointerException e) {connectstatus = 0;
                LOG.I (TAG, String.Format ("NullPointerException ()->%s", E.getmessage ());
                LOG.E (TAG, "NullPointerException ()", e); Eventbus.getdefAult (). Post (new Websocketconnectionerrorevent ("NullPointerException:" + e.getmessage ()));
                catch (Openinghandshakeexception e) {connectstatus = 0;
                LOG.I (TAG, String.Format ("Openinghandshakeexception ()->%s", E.getmessage ());
                LOG.E (TAG, "openinghandshakeexception ()", e);
                Statusline SL = E.getstatusline ();
                LOG.I (TAG, "= = = Status Line = = =");
                LOG.E (TAG, "= = = Status Line = = =");
                LOG.I (TAG, String.Format ("HTTP Version =%s\n", sl.gethttpversion ());
                LOG.E (TAG, String.Format ("HTTP Version =%s\n", sl.gethttpversion ());
                LOG.I (TAG, String.Format ("Status Code =%s\n", Sl.getstatuscode ());
                LOG.E (TAG, String.Format ("Status Code =%s\n", Sl.getstatuscode ());
                LOG.I (TAG, String.Format ("Reason Phrase =%s\n", sl.getreasonphrase ()); LOG.E (TAG, String.Format ("Reason Phrase =%s\n", Sl.getrEasonphrase ()));
                map<string, list<string>> headers = E.getheaders ();
                LOG.I (TAG, "= = = = HTTP Headers = =");
                LOG.E (TAG, "= = = = HTTP Headers = =");
                    For (map.entry<string, list<string>> entry:headers.entrySet ()) {//Header name.

                    String name = Entry.getkey ();
                    Values of the header.

                    list<string> values = Entry.getvalue ();
                        If values = NULL | | values.size () = = 0) {//Print the name only.
                        SYSTEM.OUT.PRINTLN (name);
                    Continue
                        } for (String value:values) {//Print the name and the value.
                        LOG.E (TAG, String.Format ("%s:%s\n", name, value));
                    LOG.I (TAG, String.Format ("%s:%s\n", name, value));
    }            Eventbus.getdefault (). Post (new Websocketconnectionerrorevent ("Openinghandshakeexception:" +
            E.getmessage ()));
                catch (Hostnameunverifiedexception e) {connectstatus = 0;
                The certificate of the peer does not match the expected hostname.
                LOG.I (TAG, String.Format ("Hostnameunverifiedexception ()->%s", E.getmessage ());
                LOG.E (TAG, "hostnameunverifiedexception ()", e);
            Eventbus.getdefault (). Post (new Websocketconnectionerrorevent ("hostnameunverifiedexception:" + e.getMessage ()));
                catch (Websocketexception e) {connectstatus = 0;
                Failed to establish a WebSocket connection.
                LOG.I (TAG, String.Format ("Websocketexception ()->%s", E.getmessage ());
                LOG.E (TAG, "websocketexception ()", e); Eventbus.getdefault (). Post (new Websocketconnectionerrorevent ("websocketexception:" + E.getmEssage ()));
            The catch (IOException e) {connectstatus = 0;
            LOG.I (TAG, String.Format ("IOException ()->%s", E.getmessage ());
            LOG.E (TAG, "IOException ()", e);
        Eventbus.getdefault (). Post (new Websocketconnectionerrorevent ("IOException:" + e.getmessage ()));
        @Override public void SendText (String text) {if (Textutils.isempty (text)) return;
        if (debug ()) {log.i (TAG, String.Format ("SendText ()->%s", text);
        } if (WebSocket!= null && connectstatus = 2) {websocket.sendtext (text);
    @Override public int Getconnectstatus () {return connectstatus;
        @Override public void Reconnect () {log.i (TAG, Reconnect ()); New Thread (New Runnable () {@Override public void run () {log.i (TAG, "Reconnect ()-
                >begin restart ... ");
   try {                 Thread.Sleep (200);
                }catch (Exception e) {log.e (TAG, "Reconnect ()->run:", e);  } if (Websocketthread!= null &&!websocketthread.isalive ()) {connectstatus =
                    0;
                    Websocketthread = new Websocketthread ();
                    Websocketthread.start ();
                LOG.I (TAG, "reconnect ()->start success"); else {log.i (TAG, "Reconnect ()->start Failed:websocketthread==null | |
                Websocketthread.isalive () ");
    }}). Start ();
        @Override public void Stop () {log.i (TAG, Stop ());
        Websocket.disconnect ();
        Stop = true;
    LOG.I (TAG, "Stop ()->success");
            public boolean debug () {try {applicationinfo info = getapplication (). Getapplicationinfo (); Return (Info.flags & Applicationinfo.flag_debuggabLE)!= 0;
        catch (Exception e) {return false; }
    }
}

There are two abstract methods:

String Getconnecturl ()//Get server connection address
void Dispatchresponse (String textresponse)/callback This method when data is received, distributing data in this method

Once you have created the Abswebsocketservice service above, you also need to create a websocketservice to implement the class based on your business requirements. Websocketservice Service

The code is simple, as follows:

public class Websocketservice extends Absbasewebsocketservice {@Override protected String Getconnecturl () {
    Return "server corresponding URL"; @Override protected void Dispatchresponse (String textresponse) {//Process data try {Commo nresponse<string> response = Json.parseobject (Textresponse, New typereference<commonresponse<string>
            > () {}); if (response = = null) {Eventbus.getdefault (). Post (New Websocketsenddataerrorevent ("", Textresponse, "response data
                is empty "));
            Return //Here can be adjusted according to the server interface document to determine whether the code value is legal, as follows://if (Response.getcode () >= 1000 && Response.get Code () < Watts) {//Eventbus.getdefault (). Post (response);//}else{//EVENTBU S.getdefault (). Post (New Websocketsenddataerrorevent (Response.getcommand (). GetPath (), Textresponse,
Response.getmsg ())); } Eventbus.getdefault(). Post (response); }catch (Exception e) {//generally due to JSON parsing an exception Eventbus.getdefault (). Post (New Websocketsenddataerroreven
        T ("", Textresponse, "Data anomaly:" + e.getmessage ())); }
    }
}

The Dispatchresponse (String) approach is to convert the data to the corresponding entity and then send it out using Eventbus, where you can do some of the data correctly, such as the notes above.
One of the commonresponse is a standard template for our backend interface, all the data returned by the grid interface should be in this format, this class is written according to their own interface, do not follow my. Take a look at the code:

public class Commonresponse<t> {

    private String msg;
    Private T data;
    private int code;
    private String path;

    Public String getmsg () {return
        msg;
    }

    public void Setmsg (String msg) {
        this.msg = msg;
    }

    Public T GetData () {return
        data;
    }

    public void SetData (T data) {
        this.data = data;
    }

    public int GetCode () {return
        code;
    }

    public void Setcode (int code) {
        this.code = code;
    }

    Public String GetPath () {return
        path;
    }

    public void SetPath (String path) {
        This.path = path;
    }
}

Where path represents the interface address, its essence is a string, and we use this string as an identifier to identify which interface the returned data belongs to, and then we can make the corresponding operation.
Generic T represents the entity of the data, generally we will write different entities according to different interfaces to facilitate the use of, of course, these are not important, but also my personal habits, here also does not involve the core code, so you can change according to personal preferences.
Don't forget to register the service in Androidmanifest and then start the service at the right time, and I started it in the OnCreate method in application:

public class Gateapplication extends application {

    @Override public
    void OnCreate () {
        super.oncreate ();
        Intent Intent = new Intent (this, websocketservice.class);
        StartService (intent);
    }

Here the WebSocket service has been introduced, but we must be very troublesome if we use it directly.
For example, when you call the Websocketservice.sendtext (String) method, you find that the WebSocket connection is broken, bind the WebSocket service, determine its connection state, and so on, there are still many things to do, you can't always activity/ Fragment have to write so many code to judge it.
For this I have written absbasewebsocketactivity and absbasewebsocketfragment two abstract classes, which block out most of the connection state judgments and so on.
For example, when we call the Absbasewebsocketfragment.sendtext (String) method, we can directly determine the current time is the connection state, if not connected to reconnect, the connection is completed before sending the data.
Let's take a look at Absbasewebsocketactivity code: absbasewebsocketactivity

These include binding services, judging connection status, sending data and other operations, and exposing several methods for use:

Public abstract class Absbasewebsocketactivity extends Baseappcompatactivity {/** * Service connection number, * This refers to the binding WEBSO

    The number of cket used when the service fails, and in general there will be no binding failure/private final int reconnect_time = 5;
    Private Iwebsocket Mwebsocketservice;

    protected String networkerrortips; /** * Connection Time:</br> * 0-when entering the interface, if WebSocket is not connected, will continue to connect, or for some reason WebSocket disconnect, will automatically reconnect, which will trigger connection success/failure events; &LT;/BR&G
     T * 1-onresume () method callback to determine whether WebSocket is connected, if not connected, connect, triggering connection success/failure Events;</br> * 2-sendtext () method determines whether WebSocket is connected If it is not connected, the connection is triggered to trigger a connection success/failure event, which should continue calling the SendText () method to send the data when the connection succeeds. </br> * <p> * In addition, when Connecttype!= 0 o'clock, it should be set to 0 after each use.
     Because the state of 0 is unpredictable, it can be invoked at any time.
    * Private int connecttype = 0;
     /** * need to send the data, when connecttype = = 2 o'clock will be used.

    * * Private String Needsendtext;
    Private Boolean isconnected = false;
    Private Boolean networkreceiverisregister = false;
    private int connecttime = 0; Protected Serviceconnection MWEBSOCKetserviceconnection = new Serviceconnection () {public void onserviceconnected (componentname name, IBinder Servic
            e) {log.i (TAG, "onserviceconnected ()");
            Mwebsocketservice = (iwebsocket) (absbasewebsocketservice.servicebinder) service). GetService (); This assumes that the connection is either not connected or disconnected, and the connection is waiting to receive a successful/failed broadcast if (mwebsocketservice.getconnectstatus () = 2) {Log . I (TAG, "onserviceconnected ()->mwebsocketservice.getconnectstatus () = = 2;
                Bindsuccess ");
            Onservicebindsuccess (); else {log.i (TAG, String.Format ("O
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.