2014年11月

这个组件是很早之前写的了,当时的一个需求是需要实现在Android手机客户端的长连接,所以需要用到socket通信,当时查阅了相关资料,在其他前辈的基础上,整理出这样一个组件,其中肯定还有许多问题,但还是先放出来吧。

实现的原理很简单,开启一个子线程,与服务器通信,并且实现了断线重连,获取到数据以后回调接口,不阻塞主线程。

连接服务器线程类

package org.yong.tcpsocket;

import java.util.Vector;

import android.util.Log;

/**
 * 连接服务器线程类
 * 
 * @author Cheng Yong
 */
public class TCPSocketConnect implements Runnable {

    private boolean isConnect = false;// 是否连接服务器
    private boolean isWrite = false;// 是否发送数据
    private static Vector<byte[]> datas = new Vector<byte[]>();// 待发送数据队列
    private Object lock = new Object();// 连接锁对象
    private TCPSocketFactory mSocket;// socket连接
    private WriteRunnable writeRunnable;// 发送数据线程
    private String ip = null;
    private int port = -1;

    /**
     * 创建连接
     * 
     * @param callback
     *            回调接口
     * @param executor
     *            线程池对象
     */
    public TCPSocketConnect(TCPSocketCallback callback) {
        mSocket = new TCPSocketFactory(callback);// 创建socket连接
        writeRunnable = new WriteRunnable();// 创建发送线程
    }

    @Override
    public void run() {
        if (ip == null || port == -1) {
            return;
        }
        isConnect = true;
        while (isConnect) {
            synchronized (lock) {
                try {
                    Log.e("TCPSocketConnect",">TCP连接服务器<");
                    mSocket.connect(ip, port);// 连接服务器
                } catch (Exception e) {
                    try {
                        Log.e("TCPSocketConnect",">TCP连接服务器失败, 6秒后重新连接<");
                        resetConnect();// 断开连接
                        lock.wait(6000);
                        continue;
                    } catch (InterruptedException e1) {
                        continue;
                    }
                }
            }
            Log.e("TCPSocketConnect",">TCP连接服务器成功<");
            isWrite = true;// 设置可发送数据
            new Thread(writeRunnable).start();// 在线程池启动发送线程
            try {
                mSocket.read();// 获取数据
            } catch (Exception e) {
                Log.e("TCPSocketConnect",">TCP连接异常<", e);
            } finally {
                Log.e("TCPSocketConnect",">TCP连接中断<");
                resetConnect();// 断开连接
            }
        }
        Log.e("TCPSocketConnect",">=TCP结束连接线程=<");
    }

    /**
     * 关闭服务器连接
     */
    public void disconnect() {
        synchronized (lock) {
            isConnect = false;
            lock.notify();
            resetConnect();
        }
    }

    /**
     * 重置连接
     */
    public void resetConnect() {
        Log.e("TCPSocketConnect",">TCP重置连接<");
        writeRunnable.stop();// 发送停止信息
        mSocket.disconnect();
    }

    /**
     * 向发送线程写入发送数据
     */
    public void write(byte[] buffer) {
        writeRunnable.write(buffer);
    }

    /**
     * 设置IP和端口
     * 
     * @param ip
     * @param port
     */
    public void setAddress(String host, int port) {
        this.ip = host;
        this.port = port;
    }

    /**
     * 发送数据
     */
    private boolean writes(byte[] buffer) {
        try {
            mSocket.write(buffer);
            Thread.sleep(1);
            return true;
        } catch (Exception e) {
            resetConnect();
            return false;
        }
    }

    /**
     * 发送线程
     * 
     * @author Esa
     */
    private class WriteRunnable implements Runnable {

        private Object wlock = new Object();// 发送线程锁对象

        @Override
        public void run() {
            Log.e("TCPSocketConnect",">TCP发送线程开启<");
            while (isWrite) {
                synchronized (wlock) {
                    if (datas.size() <= 0) {
                        try {
                            wlock.wait();// 等待发送数据
                        } catch (InterruptedException e) {
                            continue;
                        }
                    }
                    while (datas.size() > 0) {
                        byte[] buffer = datas.remove(0);// 获取一条发送数据
                        if (isWrite) {
                            writes(buffer);// 发送数据
                        } else {
                            wlock.notify();
                        }
                    }
                }
            }
            Log.e("TCPSocketConnect",">TCP发送线程结束<");
        }

        /**
         * 添加数据到发送队列
         * 
         * @param buffer
         *            数据字节
         */
        public void write(byte[] buffer) {
            synchronized (wlock) {
                datas.add(buffer);// 将发送数据添加到发送队列
                wlock.notify();// 取消等待
            }
        }

        public void stop() {
            synchronized (wlock) {
                isWrite = false;
                wlock.notify();
            }
        }
    }
}

 

获取网络数据回调类

package org.yong.tcpsocket;

/**
 * 获取网络数据回调类
 * 
 * @author Cheng Yong
 * 
 */
public abstract interface TCPSocketCallback {
    
    /**
     * 断开连接
     */
    public static final int TCP_DISCONNECTED = 0;
    
    /**
     * 已连接
     */
    public static final int TCP_CONNECTED = 1;
    
    /**
     * 连接获得数据
     */
    public static final int TCP_DATA = 2;

    /**
     * 当建立连接是的回调
     */
    public abstract void tcp_connected();

    /**
     * 当获取网络数据回调接口
     * 
     * @param buffer
     *            字节数据
     */
    public abstract void tcp_receive(byte[] buffer);

    /**
     * 当断开连接的回调
     */
    public abstract void tcp_disconnect();

}

 

Socket连接操作类

package org.yong.tcpsocket;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;

/**
 * Socket连接操作类
 * 
 * @author Cheng Yong
 */
public class TCPSocketFactory {

    private Socket mSocket;// socket连接对象
    private DataOutputStream out;
    private DataInputStream in;// 输入流
    private byte[] buffer = new byte[1024*1];// 缓冲区字节数组,信息不能大于此缓冲区
    private byte[] tmpBuffer;// 临时缓冲区
    private TCPSocketCallback callback;// 信息回调接口
    private int timeOut = 1000 * 30;

    /**
     * 构造方法传入信息回调接口对象
     * 
     * @param sdi
     *  回调接口
     */
    public TCPSocketFactory(TCPSocketCallback callback) {
        this.callback = callback;
    }

    /**
     * 连接网络服务器
     * 
     * @throws UnknownHostException
     * @throws IOException
     */
    public void connect(String ip, int port) throws Exception {
        mSocket = new Socket();
        SocketAddress address = new InetSocketAddress(ip, port);
        mSocket.connect(address, timeOut);// 连接指定IP和端口
        if (isConnected()) {
            out = new DataOutputStream(mSocket.getOutputStream());// 获取网络输出流
            in = new DataInputStream(mSocket.getInputStream());// 获取网络输入流
            if (isConnected()) {
                callback.tcp_connected();
            }
        }
    }

    public void setTimeOut(int timeOut) {
        this.timeOut = timeOut;
    }

    /**
     * 返回连接服是否成功
     * 
     * @return
     */
    public boolean isConnected() {
        if (mSocket == null || mSocket.isClosed()) {
            return false;
        }
        return mSocket.isConnected();
    }

    /**
     * 发送数据
     * 
     * @param buffer
     *            信息字节数据
     * @throws IOException
     */
    public void write(byte[] buffer) throws IOException {
        if (out != null) {
            out.write(buffer);
            out.flush();
        }
    }

    /**
     * 断开连接
     * 
     * @throws IOException
     */
    public void disconnect() {
        try {
            if (mSocket != null) {
                if (!mSocket.isInputShutdown()) {
                    mSocket.shutdownInput();
                }
                if (!mSocket.isOutputShutdown()) {
                    mSocket.shutdownOutput();
                }
            }
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }
            if (mSocket != null && !mSocket.isClosed()) {// 判断socket不为空并且是连接状态
                mSocket.close();// 关闭socket
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            callback.tcp_disconnect();
            out = null;
            in = null;
            mSocket = null;// 制空socket对象
        }
    }

    /**
     * 读取网络数据
     * 
     * @throws IOException
     */
    public void read() throws IOException {
        if (in != null) {
            int len = 0;// 读取长度
            while ((len = in.read(buffer)) > 0) {
                tmpBuffer = new byte[len];// 创建临时缓冲区
                System.arraycopy(buffer, 0, tmpBuffer, 0, len);// 将数据拷贝到临时缓冲区
                callback.tcp_receive(tmpBuffer);// 调用回调接口传入得到的数据
                tmpBuffer = null;
            }
        }
    }
}

 

经常在使用Android Studio的时候会发现不进行设置的话它不能自动的导入一些包名,敲快捷键Alter + Enter键也只能一次导入一个,所以今天就教大家如何设置Android Studio来自动导入包名。

首先我们打开我们下载安装好的Android Studio,进入首选项设置页面:

QQ20150729-1@2x.png

点击这个小扳手就可以进入了,进入以后,找到 Editor-->General-->Auto Import:

QQ20150729-2@2x.png

然后把右侧的选项全部选中:

QQ20150729-3@2x.png

点击确定之后我们可以写入代码看看,我们可以看到一些类和包名会自动导入进去。

由于国内的网络原因,导致国内的开发者经常无法更新Android Studio 和 Android SDK Manager,以下是我的两个可行的方法

1.设置国内镜像源

目前我所知道的有2个源,一个是 mirrors.neusoft.edu.cn:80,还有一个是 sdk.gdgshanghai.com:8000,下面是以mirrors.neusoft.edu.cn:80为例子的设置方法

—》在Windows 下

配置步骤 1.启动 Android SDK Manager ,打开主界面,依次选择「Tools」、「Options...」,弹出『Android SDK Manager - Settings』窗口; 2.在『Android SDK Manager - Settings』窗口中,在「HTTP Proxy Server」和「HTTP Proxy Port」输入框内填入mirrors.neusoft.edu.cn和80,并且选中「Force https://... sources to be fetched using http://...」复选框。 3.设置完成后单击「Close」按钮关闭『Android SDK Manager - Settings』窗口返回到主界面; 4.依次选择「Packages」、「Reload」。

—》在Mac 下

配置步骤 1.启动 Android SDK Manager ,打开主界面,依次选择「Android SDK Manager」、「Preferences」,弹出『Android SDK Manager - Settings』窗口; 2.在『Android SDK Manager - Settings』窗口中,在「HTTP Proxy Server」和「HTTP Proxy Port」输入框内填入mirrors.neusoft.edu.cn和80,并且选中「Force https://... sources to be fetched using http://...」复选框。 3.设置完成后单击「Close」按钮关闭『Android SDK Manager - Settings』窗口返回到主界面; 4.依次选择「Packages」、「Reload」。 ![avatar](/usr/uploads/2014/11/QQ2014110712.png) 2.手动修改hosts

先 ping  dl.google.com  得到IP地址,修改hosts文件指定 dl-ssl.google.com 的 IP,hosts 文件在mac 和 windows 下的路径不同

—》在Windows 下

Hosts文件位置 C:\windows\system32\drivers\etc\hosts

—》在Mac 下

Hosts文件位置 /etc/hosts

在最下面一行加上  :

203.208.46.146  dl.google.com 203.208.46.146  dl-ssl.google.com

avatar

每个人得到的IP地址可能不同,以你自己的IP地址为准