从两个方面说下这个问题:
1. 不让访问网络的原因
2. 解决该问题的办法
不让访问网络的原因:
由于对于网络状况的不可预见性,很有可能在网络访问的时候造成阻塞,那么这样一来我们的主线程UI线程 就会出现假死的现象,产生很不好的用户体验。所以,默认的情况下如果直接在主线程中访问就报出了这个异常,名字是NetworkOnMainThreadException
解决该问题的办法
1. 独立线程
2. 异步线程AsyncTask
3. StrictMode修改默认的策略
1) 独立线程的办法
启动一个新线程的代码:
new Thread(){@Override
public void run() {
Dosomething();
handler.sendEmptyMessage(0);
}
}.start();
例子:
- 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("\nBegin test >>\n");
- } else if (msg.what == 1) {
- txtResult.append(msg.obj.toString());
- } else if (msg.what == 2) {
- txtResult.append("\n<<End test\n");
- }
- }
- };
- //
- 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("\nBegin test >>\n");
- String text = "";
- try {
- text = Jsoup.connect(url).get().toString();
- } catch (Exception e) {
- e.printStackTrace();
- // text = e.getMessage();
- }
- txtResult.append(text);
- txtResult.append("\n<<End test\n");
- }
- 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();
- }
- }
此处我们重写了线程类的run方法,执行Dosomething. 在里面还有个handler对象,这又涉及到了跨线程修改UI元素内容的问题。在java中是不允许跨线程修改UI元素的,如我们在新启动的线程中想去修改UI主线程中TextView的文本时,会报错误的。如果想做这样的操作,我们就得借助Handler这个类来实现。 关于这个handler类的用法,我们单独的再来写一篇博客进行介绍。
2) 异步调用的方法 AsyncTask
这里关于AsyncTask 介绍的文章不错, 详细情况看作者的介绍吧
http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html#2824345
接下来也将会有一篇博客专门介绍 关于更新主线程UI线程的所有办法
3) StrictMode修改默认的策略
在我们的Activity类的onCreate方法中,设置如下规则:
StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
这样也可以解决这个问题
关于StrictMode的具体介绍,请看另一个博客介绍的非常详细:
http://hb.qq.com/a/20110914/000054.htm
在onCreate中加入以下代码即可:
<span style="font-family: Arial; font-size: 14px; line-height: 26px; background-color: rgb(255, 255, 255);">不过如果要求至少是API-9才可以,否则会编译器提示错误,所以在适配一些低版本系统时候不太给力。</span>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());