First of all, we should understand two points:
1.Android does not allow access to the network in the main thread (for android, the main thread is the UI thread).
2.Android does not allow updating UI controls directly in a sub-thread.
For Question 1, you might say, is this not easy to do? Is it all right to open another thread? Yes, you're smart and the principle is simple.
For Problem 2, Interthreaded Communication (IPC) is needed, and Android encapsulates it very well, so there are today's Handler and AsyncTask.
Applicability:
AsyncTask is a lightweight backstage asynchronous task class, simple and convenient. Suitable for less background tasks, because each background task has to be written as a Class to inherit AsyncTask, the code seems bloated. Otherwise, use Handler. It's powerful, but it's hard for beginners to master.
Usage method:
AsyncTask defines three generic types: Params, Progress and Result.
- Params Start the input parameters for task execution, such as the URL of the HTTP request.
- Progress: Percentage of background task execution.
- Result The result that the background execution task ultimately returns, such as String.
At least rewrite the following methods:
- doInBackground(Params... ) Background execution, more time-consuming operations can be placed here. Note that the UI cannot be manipulated directly here. It usually takes a long time for this method to execute in the background thread and complete the main task. You can call publicProgress during execution. ) To update the progress of the task. (Must be rewritten)
- onPostExecute(Result) is equivalent to the way Handler processes the UI, where the result obtained in doInBackground can be used to process the operation UI. This method is executed on the main thread, and the result of task execution is returned as a parameter of this method (you can not override it, because you can update the UI with post(Runable r), but since AsyncTask is used, it is convenient to override this method directly!).
If necessary, you have to rewrite the following three methods, but not necessarily:
- OnProgress Update ) You can use progress bars to increase user experience. This method is executed in the main thread to show the progress of task execution.
- onPreExecute() This is the interface where the end user calls Excute. This method is called before the task is executed, and the progress dialog box can be displayed here.
- onCancelled() The action to be done when the user calls cancel
Using the AsyncTask class, the following guidelines must be followed:
- Task instances must be created in UI thread s;
- The execute method must be called in the UI thread.
- Do not manually call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...).
- This task can only be executed once, otherwise it will be abnormal when it is called many times.
Handler is used with Thread. Specific use method, please see the following small examples.
Server-side code: Generate a random number between 0 and 10 and encapsulate it as a JSON object
package com.test.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("{\"rand\":"+"\""+(int)(Math.random()*10)+"\""+"}"); out.flush(); out.close(); } }
At this point, the browser access test is successful:
Note: 8888 is my modified tomcat port number, the default is 8080 oh, you do not learn from me.
Android side:
Layout files are used for displaying data in just one Textview:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="xjtu.com.test.MainActivity"> <TextView android:id="@+id/tv" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="50sp" android:gravity="center"/> </LinearLayout>
Note the addition of network access privileges in the Manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
Code:
The first is AsyncTask:
package xjtu.com.test; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import org.json.JSONObject; import xjtu.com.utils.HttpUtils; public class MainActivity extends AppCompatActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv=(TextView)findViewById(R.id.tv); new GetData().execute(); } class GetData extends AsyncTask<Void,Void,String>{ @Override protected String doInBackground(Void... params) { String json_str= HttpUtils.getJsonContent(HttpUtils.BaseUrl); String result=""; try{ JSONObject js_obj=new JSONObject(json_str); result=js_obj.getString("rand"); }catch (Exception e){ e.printStackTrace(); } return result; } @Override protected void onPostExecute(String s) { tv.setText(s); } } }
The parameter s of onPostExecute(String s) is actually the result of the return value of the doInBackground method.
Results Screenshot:
The second way: Handler
package xjtu.com.test; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; import org.json.JSONObject; import xjtu.com.utils.HttpUtils; public class MainActivity extends AppCompatActivity { private TextView tv; private Thread thread; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv=(TextView)findViewById(R.id.tv); //Instantiate a handler in the main thread, waiting to receive Message from the sub-thread handler=new Handler(){ @Override public void handleMessage(Message msg) { if (msg.what == 0x123){//Information mark Bundle bundle=msg.getData(); tv.setText(bundle.getString("text")); } } }; } @Override protected void onResume() { super.onResume(); thread=new Thread(new Runnable() { @Override public void run() { while(!Thread.currentThread().isInterrupted()) { String json_str = HttpUtils.getJsonContent(HttpUtils.BaseUrl); String result = ""; try { JSONObject js_obj = new JSONObject(json_str); result = js_obj.getString("rand"); //Communicate with the main thread Message message = new Message(); message.what = 0x123; Bundle bundle = new Bundle(); bundle.putString("text", result); message.setData(bundle); handler.sendMessage(message); //Thread hibernates for 1 second Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } }); //Open a new thread thread.start(); } @Override protected void onStop() { super.onStop(); //When the current Activity terminates, the thread is blocked thread.interrupt(); } }
The resulting random number is updated every second.
Finally, an encapsulation class for accessing the network is used in the above code. The code is as follows:
package xjtu.com.utils; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; public class HttpUtils { public static String BaseUrl = "http://172.16.0.10:8888/Test/servlet/TestServlet"; public static String getJsonContent(String path) { try { URL url = new URL(path); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(3000); connection.setRequestMethod("GET"); connection.setDoInput(true); int code = connection.getResponseCode(); if (code == 200) { return changeInputString(connection.getInputStream()); } } catch (Exception e) { e.printStackTrace(); } return ""; } private static String changeInputString(InputStream inputStream) { String jsonString = ""; ByteArrayOutputStream outPutStream = new ByteArrayOutputStream(); byte[] data = new byte[1024]; int len = 0; try { while ((len = inputStream.read(data)) != -1) { outPutStream.write(data, 0, len); } jsonString = new String(outPutStream.toByteArray()); } catch (Exception e) { e.printStackTrace(); } return jsonString; } }