Skip to content

Commit aa8e8da

Browse files
committed
Use another thread for sending frames.
Fixes NetworkOnMainThreadException on Android 4.1 (Jelly Bean).
1 parent 5190a96 commit aa8e8da

File tree

2 files changed

+53
-30
lines changed

2 files changed

+53
-30
lines changed

src/com/codebutler/android_websockets/HybiParser.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public void start(HappyDataInputStream stream) throws IOException {
128128
break;
129129
}
130130
}
131-
mClient.getHandler().onDisconnect(0, "EOF");
131+
mClient.getListener().onDisconnect(0, "EOF");
132132
}
133133

134134
private void parseOpcode(byte data) throws ProtocolError {
@@ -262,25 +262,25 @@ private void emitFrame() throws IOException {
262262
if (mFinal) {
263263
byte[] message = mBuffer.toByteArray();
264264
if (mMode == MODE_TEXT) {
265-
mClient.getHandler().onMessage(encode(message));
265+
mClient.getListener().onMessage(encode(message));
266266
} else {
267-
mClient.getHandler().onMessage(message);
267+
mClient.getListener().onMessage(message);
268268
}
269269
reset();
270270
}
271271

272272
} else if (opcode == OP_TEXT) {
273273
if (mFinal) {
274274
String messageText = encode(payload);
275-
mClient.getHandler().onMessage(messageText);
275+
mClient.getListener().onMessage(messageText);
276276
} else {
277277
mMode = MODE_TEXT;
278278
mBuffer.write(payload);
279279
}
280280

281281
} else if (opcode == OP_BINARY) {
282282
if (mFinal) {
283-
mClient.getHandler().onMessage(payload);
283+
mClient.getListener().onMessage(payload);
284284
} else {
285285
mMode = MODE_BINARY;
286286
mBuffer.write(payload);
@@ -290,7 +290,7 @@ private void emitFrame() throws IOException {
290290
int code = (payload.length >= 2) ? 256 * payload[0] + payload[1] : 0;
291291
String reason = (payload.length > 2) ? encode(slice(payload, 2)) : null;
292292
Log.d(TAG, "Got close op! " + code + " " + reason);
293-
mClient.getHandler().onDisconnect(code, reason);
293+
mClient.getListener().onDisconnect(code, reason);
294294

295295
} else if (opcode == OP_PING) {
296296
if (payload.length > 125) { throw new ProtocolError("Ping payload too large"); }

src/com/codebutler/android_websockets/WebSocketClient.java

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.codebutler.android_websockets;
22

3+
import android.os.Handler;
4+
import android.os.HandlerThread;
35
import android.text.TextUtils;
46
import android.util.Base64;
57
import android.util.Log;
@@ -27,9 +29,11 @@ public class WebSocketClient {
2729
private static final String TAG = "WebSocketClient";
2830

2931
private URI mURI;
30-
private Handler mHandler;
32+
private Listener mListener;
3133
private Socket mSocket;
3234
private Thread mThread;
35+
private HandlerThread mHandlerThread;
36+
private Handler mHandler;
3337
private List<BasicNameValuePair> mExtraHeaders;
3438
private HybiParser mParser;
3539

@@ -41,15 +45,19 @@ public static void setTrustManagers(TrustManager[] tm) {
4145
sTrustManagers = tm;
4246
}
4347

44-
public WebSocketClient(URI uri, Handler handler, List<BasicNameValuePair> extraHeaders) {
48+
public WebSocketClient(URI uri, Listener listener, List<BasicNameValuePair> extraHeaders) {
4549
mURI = uri;
46-
mHandler = handler;
50+
mListener = listener;
4751
mExtraHeaders = extraHeaders;
4852
mParser = new HybiParser(this);
53+
54+
mHandlerThread = new HandlerThread("websocket-thread");
55+
mHandlerThread.start();
56+
mHandler = new Handler(mHandlerThread.getLooper());
4957
}
5058

51-
public Handler getHandler() {
52-
return mHandler;
59+
public Listener getListener() {
60+
return mListener;
5361
}
5462

5563
public void connect() {
@@ -69,7 +77,7 @@ public void run() {
6977
}
7078

7179
String originScheme = mURI.getScheme().equals("wss") ? "https" : "http";
72-
URI origin = new URI(originScheme, mURI.getSchemeSpecificPart(), null);
80+
URI origin = new URI(originScheme, "//" + mURI.getHost(), null);
7381

7482
SocketFactory factory = mURI.getScheme().equals("wss") ? getSSLSocketFactory() : SocketFactory.getDefault();
7583
mSocket = factory.createSocket(mURI.getHost(), port);
@@ -109,32 +117,42 @@ public void run() {
109117
}
110118
}
111119

112-
mHandler.onConnect();
120+
mListener.onConnect();
113121

114122
// Now decode websocket frames.
115123
mParser.start(stream);
116124

117125
} catch (EOFException ex) {
118126
Log.d(TAG, "WebSocket EOF!", ex);
119-
mHandler.onDisconnect(0, "EOF");
127+
mListener.onDisconnect(0, "EOF");
120128

121129
} catch (SSLException ex) {
122130
// Connection reset by peer
123131
Log.d(TAG, "Websocket SSL error!", ex);
124-
mHandler.onDisconnect(0, "SSL");
132+
mListener.onDisconnect(0, "SSL");
125133

126134
} catch (Exception ex) {
127-
mHandler.onError(ex);
135+
mListener.onError(ex);
128136
}
129137
}
130138
});
131139
mThread.start();
132140
}
133141

134-
public void disconnect() throws IOException {
142+
public void disconnect() {
135143
if (mSocket != null) {
136-
mSocket.close();
137-
mSocket = null;
144+
mHandler.post(new Runnable() {
145+
@Override
146+
public void run() {
147+
try {
148+
mSocket.close();
149+
mSocket = null;
150+
} catch (IOException ex) {
151+
Log.d(TAG, "Error while disconnecting", ex);
152+
mListener.onError(ex);
153+
}
154+
}
155+
});
138156
}
139157
}
140158

@@ -154,7 +172,7 @@ private StatusLine parseStatusLine(String line) {
154172
}
155173

156174
private Header parseHeader(String line) {
157-
return BasicLineParser.parseHeader(line, new BasicLineParser());
175+
return BasicLineParser.parseHeader(line, new BasicLineParser());
158176
}
159177

160178
// Can't use BufferedReader because it buffers past the HTTP data.
@@ -185,19 +203,24 @@ private String createSecret() {
185203
return Base64.encodeToString(nonce, Base64.DEFAULT).trim();
186204
}
187205

188-
void sendFrame(byte[] frame) {
189-
try {
190-
synchronized (mSendLock) {
191-
OutputStream outputStream = mSocket.getOutputStream();
192-
outputStream.write(frame);
193-
outputStream.flush();
206+
void sendFrame(final byte[] frame) {
207+
mHandler.post(new Runnable() {
208+
@Override
209+
public void run() {
210+
try {
211+
synchronized (mSendLock) {
212+
OutputStream outputStream = mSocket.getOutputStream();
213+
outputStream.write(frame);
214+
outputStream.flush();
215+
}
216+
} catch (IOException e) {
217+
mListener.onError(e);
218+
}
194219
}
195-
} catch (IOException e) {
196-
mHandler.onError(e);
197-
}
220+
});
198221
}
199222

200-
public interface Handler {
223+
public interface Listener {
201224
public void onConnect();
202225
public void onMessage(String message);
203226
public void onMessage(byte[] data);

0 commit comments

Comments
 (0)