android.os.NetworkOnMainThreadException异常

来源:互联网 发布:阿里云服务器流量攻击 编辑:程序博客网 时间:2024/04/30 10:12

今天练习android例子,例子请求新浪网站地址获取内容,结果遇到android.os.NetworkOnMainThreadException异常。网上查资料说是android4.0+后,在主线程里不能直接访问外部网络。

相关说法见:

http://hi.baidu.com/duqingming/item/8e9504c39d74bd25a0b50aaf

http://blog.csdn.net/haqer0825/article/details/18223793


折腾一番后初步解决问题:

总的思路: MainActivity的onCreate方法中通过新的线程实现对网页内容的访问(采用HttpClient方式),线程中访问到数据后通过消息返回到MainActivity,MainActivity实现Handler接收消息


1.布局文件

activity_main.xml

---------------------------

<RelativeLayout 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/rssNews"></ListView>

</RelativeLayout>

---------------------------


shownews.xml

---------------------------

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/titleView" />
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:autoLink="web"
        android:id="@+id/linkView" />
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/pubDateView" />
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/descriptionView" />

</LinearLayout>

---------------------------


2.java文件

News.java

---------------------------

package com.sharpandroid.pullrssdemo;

public class News {
    
    private String title;
    private String link;
    private String author;
    private String guid;
    private String category;
    private String pubDate;
    private String comments;
    private String description;
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getLink() {
        return link;
    }
    public void setLink(String link) {
        this.link = link;
    }
    public String getPubDate() {
        return pubDate;
    }
    public void setPubDate(String pubDate) {
        this.pubDate = pubDate;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getGuid() {
        return guid;
    }
    public void setGuid(String guid) {
        this.guid = guid;
    }
    public String getCategory() {
        return category;
    }
    public void setCategory(String category) {
        this.category = category;
    }
    public String getComments() {
        return comments;
    }
    public void setComments(String comments) {
        this.comments = comments;
    }
    
    
}


---------------------------


MainActivity.java

---------------------------

package com.sharpandroid.pullrssdemo;

import java.io.InputStream;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {
    private ListView contentView;
    
    private String[] content;//记录标题
    private int count = 0;//计数器
    private List<News> list=null;//新闻
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //一种说法是android 4.0+后不能直接在主进程中进行网络访问, 要通过新开线程来访问,获取的数据通过Message来发送,主进程通过实现Handler来获取返回数据
        new Thread(rssRunnable).start();
        
    }
    /**
     * 渲染列表
     */
    public void renderList(){
        if(null != list && list.size()>0){
            content = new String[list.size()];
            for(News ne : list){
                content[count] = ne.getTitle().trim();
                count++;
            }
            
            contentView =(ListView)findViewById(R.id.rssNews);
            //绑定列表项单击事件监听器
            contentView.setOnItemClickListener(new AdapterView.OnItemClickListener(){

                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position,
                        long id) {
                    News temp = list.get(position);
                    Intent intent = new Intent(MainActivity.this, ShowNewsActivity.class);
                    intent.putExtra("title",temp.getTitle());
                    intent.putExtra("pubDate", temp.getPubDate());
                    intent.putExtra("description", temp.getDescription());
                    intent.putExtra("link", temp.getLink());
                    startActivity(intent);
                }
                
            });
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this,
                    android.R.layout.simple_list_item_1, content);
            //列表展示适配器
            contentView.setAdapter(adapter);
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        menu.add(0, 0, 0, "继续");
        menu.add(0, 1, 1, "退出");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()){
            case 1:
                MainActivity.this.finish();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    
    Runnable rssRunnable = new Runnable(){

        @Override
        public void run() {
            try {
                String path = "http://rss.sina.com.cn/sports/global/focus.xml";
                //访问网络
                InputStream is = NetTool.getStream(path,"UTF-8");
                if(null != is){
                    List<News> list2 = PullNewsService.readXML(is);
                    Log.i("MainActivity", "list2 size = "+list2.size());


                    Message msg = new Message();
                    msg.what=0;
                    msg.obj = list2;
                    //发送消息
                    handler.sendMessage(msg);

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    };
    //接收消息
    private Handler handler = new Handler(){

        @SuppressWarnings("unchecked")
        public void handleMessage(Message msg) {
            if(0 == msg.what){
                list = (List<News>)msg.obj;
                Log.i("MainActivity", "list3 size = "+list.size());
                renderList();
            }
        }
        
    };
    

}


---------------------------


NetTool.java

---------------------------

package com.sharpandroid.pullrssdemo;

import java.io.IOException;
import java.io.InputStream;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.util.Log;

public class NetTool {
    /**
     * 从指定地址获取RSS输入流
     * @param urlpath
     * @param encoding
     * @return
     * @throws ClientProtocolException
     * @throws IOException
     * @throws Exception
     */
    public static InputStream getStream(String urlpath, String encoding){

        //此处采用HttpClient来请求外网内容
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(urlpath);
        HttpResponse httpResponse;
        try {
            httpResponse = httpClient.execute(httpGet);
            HttpEntity entity = httpResponse.getEntity();
            InputStream inputStream = entity.getContent();
            Log.i("NetTool", "inputStream="+inputStream.toString());
            return inputStream;
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

---------------------------


PullNewsService.java

---------------------------

package com.sharpandroid.pullrssdemo;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import android.util.Xml;

public class PullNewsService {
    /**
     * 从RSS输入流中提取新闻信息
     * @param inputStream
     * @return List&lt;News&gt;
     * @throws Exception
     */
    public static List<News> readXML(InputStream inputStream) throws Exception{
        List<News> news_list=null;
        News news = null;
        boolean flog = false;
        //解析器
        XmlPullParser parser = Xml.newPullParser();
        //设置输入流和编码
        parser.setInput(inputStream, "UTF-8");
        //读取初始事件编码
        int eventCode = parser.getEventType();
        //判断文档读取是否结束
        while(eventCode != XmlPullParser.END_DOCUMENT){
            switch(eventCode){
                case XmlPullParser.START_DOCUMENT:{//文档开始事件
                    news_list =new ArrayList<News>();
                    break;
                }
                case XmlPullParser.START_TAG:{
                    if("item".equals(parser.getName())){
                        flog = true;//开始标志
                        news = new News();
                    }
                    if(flog){
                        if("title".equals(parser.getName())){
                            news.setTitle(parser.nextText());
                        }else if("link".equals(parser.getName())){
                            news.setLink(parser.nextText());
                        }else if("pubDate".equals(parser.getName())){
                            news.setPubDate(parser.nextText());
                        }else if("description".equals(parser.getName())){
                            news.setDescription(parser.nextText());
                        }else if("author".equals(parser.getName())){
                            news.setAuthor(parser.nextText());
                        }else if("guid".equals(parser.getName())){
                            news.setGuid(parser.nextText());
                        }else if("category".equals(parser.getName())){
                            news.setCategory(parser.nextText());
                        }else if("comments".equals(parser.getName())){
                            news.setComments(parser.nextText());
                        }
                    }
                    break;
                }
                case XmlPullParser.END_TAG:{
                    if("item".equals(parser.getName())){
                        flog = false;
                        news_list.add(news);
                        news = null;
                    }
                    break;
                }
            }
            //获取下一事件编码
            eventCode = parser.next();
        }
        //返回处理结果
        return news_list;
    }

}


---------------------------


ShowNewsActivity.java

---------------------------

package com.sharpandroid.pullrssdemo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

public class ShowNewsActivity extends Activity {
    
    private TextView titleView, linkView, pubDateView, descriptionView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.shownews);
        titleView = (TextView)findViewById(R.id.titleView);
        linkView = (TextView)findViewById(R.id.linkView);
        pubDateView = (TextView)findViewById(R.id.pubDateView);
        descriptionView = (TextView)findViewById(R.id.descriptionView);
        
        Intent intent = getIntent();
        //获取相应数据
        String title = intent.getStringExtra("title");
        String pubDate = intent.getStringExtra("pubDate");
        String description = intent.getStringExtra("description");
        String link = intent.getStringExtra("link");
        
        titleView.setText(formatString(title));
        linkView.setText(link);
        pubDateView.setText(pubDate);
        descriptionView.setText(formatString(description));
    }
    /**
     * 利用正则表达式, 格式化字符串
     * @param content
     * @return
     */
    public String formatString(String content){
        Pattern p = Pattern.compile("\\s*|\t|\n");
        Matcher m = p.matcher(content);
        return content.trim();
    }
    
}


---------------------------


AndroidManifest.xml

---------------------------

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sharpandroid.pullrssdemo"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    
    <!-- 访问网络权限 -->
    <uses-permission android:name="android.permission.INTERNET"/>

        
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <uses-library android:name="android.test.runner" />
        <activity
            android:name="com.sharpandroid.pullrssdemo.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.sharpandroid.pullrssdemo.ShowNewsActivity"
            android:label="@string/app_name"></activity>
    </application>
    <instrumentation
        android:name="android.test.InstrumentationTestRunner"
        android:targetPackage="com.sharpandroid.pullrssdemo"
        android:label="Test For My App"></instrumentation>
</manifest>

---------------------------


0 0