編輯:關於Android編程
Selector mSelector = null;
ByteBuffer sendBuffer = null;
SocketChannel client = null;
InetSocketAddress isa = null;
SocketEventListener mSocketEventListener = null;
private boolean Connect(String site, int port)
{
if (mSocketEventListener != null)
{
mSocketEventListener.OnSocketPause();
}
boolean ret = false;
try
{
mSelector = Selector.open();
client = SocketChannel.open();
client.socket().setSoTimeout(5000);
isa = new InetSocketAddress(site, port);
boolean isconnect = client.connect(isa);
// 將客戶端設定為異步
client.configureBlocking(false);
// 在輪訊對象中注冊此客戶端的讀取事件(就是當服務器向此客戶端發送數據的時候)
client.register(mSelector, SelectionKey.OP_READ);
long waittimes = 0;
if(!isconnect)
{
while (!client.finishConnect())
{
EngineLog.redLog(TAG, "等待非阻塞連接建立....");
Thread.sleep(50);
if(waittimes < 100)
{
waittimes++;
}
else
{
break;
}
}
}
Thread.sleep(500);
haverepaired();
startListener();
ret = true;
}
catch (Exception e)
{
EngineLog.redLog(TAG + " - Connect error", e != null ? e.toString() : "null");
try
{
Thread.sleep(1000 * 10);
}
catch (Exception e1)
{
EngineLog.redLog(TAG + " - Connect error", e1 != null ? e1.toString() : "null");
}
ret = false;
}
return ret;
}
在上述代碼中,我們可以看到有一個SocketEventListener監聽接口,這個接口用於監聽socket事件,將其回調給調用者
SocketEventListener接口:
public interface SocketEventListener
{
/**
* Socket正在接收數據
* */
public void OnStreamRecive();
/**
* Socket接收數據完成
* */
public void OnStreamReciveFinish();
/**
* Socket有新的消息返回
* */
public void OnStreamComing(byte[] aStreamData);
/**
* Socket出現異常
* */
public void OnSocketPause();
/**
* Socket已修復,可用
* */
public void OnSocketAvaliable();
}監聽接口的使用:
rivate void startListener()
{
if (mReadThread == null || mReadThread.isInterrupted())
{
mReadThread = null;
mReadThread = new Thread()
{
@Override
public void run()
{
while (!this.isInterrupted() && mRunRead)
{
MyLineLog.redLog(TAG,"startListener:" + mSendMsgTime);
try
{
// 如果客戶端連接沒有打開就退出循環
if (!client.isOpen())
break;
// 此方法為查詢是否有事件發生如果沒有就阻塞,有的話返回事件數量
int eventcount = mSelector.select();
// 如果沒有事件返回循環
if (eventcount > 0)
{
starttime = CommonClass.getCurrentTime();
// 遍例所有的事件
for (SelectionKey key : mSelector.selectedKeys())
{
// 刪除本次事件
mSelector.selectedKeys().remove(key);
// 如果本事件的類型為read時,表示服務器向本客戶端發送了數據
if (key.isValid() && key.isReadable())
{
if (mSocketEventListener != null)
{
mSocketEventListener.OnStreamRecive();
}
boolean readresult = ReceiveDataBuffer((SocketChannel) key.channel());
if (mSocketEventListener != null)
{
mSocketEventListener.OnStreamReciveFinish();
}
if(readresult)
{
key.interestOps(SelectionKey.OP_READ);
sleep(200);
}
else
{
throw new Exception();
}
}
key = null;
}
mSelector.selectedKeys().clear();
}
}
catch (Exception e)
{
mRunRead = false;
mReadThread = null;
if(e instanceof InterruptedException)
{
MyLineLog.redLog(TAG, "startListener:" + e.toString());
}
else
{
break;
}
}
}
}
};
mReadThread.setName(TAG + " Listener, " + CommonClass.getCurrentTime());
mRunRead = true;
mReadThread.start();
}
}public boolean SendSocketMsg(byte[] aMessage) throws IOException
{
boolean ret = false;
try
{
sendBuffer.clear();
sendBuffer = ByteBuffer.wrap(aMessage);
int sendsize = client.write(sendBuffer);
sendBuffer.flip();
sendBuffer.clear();
mSendMsgTime = CommonClass.getCurrentTime();
MyLineLog.redLog(TAG, "SendSocketMsg:" + mSendMsgTime + ", sendsize:" + sendsize);
ret = true;
}
catch (Exception e)
{
MyLineLog.redLog(TAG, "發送數據失敗。");
if (mSocketEventListener != null)
{
mSocketEventListener.OnSocketPause();
}
// crash();
}
return ret;
}private boolean ReceiveDataBuffer(SocketChannel aSocketChannel)
{
// n 有數據的時候返回讀取到的字節數。
// 0 沒有數據並且沒有達到流的末端時返回0。
// -1 當達到流末端的時候返回-1。
boolean ret = false;
ByteArrayBuffer bab = new ByteArrayBuffer(8*1024);
while(true)
{
try
{
ByteBuffer readBuffer = ByteBuffer.allocate(1024 * 1);
readBuffer.clear();
int readsize = aSocketChannel.read(readBuffer);
if(readsize > 0)
{
MyLineLog.redLog(TAG, "aSocketChannel.read=>" + readsize);
byte[] readbytes = readBuffer.array();
bab.append(readbytes, 0, readsize);
readBuffer.clear();
readBuffer.flip();
ret = true;
}
else if(readsize == 0)
{
int buffersize = bab.length();
byte[] readdata = bab.buffer();
int readdataoffset = 0;
boolean parsedata = true;
while(readdataoffset < buffersize && parsedata)
{
byte datatype = readdata[readdataoffset];
if (datatype == PushUtils.PACKAGETYPE_HEARTBEAT || datatype == PushUtils.PACKAGETYPE_HEARTBEAR_NODATA)
{
byte[] blockdata = new byte[] { datatype };
ReceiveData(blockdata);
readdataoffset += 1;
blockdata = null;
}
else
{
byte[] blocklength = new byte[4];
System.arraycopy(readdata, readdataoffset + 5, blocklength, 0, 4);
int blocksize = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(blocklength));
blocklength = null;
int blockdatasize = 5 + blocksize + 4;
if(blockdatasize <= buffersize)
{
MyLineLog.redLog(TAG, "塊數據大小:" + blockdatasize);
byte[] blockdata = new byte[blockdatasize];
System.arraycopy(readdata, readdataoffset, blockdata, 0, blockdatasize);
long starttime = CommonClass.getCurrentTime();
ReceiveData(blockdata);
long endtime = CommonClass.getCurrentTime();
MyLineLog.redLog(TAG, "解析數據用時:" + (endtime - starttime) + "ms");
readdataoffset += blockdatasize;
blockdata = null;
}
else if(blockdatasize < 10240)
{//小於10k,則屬於正常包
MyLineLog.redLog(TAG, "塊數據大小:" + blockdatasize + ",小於10k,說明數據不完整,繼續獲取。");
//將未解析數據存到臨時buffer
int IncompleteSize = buffersize - readdataoffset;
if(IncompleteSize > 0)
{
byte[] Incompletedata = new byte[IncompleteSize];
System.arraycopy(readdata, readdataoffset, Incompletedata, 0, IncompleteSize);
bab.clear();
bab.append(Incompletedata, 0, IncompleteSize);
parsedata = false;
Incompletedata = null;
}
}
else
{//異常包
MyLineLog.yellowLog(TAG, "塊數據錯誤大小:" + blockdatasize);
MyLineLog.redLog(TAG,"blockdatasize error:" + blockdatasize);
ret = true;
break;
}
}
}
if(parsedata)
{
ret = true;
break;
}
}
else if(readsize == -1)
{
ret = false;
break;
}
else
{
ret = true;
break;
}
}
catch (IOException e)
{
MyLineLog.redLog(TAG, "aSocketChannel IOException=>" + e.toString());
ret = false;
break;
}
}
bab.clear();
bab = null;
return ret;
}private void ReceiveData(byte[] aDataBlock)
{
try
{
MyLineLog.redLog(TAG, "ReceiveData:" + mSendMsgTime);
if (mSendMsgTime != 0)
{
mSendMsgTime = 0;
}
byte[] ret = null;
int offset = 0;
byte datatype = aDataBlock[offset];
offset += 1;
if (datatype != -1)
{
if (datatype == PushUtils.PACKAGETYPE_HEARTBEAT)
{
ret = new byte[] { datatype };
}
else if (datatype == PushUtils.PACKAGETYPE_HEARTBEAR_NODATA)
{
ret = new byte[] { datatype };
}
else if (datatype == PushUtils.PACKAGETYPE_NORMAL || datatype == PushUtils.PACKAGETYPE_HEARTBEAR_HAVEDATA)
{
byte[] databytelength = new byte[4];
System.arraycopy(aDataBlock, offset, databytelength, 0, 4);
offset += 4;
int header = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(databytelength));
databytelength = null;
if (header == PushUtils.PACKAGEHEADER)
{
byte[] datalengthbyte = new byte[4];
System.arraycopy(aDataBlock, offset, datalengthbyte, 0, 4);
offset += 4;
int datalength = CommonClass.bytes2int(CommonClass.LitteEndian_BigEndian(datalengthbyte));
datalengthbyte = null;
if (datalength > 4)
{
// compressed bit 暫時不壓縮
byte compressed = aDataBlock[offset];
offset += 1;
if (compressed == 1)
{//解壓縮
//跳過頭4個字節,此處用於解壓縮後的數據大小,暫時不需要
offset += 4;
int contentlength = datalength - 1 - 4;
byte[] datacontentbyte = new byte[contentlength];
System.arraycopy(aDataBlock, offset, datacontentbyte, 0, contentlength);
offset += contentlength;
byte[] compressdata = new byte[contentlength - 4];
System.arraycopy(datacontentbyte, 0, compressdata, 0, contentlength - 4);
long starttime = CommonClass.getCurrentTime();
byte[] decompressdatacontentbyte = CommonClass.decompress(compressdata);
long endtime = CommonClass.getCurrentTime();
MyLineLog.redLog(TAG, "解壓縮數據用時:" + (endtime - starttime) + "ms");
int decompressdatacontentbytelength = decompressdatacontentbyte.length;
compressdata = null;
int footer = PushUtils.getInt(datacontentbyte, contentlength - 4);
if (footer == PushUtils.PACKAGEFOOTER)
{
ret = new byte[decompressdatacontentbytelength + 1];
ret[0] = datatype;
System.arraycopy(decompressdatacontentbyte, 0, ret, 1, decompressdatacontentbytelength);
datacontentbyte = null;
decompressdatacontentbyte = null;
}
}
else
{//數據未壓縮
int contentlength = datalength - 1;
byte[] datacontentbyte = new byte[contentlength];
System.arraycopy(aDataBlock, offset, datacontentbyte, 0, contentlength);
offset += contentlength;
int footer = PushUtils.getInt(datacontentbyte, contentlength - 4);
if (footer == PushUtils.PACKAGEFOOTER)
{
ret = new byte[contentlength + 1 - 4];
ret[0] = datatype;
System.arraycopy(datacontentbyte, 0, ret, 1, contentlength - 4);
datacontentbyte = null;
}
}
}
}
}
if (mSocketEventListener != null)
{
mSocketEventListener.OnStreamComing(ret);
}
}
}
catch (Exception e)
{
MyLineLog.redLog(TAG + " - ReceiveData error", e.toString());
}
}public void closeSocket()
{
mRunRead = false;
if (mReadThread != null)
{
if (!mReadThread.isInterrupted())
{
mReadThread.interrupt();
mReadThread = null;
}
}
if (mSelector != null && mSelector.isOpen())
{
try
{
mSelector.close();
}
catch (IOException e)
{
MyLineLog.redLog(TAG + " - closeSocket error", e.toString());
}
mSelector = null;
}
if (client != null)
{
try
{
client.close();
client = null;
}
catch (IOException e)
{
MyLineLog.redLog(TAG + " - closeSocket2 error", e.toString());
}
}
System.gc();
}
android插件化-apkplug框架基本結構-01
由於框架開發更新頻繁的原因一直都沒有時間寫出框架的基本架構讓大家雲裡霧裡的,現在框架已基本穩定和完善,我就抽出時間寫寫關於apkplug框架的基本架構和原理,同時也跟大家
Android Gradle項目Andfix熱修復技術的接入指南
前言很多團隊都有接入Android Andfix的剛性需求,但是早些版本的Andfix接入成本略高。如只支持maven工程、定制的打包插件有很多額外限制、摩天輪打包不支持
Android AIDL和遠程Service調用示例代碼
Android:AIDL和遠程Service調用本講的內容,理解起來很難,也許你看了很多資料也看不明白,但是用起來缺簡單的要命。所以我們干脆拿一個音樂播放器中進度條的實例
Android動態添加設置布局與控件的方法
本文實例講述了Android動態添加設置布局與控件的方法。分享給大家供大家參考,具體如下:有時候我們會在代碼端,動態的設置,添加布局和控件。下面我們就看來看一下如何處理,