【问题标题】:which operation is exactly blocking the main thread in android哪个操作恰好阻塞了android中的主线程
【发布时间】:2017-07-31 11:36:06
【问题描述】:

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

关于这部分我有 2 个问题

1- 以下哪个操作阻塞了主线程(A 或 B)

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

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

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

//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()


}
}

【问题讨论】:

    标签: android multithreading android-asynctask internet-connection


    【解决方案1】:

    以下哪个操作阻塞了主线程(A 或 B)?

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

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

    当您在主线程上调用以下行时:

    InputStream stream=c.getInputStream();
    

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

    如果 A 和 B 都必须在一个新线程中运行,请给它 在新的单独线程中运行每个线程会产生不好的影响吗?

    从技术上讲,是的,在单独的线程中运行两者是不好的。此外,您为什么要这样做?在启动流读取过程之前,您需要确保连接已打开。在单独的线程中调用 A 和 B 会引发并发问题。您必须在 A 之后调用 B,所以即使您解决了并发问题,创建两个单独的线程也是没有用的。

    编辑:

    正如您在 cmets 中所说,您希望避免使用 AsyncTask。另一种方法是 Java 线程。查看以下线程使用示例:

    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
    }
    

    【讨论】:

      【解决方案2】:

      此解决方案使用处理程序将主线程与后台线程(执行 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();
        }
      

      【讨论】:

      • 我想避免 AsyncTask
      • 好的,明天我将发送一个使用处理程序和循环器的示例代码。
      猜你喜欢
      • 2016-09-25
      • 1970-01-01
      • 2020-05-21
      • 2017-12-24
      • 2019-09-01
      • 2019-07-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      相关资源
      最近更新 更多