Android InetAddress.getByName导致NetworkOnMainThreadException

Android InetAddress.getByName导致NetworkOnMainThreadException,android,runnable,Android,Runnable,意识到我不得不担心一个基于网络的线程会对我的UI线程造成严重破坏,我经历了为我的TCP/IP网络创建自定义处理程序和自定义线程的整个过程,在我的应用程序和远程服务器之间进行命令和响应的乒乓。工作得很好。(您将看到它在下面的代码中被引用为main communicationread(controlCommands);) 在触发线程/处理程序之前,我从SQL中提取IP或主机名(称为currIPstr),然后将其与一组其他变量一起发送给线程/处理程序。 不过,我需要做的一件事是,确保它要么是A)有效的

意识到我不得不担心一个基于网络的线程会对我的UI线程造成严重破坏,我经历了为我的TCP/IP网络创建自定义处理程序和自定义线程的整个过程,在我的应用程序和远程服务器之间进行命令和响应的乒乓。工作得很好。(您将看到它在下面的代码中被引用为
main communicationread(controlCommands);

在触发线程/处理程序之前,我从SQL中提取IP或主机名(称为currIPstr),然后将其与一组其他变量一起发送给线程/处理程序。 不过,我需要做的一件事是,确保它要么是A)有效的IP地址,要么是B)解析主机名——否则,甚至开始尝试都没有意义

好的,没问题,我就叫它:

currIP = InetAddress.getByName(currIPstr).toString().split("/")[1];
但我刚刚遇到的是,在姜饼或StrictMode运行时,上面的行触发了可怕的NetworkOnMainThread异常

是的,对InetAddress.getByName的简单调用就足够了。我一直在努力解决这个问题,所以我将整个函数移到了一个runnable中:

private String currStatIP = null;
private String currentStatIPstr = null;
private Integer currentStatIDstr = -1;
private String currentPort = null;
private String currentLocation = null;
private String currUserName = null;
private String currPassword = null;
private Integer currStatID = -1;
public void StatControl(Cursor c, final String[] commandtosend){


    /*the object will always start off with the first 4 fields being the current login information.
     * [0] = IP Address
     * [1] = port number
     * [2] = username
     * [3] = password
     * [4] = COMMAND -- this will be used in a switchcase inside the pingpong to decide what to do.
     *               -- if the Socket is not open, the first 4 fields will be used to re-initiate the connection
     *               -- otherwise, the command is drawn from this field and sent directly.
     * */


    currentStatIDstr = c.getInt(0);
    currentStatIPstr = c.getString(1);
    currentPort = c.getString(2);
    currentLocation = c.getString(3);
    currUserName = c.getString(4);
    currPassword = c.getString(5);
    currStatID = currentStatIDstr;


    Handler networkLookupHandler = new Handler();
    Runnable networkLookupRunnable = new Runnable() {
         public void run() {
             try {
                    currStatIP = InetAddress.getByName(currentStatIPstr).toString().split("/")[1];
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
             int portNumber = 0;
                try {
                    portNumber = Integer.parseInt(currentPort);
                } catch(NumberFormatException nfe) {
                   nfe.printStackTrace();
                }
                String userName = currUserName;
                String passWord = currPassword;
                String[] command = commandtosend;

                Object[] controlCommands = new Object[]{
                        currStatID,
                        currStatIP, //InetAddress of String representing the IP address
                        portNumber,     //int representation of the port number, taken from String
                        currentLocation,
                        userName,
                        passWord,
                        command
                        };
                /*for(int i=0;i<controlCommands.length;i++){
                    Log.d("object work","controlCommands[" + i + "] is " + controlCommands[i]);
                }*/

                mainCommunicationThread(controlCommands);
         }   
    };
    networkLookupHandler.post(networkLookupRunnable);
}
私有字符串currstip=null;
私有字符串currentStatIPstr=null;
私有整数currentStatIDstr=-1;
私有字符串currentPort=null;
私有字符串currentLocation=null;
私有字符串currUserName=null;
私有字符串currPassword=null;
私有整数currstId=-1;
public void StatControl(光标c,最终字符串[]commandtosend){
/*对象将始终以前4个字段作为当前登录信息开始。
*[0]=IP地址
*[1]=端口号
*[2]=用户名
*[3]=密码
*[4]=命令——这将在乒乓球内的开关盒中使用,以决定要做什么。
*--如果插座未打开,前4个字段将用于重新启动连接
*--否则,命令将从此字段提取并直接发送。
* */
currentstatidsr=c.getInt(0);
currentStatIPstr=c.getString(1);
currentPort=c.getString(2);
currentLocation=c.getString(3);
currUserName=c.getString(4);
currPassword=c.getString(5);
currstistid=currentstatistsr;
Handler networkLookupHandler=新处理程序();
Runnable networkLookupRunnable=新的Runnable(){
公开募捐{
试一试{
currStatIP=InetAddress.getByName(CurrentStatistr.toString().split(“/”)[1];
}捕获(未知后异常e){
e、 printStackTrace();
}
int端口号=0;
试一试{
portNumber=Integer.parseInt(当前端口);
}捕获(NumberFormatException nfe){
nfe.printStackTrace();
}
字符串用户名=currUserName;
字符串密码=当前密码;
String[]command=commandtosend;
对象[]控制命令=新对象[]{
货币主义,
CurrstIP,//表示IP地址的字符串的InetAddress
portNumber,//端口号的int表示形式,取自字符串
当前位置,
用户名,
密码,
命令
};

/*对于(int i=0;i您正试图在可运行的网络中运行操作,因此请尝试在onCreate方法中添加此代码:

     StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
     StrictMode.setThreadPolicy(policy); 

或者我建议您使用asynctask,而不是使用可运行线程。我通过在新线程中运行Inet6Address.getLocalHost()NetworkOnMainThreadException解决了我的Inet6Address.getLocalHost()NetworkOnMainThreadException问题。

我的解决方案:

public static InetAddress getInetAddressByName(String name)
{
    AsyncTask<String, Void, InetAddress> task = new AsyncTask<String, Void, InetAddress>()
            {

                @Override
                protected InetAddress doInBackground(String... params)
                {
                    try
                    {
                        return InetAddress.getByName(params[0]);
                    }
                    catch (UnknownHostException e)
                    {           
                        return null;
                    }                       
                }           
            };
    try
    {
        return task.execute(name).get();
    }
    catch (InterruptedException e)
    {
        return null;
    }
    catch (ExecutionException e)
    {
        return null;
    }

}
公共静态InetAddress getInetAddressByName(字符串名称)
{
AsyncTask任务=新建AsyncTask()
{
@凌驾
受保护的InetAddress doInBackground(字符串…参数)
{
尝试
{
返回InetAddress.getByName(参数[0]);
}
捕获(未知后异常e)
{           
返回null;
}                       
}           
};
尝试
{
返回task.execute(name.get();
}
捕捉(中断异常e)
{
返回null;
}
捕获(执行例外)
{
返回null;
}
}

在没有网络连接的情况下,你到底希望如何解析域名?(可能会有这样的情况,即当域在缓存中,或者当你给它一个ip作为名称时)。在大多数情况下,handler.post会在ui线程上运行(除非你为它创建一个循环器)@njzk2?我没有(显然)深入研究了线程/处理程序的所有警告,得到了一个“为handler.post创建循环器”的示例?没有,因为大多数时候你不需要这样做。如果你只是想在线程中运行你的runnable,那么新线程(runnable).start()就足够了。如果你需要ui访问(你似乎不需要)您将需要asynctasks或handlersyeah,我确实需要ui访问,但我已经为handlerthread和workerthread编写了自定义类(这是由
MainCommunicationRead()调用的)
以上。最奇怪的是,它在4.1模拟器上工作,但在我的4.1手机上不工作。这很好,但我很担心。这就像是在你的安全带没有系上的情况下盖过了车上那讨厌的铃铛。我想我必须更深入地研究这整个
活套。prepare()
东西。?或者,您是建议我将整个
StatControl
函数移动到asynctask的doInBackground()中?我建议您将整个StatControl函数移动到asynctask的doInBackground()中如何使用?