【问题标题】:Singleton class for socket connection not working套接字连接的单例类不起作用
【发布时间】:2014-05-08 06:13:25
【问题描述】:

我创建了一个单例类来启用套接字连接,它返回一个套接字对象,应用程序中的任意数量的活动都可以使用该对象。 单例类如下

public class Singleton 
{
private static Socket socket;
private DataInputStream input;
private DataOutputStream output;
private boolean logged;
private static Singleton instance;
private String information;
private static final int SERVERPORT = 8020;
private static final String SERVER_IP = "192.168.1.33";
static PrintWriter out;

private Singleton()
{
}

public static Singleton getInstance()
{
        return instance;
}

public static void initSingleton()
{
    if(instance == null)
    {
        instance = new Singleton();
        InetAddress serverAddr = null;
        try {
            serverAddr = InetAddress.getByName(SERVER_IP);
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        try {
            socket = new Socket(serverAddr, SERVERPORT);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
        try {
            out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())),
                    true);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}



public Socket getSocket()
{
    return socket;
}


public PrintWriter getOutput()
{
    return out;
}

}

在 MainActivity 中,我调用了单例类。

public class MainActivity extends Activity implements OnItemSelectedListener {
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);     
    initSingleton(); }
protected void initSingleton()
{
    Singleton.initSingleton();
}
public void onClickon(View view) {
    Socket socket = Singleton.getInstance().getSocket();

    try{

        PrintWriter out=Singleton.getInstance().getOutput();    
    out.println("0"); 
    }
    catch (Exception e) {
        e.printStackTrace();
    }

}
  }

点击按钮时,会调用 onClickon 函数,该函数使用 Singleton 类的 getSocket() 和 getOutput() 函数返回对象类型。

但是应用程序崩溃了。

日志如下。

05-08 11:33:41.236: E/AndroidRuntime(19813): FATAL EXCEPTION: main
05-08 11:33:41.236: E/AndroidRuntime(19813): Process: com.example.clientmobile2, PID: 19813
05-08 11:33:41.236: E/AndroidRuntime(19813): java.lang.RuntimeException: Unable to start activity     ComponentInfo{com.example.clientmobile2/com.example.clientmobile2.MainActivity}: android.os.NetworkOnMainThreadException
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2269)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread.access$800(ActivityThread.java:139)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.os.Handler.dispatchMessage(Handler.java:102)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.os.Looper.loop(Looper.java:136)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread.main(ActivityThread.java:5102)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.lang.reflect.Method.invokeNative(Native Method)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.lang.reflect.Method.invoke(Method.java:515)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at dalvik.system.NativeStart.main(Native Method)
05-08 11:33:41.236: E/AndroidRuntime(19813): Caused by: android.os.NetworkOnMainThreadException
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at libcore.io.IoBridge.connect(IoBridge.java:112)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.net.Socket.startupSocket(Socket.java:566)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at java.net.Socket.<init>(Socket.java:226)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at com.example.clientmobile2.Singleton.initSingleton(Singleton.java:48)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at com.example.clientmobile2.MainActivity.initSingleton(MainActivity.java:148)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at com.example.clientmobile2.MainActivity.onCreate(MainActivity.java:101)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.Activity.performCreate(Activity.java:5248)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1110)
05-08 11:33:41.236: E/AndroidRuntime(19813):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2173)

【问题讨论】:

  • 何必呢? new Socket(...) 只是一行代码。
  • @EJP 你能详细说明一下吗?
  • 是你在阐述。你正在创建 20 行代码,而你会这样做。

标签: java android sockets design-patterns singleton


【解决方案1】:

一个主要的事情是你不能在主线程上运行昂贵的操作,比如远程连接.. e.t.c, 我的意思是您为此套接字连接创建新线程,否则使用异步任务将解决您的问题。

注意:请不要忘记关闭连接

【讨论】:

  • 感谢您的回复。我有几个问题
  • 1)我可以使用 AsynTask 创建一个在应用程序的所有活动中都可用的套接字连接吗?
  • 你需要关注 Moulder asynctask 在stackoverflow.com/a/23534743/2751529查看我的回答
【解决方案2】:

这段代码:

protected void initSingleton()
{
    Singleton.initSingleton();
}

在您尝试获取实例之前未执行,即使您正在调用该函数onCreate()。为什么要在单独的方法上实例化 Singleton,而不是在 getInstance() 中实例化它?

将您的代码更改为如下所示,以避免在调用 Singleton 并且实例不存在时出现此类问题。

public static Singleton getInstance()
{
     if(instance == null)
        initSingleton();

     return instance;
}

private static void initSingleton()
{
     instance = new Singleton();
     InetAddress serverAddr = null;
     try 
     {
         serverAddr = InetAddress.getByName(SERVER_IP);
     } 
     catch (UnknownHostException e) 
     {
         System.err.println("Fail when getting Server Address.");
     }
     try 
     {
         socket = new Socket(serverAddr, SERVERPORT);
     } 
     catch (IOException e) 
     {
         System.err.println("Failed creating new socket.");
     }  
     try 
     {
         out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())),
                    true);
     } 
     catch (IOException e) 
     {
          System.err.println("EPIC FAIL HERE"); 
     }
}

主要活动:

public class MainActivity extends Activity implements OnItemSelectedListener 
{
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);     
    }

    public void onClickon(View view) 
    {
        Socket socket = Singleton.getInstance().getSocket();
        try
        {
           PrintWriter out=Singleton.getInstance().getOutput();    
           out.println("0"); 
        }
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
  }

【讨论】:

  • 谢谢您的回复。应用程序仍然崩溃。我根据您的回答检查了 Singleton.Java 代码。我需要在 MainActivity.java 中进行任何更改吗? @FunctionR
  • 立即尝试。如果它仍然引发错误,请发布它,如果它是不同的。如果它在执行期间确实抛出错误,那么问题出在您创建 socket 的方式上。
  • 我还更改了您的 catch 语句,以便您无需阅读一堆堆栈跟踪即可知道代码失败的位置。
  • 再次感谢您的帮助!应用程序再次崩溃。是不是因为你没有调用 initSingleton() 方法?
  • 当我调用Singleton.getInstance().getSocket(); 时,getInstance 方法会调用initSingleton(),因此会创建单例。崩溃时打印了什么?
【解决方案3】:

FunctionR 的解决方案是正确的,但它不是线程安全的,因此一种解决方案可以是在静态初始化器中实例化单例变量或使用同步块来使单例实例化线程安全 (http://www.jguru.com/faq/view.jsp?EID=124425)。

【讨论】:

    【解决方案4】:

    嗨,我尝试了我们的代码,我做了一些修改,它工作正常,我实例化套接字并在执行时在前面实现 initSingleton() 主要活动

    public class ConnectActivity extends Activity {
        Socket clientSocket;
        Singleton instance;
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_connect);
            instance=new Singleton();
    
            new Thread(new ClientThread()).start();
            //Socket socket = Singleton.getInstance().getSocket();
    
        }
        protected void initSingleton()
        {
            instance.initSingleton();
        }
       
        class ClientThread implements Runnable {
            @Override
            public void run() {
    
                    initSingleton();
                    Socket socket = Singleton.getInstance().getSocket();
                }
        }

    单例()

    public class Singleton {
        public static Socket clientSocket;
        /* private DataInputStream input;
         private DataOutputStream output;*/
        private boolean logged;
        public static Singleton instance;
        public static String information;
        public static int SERVER_PORT;
        public static String SERVER_IP;
        /*static PrintWriter out;*/
    
        public Singleton() {
        }
    
        public Singleton(int server_port, String server_ip) {
            SERVER_PORT = server_port;
            SERVER_IP = server_ip;
    
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    
        public static void initSingleton() {
            if (instance == null) {
                instance = new Singleton();
                InetAddress serverAddr = null;
                try {
                    serverAddr = InetAddress.getByName(SERVER_IP);
                    information=SERVER_IP;
                } catch (UnknownHostException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
                try {
                    clientSocket = new Socket(information, SERVER_PORT);
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
    
    
            }
        }
    
        public Socket getSocket() {
            return clientSocket;
        }
    }

    我将代码更改为我的项目,但我认为你可以使用修改来运行你的`

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-01
      • 1970-01-01
      • 2015-11-01
      • 1970-01-01
      • 2021-05-18
      • 2023-01-20
      • 2012-09-13
      • 2020-05-20
      相关资源
      最近更新 更多