Android 在生命周期更改期间关闭套接字

Android 在生命周期更改期间关闭套接字,android,sockets,android-fragments,Android,Sockets,Android Fragments,我试图用setRetainInstance(true)在无头片段的生命周期更改期间保持套接字打开;立即创建。但是,当我的应用程序返回时,会出现以下异常 E/Client: Receiving thread loop error java.net.SocketException: Socket closed at libcore.io.Posix.recvfromBytes(Native Method) at libcor

我试图用setRetainInstance(true)在无头片段的生命周期更改期间保持套接字打开;立即创建。但是,当我的应用程序返回时,会出现以下异常

E/Client: Receiving thread loop error
          java.net.SocketException: Socket closed
              at libcore.io.Posix.recvfromBytes(Native Method)
              at libcore.io.Posix.recvfrom(Posix.java:189)
              at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:250)
              at libcore.io.IoBridge.recvfrom(IoBridge.java:549)
              at java.net.PlainSocketImpl.read(PlainSocketImpl.java:481)
              at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
              at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
              at java.io.InputStreamReader.read(InputStreamReader.java:233)
              at java.io.BufferedReader.fillBuf(BufferedReader.java:145)
              at java.io.BufferedReader.readLine(BufferedReader.java:397)
              at com.gm.popper_6.ConnectionFragment$Client$ReceivingThread.run(ConnectionFragment.java:183)
              at java.lang.Thread.run(Thread.java:818)
这是片段的代码

public class ConnectionFragment extends Fragment {

    private InetAddress mGoAddress;
    private int mGoPort;
    private Client mClient;
    private static final String TAG = "Connection";
    private Server mServer;
    private Socket mSocket;
    private ConnectionFragmentListener listener;
    private String mMessage;

    public static ConnectionFragment newInstance(InetAddress address, int port){
        Bundle bundle = new Bundle();
        bundle.putSerializable("GoAddress", address);
        bundle.putInt("GoPort", port);
        ConnectionFragment fragment = new ConnectionFragment();
        fragment.setArguments(bundle);

        return fragment;
    }

    public interface ConnectionFragmentListener{
        void onMessageRcvd(String message);
    }

    public void setConnectionFragmentListener(ConnectionFragmentListener listener){
        this.listener = listener;
    }

    private void readBundle(Bundle bundle){
        if (bundle != null){
            mGoAddress = (InetAddress)bundle.getSerializable("GoAddress");
            mGoPort = bundle.getInt("GoPort");
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        readBundle(getArguments());
        mGoAddress = (InetAddress) getArguments().getSerializable("GoAddress");
        mGoPort = getArguments().getInt("GoPort");

        mServer = new Server();
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    //  THE SERVER CLASS
    private class Server{                               //DECLARATION

        ServerSocket mServerSocket = null;
        Thread mThread = null;

        public Server(){                                //CONSTRUCTOR
            mThread = new Thread(new ServerThread());
            mThread.start();
        }

        public void tearDown(){
            mThread.interrupt();
            try {
                mServerSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "Error closing server socket");
            }
        }

        class ServerThread implements Runnable{

            @Override
            public void run() {

                //REMOVE OR COMMENT OUT FOR FINAL
                //android.os.Debug.waitForDebugger();

                try {
                    mServerSocket = new ServerSocket(mGoPort, 50, mGoAddress);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                while (!Thread.currentThread().isInterrupted()){
                    try {
                        mSocket = mServerSocket.accept();
                        Log.d(TAG, "Connected");

                        if (mClient == null){
                            mClient = new Client();
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                        return;
                    }
                }
            }
        }
    }

    //THE CLIENT CLASS
    private class Client {                              //DECLARATION

        private final String CLIENT_TAG = "Client";
        private Thread mSendThread;
        private Thread mRecThread;

        public Client() {                                   //CONSTRUCTOR

            Log.d(CLIENT_TAG, "Creating Client");

            mSendThread = new Thread(new SendingThread());
            mSendThread.start();
        }

        class SendingThread implements Runnable {           //an inner class of Client

            BlockingQueue<String> mMessageQueue;
            private int QUEUE_CAPACITY = 10;

            public SendingThread() {
                mMessageQueue = new ArrayBlockingQueue<String>(QUEUE_CAPACITY);
            }

            @Override
            public void run() {

                mRecThread = new Thread(new ReceivingThread());
                mRecThread.start();

                while (true){

                    try {
                        String msg = mMessageQueue.take();
                        sendMessage(msg);
                    } catch (InterruptedException e) {
                        Log.d(CLIENT_TAG, "Sending loop interrupted, exiting");
                    }
                }
            }
        }           //closes SendingThread, an inner class of Client

        class ReceivingThread implements Runnable{          //an inner class of Client

            @Override
            public void run() {

                BufferedReader input;

                try {
                    //android.os.Debug.waitForDebugger();
                    input = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
                    while (!Thread.currentThread().isInterrupted()){

                        String messageStr = null;
                        messageStr = input.readLine();      //Line 183
                        if (messageStr!= null){
                            Log.d(CLIENT_TAG, "Read from the stream: " + messageStr);
                            mMessage = messageStr;
                            updateMessages(false);          
                        }
                        else{
                            Log.d(CLIENT_TAG, "The null!!!");
                        }
                    }

                    input.close();
                } catch (IOException e) {
                    Log.e(CLIENT_TAG, "Receiving thread loop error", e);
                    e.printStackTrace();
                }
            }       //closes run method
        }           //closes ReceivingThread, an inner class of Client

        public void tearDown(){                         //a method of Client
            try {
                getSocket().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void sendMessage(String msg){            //a method of Client
            try {
                Socket socket = getSocket();            //should return mSocket
                if (socket == null) {
                    Log.d(CLIENT_TAG, "Socket is null");
                } else if (socket.getOutputStream() == null) {
                    Log.d(CLIENT_TAG, "Socket output stream in null");
                }

                PrintWriter out = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(getSocket().getOutputStream())), true);
                out.println(msg);
                out.flush();
                mMessage = msg;
                updateMessages(true);
            } catch (UnknownHostException e){
                Log.d(CLIENT_TAG, "Unkown host", e);
            } catch (IOException e) {
                Log.d(CLIENT_TAG, "I/O exception", e);
            } catch (Exception e){
                Log.d(CLIENT_TAG, "Error 3", e);
            }
            Log.d(CLIENT_TAG, "Message sent: " + msg);
        }       //closes sendMessage, a method of the inner Client class
    }           //closes Client class, an inner class of Connection

    private Socket getSocket() {
        return mSocket;
    }

    public synchronized void updateMessages(boolean local){
        Log.i(TAG, "Updating message: " + mMessage);

        if (local){
            mMessage = "me: " + mMessage;
        }
        else{
            mMessage = "them: " + mMessage;
        }

        if (listener!= null){
            listener.onMessageRcvd(mMessage);       
        }
    }       //closes updateMessages

    public void sendMessage(String msg){                            //CALL FROM MAIN ACTIVITY
        if(mClient != null){                                        //TO SEND A STRING MESSAGE
            mClient.sendMessage(msg);
        }
    }

    public void tearDown(){
        mServer.tearDown();
        mClient.tearDown();
    }

    @Override
    public void onDestroy() {
        tearDown();
        super.onDestroy();
    }
}           //closes class declaration
公共类ConnectionFragment扩展了片段{
私人地址;
私人港口;
私人客户mClient;
私有静态最终字符串TAG=“Connection”;
专用服务器mServer;
专用插座;
私有连接碎片侦听器;
私有字符串消息;
公共静态连接片段newInstance(InetAddress地址,int端口){
Bundle=新Bundle();
bundle.putSerializable(“GoAddress”,address);
bundle.putInt(“GoPort”,port);
ConnectionFragment=新的ConnectionFragment();
fragment.setArguments(bundle);
返回片段;
}
公共接口连接FragmentListener{
void onmessagecvd(字符串消息);
}
public void setConnectionFragmentListener(ConnectionFragmentListener侦听器){
this.listener=listener;
}
私有void readBundle(Bundle){
if(bundle!=null){
mGoAddress=(InetAddress)bundle.getSerializable(“GoAddress”);
mGoPort=bundle.getInt(“GoPort”);
}
}
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(真);
readBundle(getArguments());
mGoAddress=(InetAddress)getArguments().getSerializable(“GoAddress”);
mGoPort=getArguments().getInt(“GoPort”);
mServer=新服务器();
}
@凌驾
public void onStart(){
super.onStart();
}
//服务器类
私有类服务器{//声明
ServerSocket mServerSocket=null;
线程mThread=null;
公共服务器(){//构造函数
mThread=新线程(newserverthread());
mThread.start();
}
公共无效拆卸(){
中断();
试一试{
mServerSocket.close();
}捕获(IOE异常){
e、 printStackTrace();
Log.e(标记“关闭服务器套接字时出错”);
}
}
类ServerThread实现可运行{
@凌驾
公开募捐{
//删除或注释掉以进行最终修改
//android.os.Debug.waitForDebugger();
试一试{
mServerSocket=新的ServerSocket(mGoPort,50,mGoAddress);
}捕获(IOE异常){
e、 printStackTrace();
}
而(!Thread.currentThread().isInterrupted()){
试一试{
mSocket=mServerSocket.accept();
日志d(标记“已连接”);
if(mClient==null){
mClient=新客户端();
}
}捕获(IOE异常){
e、 printStackTrace();
返回;
}
}
}
}
}
//客户端类
私有类客户端{//声明
私有最终字符串CLIENT_TAG=“CLIENT”;
私有线程mSendThread;
私有线程mRecThread;
公共客户端(){//构造函数
Log.d(客户机标签,“创建客户机”);
mSendThread=新线程(new SendingThread());
mSendThread.start();
}
类SendingThread实现可运行的{//客户端的内部类
阻塞队列消息队列;
专用int队列_容量=10;
publicsendingthread(){
mMessageQueue=新的ArrayBlockingQueue(队列容量);
}
@凌驾
公开募捐{
mRecThread=新线程(new ReceivingThread());
mRecThread.start();
while(true){
试一试{
字符串msg=mMessageQueue.take();
发送消息(msg);
}捕捉(中断异常e){
Log.d(客户端标签,“发送循环中断,退出”);
}
}
}
}//关闭客户端的内部类SendingThread
类ReceivingRead实现可运行的{//客户端的内部类
@凌驾
公开募捐{
缓冲读取器输入;
试一试{
//android.os.Debug.waitForDebugger();
输入=新的BufferedReader(新的InputStreamReader(mSocket.getInputStream());
而(!Thread.currentThread().isInterrupted()){
字符串messageStr=null;
messageStr=input.readLine();//第183行
if(messageStr!=null){
Log.d(CLIENT_标记,“从流读取:”+messageStr);
mMessage=messageStr;
更新消息(假);
}
否则{
Log.d(客户机标签“null!!!”);
}
}
input.close();
}捕获(IOE异常){
Log.e(客户机_标记,“接收线程循环错误”,e);
e、 printStackTrace();
}
}//关闭运行方法
}//关闭客户端的内部类ReceivingRead
public void tearDown(){//
public class MainActivity extends Activity implements ChannelListener, DeviceActionListener,
        ConnectionInfoListener, ConnectionFragment.ConnectionFragmentListener{

    //CLASS DECLARATIONS
    public static final String TAG = "Popper";
    private WifiP2pManager manager;
    private Boolean isWifiP2pEnabled = false;
    ArrayList<Target> mTargets = new ArrayList<Target>(0);
    Target mTarget;
    TextView rcvd;
    TextView ip;
    EditText mssg;
    String goAddress = "";
    InetAddress goInetAddress;
    int prefixedPort;

    //declare and initialize an intent filter
    private final IntentFilter intentFilter = new IntentFilter();
    //private final IntentFilter serverFilter = new IntentFilter();

    private Channel channel;
    private BroadcastReceiver receiver = null;
    private ConnectionInfoListener infoListener;
    private Intent serverServiceIntent;
    ConnectionFragment mConnection;

    //????
    public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled) {
        this.isWifiP2pEnabled = isWifiP2pEnabled;
    }

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

        //register app w/p2p framework with call to initialize
        //channel is my apps connection to the p2p framework
        manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        channel = manager.initialize(this, getMainLooper(), null);
        receiver = new P2pReceiver(manager, channel, this);
        rcvd = (TextView)findViewById(R.id.rcvd);
        rcvd.setMovementMethod(new ScrollingMovementMethod());

        //initialize filter and setup to listen for the following broadcast intents
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        Resources res = getResources();
        prefixedPort = res.getInteger(R.integer.GOport);

    }

    @Override
    public void onMessageRcvd(String message) {
        addLine(message);                       
    }

    @Override
    protected void onResume() {
        super.onResume();
        receiver = new P2pReceiver(manager, channel, this);
        registerReceiver(receiver, intentFilter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(receiver);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.action_items, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case R.id.atn_direct_discover:
                if (!isWifiP2pEnabled) {
                    NotificationToast.showToast(MainActivity.this, "Enable P2P!!!");
                    return true;
                }
                final TargetListFragment fragment = (TargetListFragment) getFragmentManager()
                        .findFragmentById(R.id.frag_list);
                fragment.onInitiateDiscovery();
                manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {

                    @Override
                    public void onSuccess() {
                        NotificationToast.showToast(MainActivity.this, "Discovery initiated");
                    }

                    @Override
                    public void onFailure(int reason) {
                        NotificationToast.showToast(MainActivity.this, "Discovery failed");
                    }
                });
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override                                   //this is associated with ChannelListener
    public void onChannelDisconnected() {       //removal causes error.
    }

    @Override
    public void onConnectionInfoAvailable(WifiP2pInfo info) {

        goAddress = info.groupOwnerAddress.getHostAddress();    //this returns a string rep of add.
        goInetAddress = info.groupOwnerAddress;                 //this returns actual inet add.
        ip = (TextView) findViewById(R.id.ip);
        mssg = (EditText) findViewById(R.id.mssg);

        ip.setText(goAddress + ":" + "8080");                   //display GO address and IP
        startConnectionFragment();
    }

    //this override method is triggered by TargetListFragment's DeviceActionListener
    @Override
    public void connect(WifiP2pConfig config) {
        manager.connect(channel, config, new ActionListener() {
            @Override
            public void onSuccess() {
                //maybe use this to gray out and disable the listview object that connected
            }
            @Override
            public void onFailure(int reason) {
            }
        });}

    public void startConnectionFragment(){
        mConnection = ConnectionFragment.newInstance(goInetAddress, prefixedPort);
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(mConnection, "TAG_1");
        ft.commit();
        mConnection.setConnectionFragmentListener(this);
    }

    public void addLine(String line){
        final String msg = line;
        runOnUiThread(new Runnable(){
            @Override
            public void run() {
                rcvd.append("\n" + msg);       
            }
        });
    }

    @Override
    public void onTargetListClick(Target target) {
        mTarget = target;
    }

    public void stopServer() {

        if(serverServiceIntent != null)
        {
            stopService(serverServiceIntent);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mConnection != null){
            //mConnection.tearDown();
        }
        stopServer();
    }

    public void SendMessage(View v){

        EditText txt = (EditText) this.findViewById(R.id.mssg);
        String str = txt.getText().toString();
        mConnection.sendMessage(str);

        txt.getText().clear();
    }
}