簡體   English   中英

生命周期更改期間的套接字關閉

[英]Socket closing during lifecycle changes

我正在嘗試使用setRetainInstance(true);在無頭片段中的生命周期更改期間保持套接字打開。 在onCreate中。 但是,當我的應用返回時,會發生以下異常。

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

這是主要活動

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();
    }
}

這可能與應用在暫停或停止時分離而又在重新恢復運行時不重新附加有關系嗎? 還有其他我應該考慮的事情嗎?

最終,應用程序需要通過p2p保持與大約5或6個設備的通信打開。 如果有更好的策略,我歡迎您提出建議。 謝謝。

更新-所以我已經確認,當主要活動進入onStop時,片段的onDestroy和onDetach方法都將觸發。 由於我有一種方法可以在片段死亡時關閉套接字,因此它們正在關閉。 現在最大的問題是如何使片段保持活力?

您也許應該創建一個幫助程序類,它將代表其他類(例如該片段)打開/關閉套接字,該幫助程序類將不受任何生命周期事件的影響,並且只要Application進程處於運行狀態,就可以保持運行狀態。活

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM