哪个操作正好阻塞了android中的主线程

时间:2017-07-31 11:36:06

标签: android multithreading android-asynctask internet-connection

当您在Android中建立网络连接时,您正在阻止主线程,因此您必须将此任务的“部分”移动到新线程

我在这部分有两个问题

1-以下哪项操作阻止主线程(A或B)

//A:
HttpURLConnection c = (HttpURLConnection) (new URL(url)).openConnection(); 

//B:
InputStream stream=c.getInputStream();

2-如果上述(A& B)的“both”必须在一个新线程中运行,那么在一个新的单独线程中运行每个线程会产生不良影响吗?看一下下面的代码:

//I temporary removed try & catch to simplify the code 
public class connect{
HttpURLConnection c; String url;
 public connect(String url){
   this.url=url;
   new Thread(new Runnable{
   @override public void run(){
    c = (HttpURLConnection) (new URL(url)).openConnection();
  }
});

}
 public InputStream get(){
  return c.getInputStream();
 //or make this one in a new thread

  }

public InputStream post(Sring params){
c.setRequestMethod("POST");
//.. make some code for posting data , and then call get()
//thats why i cannot perform c.getInputStram() at the same time with openConnection()
return get()


}
}

2 个答案:

答案 0 :(得分:1)

  

以下哪项操作阻止主线程(A或B)?

很明显,操作A和B都会阻塞主线程。只需在主线程上调用以下内容就会立即引发异常( NetworkOnMainThreadException ):

 HttpURLConnection c = (HttpURLConnection) (new URL(url)).openConnection(); 

同样在主线程上调用以下行时:

InputStream stream=c.getInputStream();

您只是尝试通过网络读取字节流。现在有各种因素将决定此操作完成所需的时间。例如,网络速度,您想要读取的总字节数等。应用程序不应该等待并保持空闲,直到读取过程完成。所有与UI相关的进程应该能够在用户对您的应用程序做出反应时运行和使用资源,这是不可能的,因为正在进行的字节读取过程实际上阻塞了主线程。

  

如果A和B都必须在一个新线程中运行,那就是剂量   在一个新的单独线程中运行每个线程会产生什么不好的影响?

从技术上讲,是的,在单独的线程中运行它们都很糟糕。除了你为什么要这样做?在启动流读取过程之前,您需要确保已打开连接。在单独的线程中调用A和B将引发并发问题。你必须在A之后调用B,所以如果你甚至解决并发问题,那么制作两个单独的线程是没有用的。

修改

正如您在评论中所说,您希望避免使用AsyncTask。另一种选择是 Java Threads 。查看以下线程的示例用法:

static public class MyThread extends Thread {
    @Override
    public void run() {
        try {

                // add your url and open connecttion here
                HttpURLConnection c = (HttpURLConnection) (new URL("your url here")).openConnection();
                // read stream or whatever data you want
                InputStream stream = c.getInputStream();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //close your connection & wipe input stream here.
            }
        }
    }

现在我们可以调用这个帖子:

private Thread downloadThread = new MyThread();
downloadThread.start();

您可以随时使用以下代码检查线程是否正在运行:

if (downloadThread != null && downloadThread.isAlive()) {
    // do something when thread is alive here
}

答案 1 :(得分:0)

此解决方案使用handler将主线程与后台线程(执行HTTP连接的线程)连接起来

public class MainActivity extends AppCompatActivity {

 Thread mThread;

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

    startThread();
  }


  public void startThread(){
      String url = "www.google.com";
       String result = "";
    mThread = new Thread(new Runnable() {
        public void run() {
            InputStream is = null;
            HttpURLConnection conn;
            try {
                ConnectivityManager connMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
                NetworkInfo networkInfo = null;
                if (connMgr != null) {
                    networkInfo = connMgr.getActiveNetworkInfo();
                }
                if (networkInfo != null && networkInfo.isConnected() && !mThread.isInterrupted()) {
                    conn = (HttpURLConnection) url.openConnection();
                    is = conn.getInputStream(); 

                     //Here you get the result from inputStream


                }
                threadMsg(result);

            }catch (IOException e){
                e.printStackTrace();
            }
            finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        private void threadMsg(String msg) {

            if (msg != null && !msg.equals("") && !mThread.isInterrupted()) {
                Message msgObj = handler.obtainMessage();
                Bundle b = new Bundle();
                b.putString("message", msg);
                msgObj.setData(b);
                handler.sendMessage(msgObj);
            }
        }
        private Handler handler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                String result = msg.getData().getString("message");
                // What you want to do in UI thread
            }
        };

    });
    mThread.start();
  }