最近做一个Android项目,利用Jsoup读取和解析网页数据,同样的程序在Android2.3上运行完全正常,而跑到Android4上面,bug出现了...
看了一下异常:android.os.NetworkOnMainThreadException
然后,上网搜索一下才发现,原来Android4默认情况下是不允许在主线程中访问网络的。
解决问题的思路有两种:
1、解除主线程网络访问限制,参见http://developer.android.com/reference/android/os/StrictMode.html
在onCreate中加入以下代码即可:
<span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">StrictMode</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">setThreadPolicy</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><code style="line-height: 14px;"><a target=_blank target="_blank" href="http://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder.html" style="color: rgb(37, 138, 175); text-decoration: none;"><span class="typ" style="color: rgb(102, 0, 102);">StrictMode</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">ThreadPolicy</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">Builder</span></a></code><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">detectDiskReads</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">detectDiskWrites</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">detectNetwork</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="com" style="color: rgb(136, 0, 0);">// or .detectAll() for all detectable problems</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">penaltyLog</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">build</span><span class="pun" style="color: rgb(102, 102, 0);">());</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">StrictMode</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">setVmPolicy</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><code style="line-height: 14px;"><a target=_blank target="_blank" href="http://developer.android.com/reference/android/os/StrictMode.VmPolicy.Builder.html" style="color: rgb(37, 138, 175); text-decoration: none;"><span class="typ" style="color: rgb(102, 0, 102);">StrictMode</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">VmPolicy</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">Builder</span></a></code><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">detectLeakedSqlLiteObjects</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">detectLeakedClosableObjects</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">penaltyLog</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">penaltyDeath</span><span class="pun" style="color: rgb(102, 102, 0);">()</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">build</span><span class="pun" style="color: rgb(102, 102, 0);">());</span>
不过如果要求至少是API-9才可以,否则会编译器提示错误,所以在适配一些低版本系统时候不太给力。
2、多线程中访问网络-既然系统默认不允许在主线程中访问,那么再开一个线程,这样在处理复杂流程的时候也不会影响界面的流畅,用户体验也好。
以下是一段测试代码:
- public class MainActivity extends Activity {
- private Button btnTest;
- private Button btnClear;
- private TextView txtResult;
- private Handler handler = null;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- // .detectDiskReads()
- // .detectDiskWrites()
- // .detectNetwork() // or .detectAll() for all detectable problems
- // .penaltyLog()
- // .build());
- // StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- // .detectLeakedSqlLiteObjects()
- // .detectLeakedClosableObjects()
- // .penaltyLog()
- // .penaltyDeath()
- // .build());
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btnTest = (Button) findViewById(R.id.btnTest);
- btnClear = (Button) findViewById(R.id.btnClear);
- txtResult = (TextView) findViewById(R.id.txtResult);
- //
- handler = new Handler() {
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- if (msg.what == 0) {
- txtResult.append(" Begin test >> ");
- } else if (msg.what == 1) {
- txtResult.append(msg.obj.toString());
- } else if (msg.what == 2) {
- txtResult.append(" <<End test ");
- }
- }
- };
- //
- txtResult.setText("");
- txtResult.setMovementMethod(ScrollingMovementMethod.getInstance());
- btnTest.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // doTest();
- doTestOnAndroid4();
- }
- });
- btnClear.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- doClear();
- }
- });
- }
- protected void doClear() {
- txtResult.setText("");
- }
- protected void doTest() {
- String url = "http://www.baidu.com/";
- txtResult.append(" Begin test >> ");
- String text = "";
- try {
- text = Jsoup.connect(url).get().toString();
- } catch (Exception e) {
- e.printStackTrace();
- // text = e.getMessage();
- }
- txtResult.append(text);
- txtResult.append(" <<End test ");
- }
- protected void doTestOnAndroid4() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- Message m = new Message();
- m.what = 0;
- handler.sendMessage(m);
- //
- m = new Message();
- m.what = 1;
- String url = "http://www.baidu.com/";
- try {
- m.obj = Jsoup.connect(url).get().toString();
- } catch (Exception e) {
- e.printStackTrace();
- // m.obj = e.getMessage();
- }
- handler.sendMessage(m);
- //
- m = new Message();
- m.what = 2;
- handler.sendMessage(m);
- }
- }).start();
- }
- }