安卓

来源:互联网 发布:华为交换机查看端口ip 编辑:程序博客网 时间:2024/04/27 06:17

这里写图片描述

一、 实验题目

网络访问

1.熟练使用 HttpURLConnection 访问 WebService
2.熟悉使用多线程以及 Handler 更新 UI
3.熟悉使用 XmlPullParser 解析 xml 文档数据
4.了解 RecyclerView 控件的使用

二、 实现内容

实现一个简单的天气查询应用,具体要求如下:

三、 课堂实验结果

(1)实验步骤以及关键代码

本次实验基于一个如下网站
http://ws.webxml.com.cn/WebServices/WeatherWS.asmx?op=getWeather


        设置一个app界面,输入城市名,即查询该CityCode的天气情况,对返回的XML文件进行解析后,在app中显示。如下(这就是最后的结果啦,当然根据你输入的城市不同,结果不同,输入城市名和城市代号都是可以识别的)

XML文件内容如下所示(本是要就要解析xml文件获取string标签中的内容,按我们喜欢的格式在app中显示。)

APP开始界面如下所示(那啥,这些都是我初始默认的不用管,就这么个布局)

layout.xml

        没什么特殊的,按照课件的格式布局,主要就是要应用RecyclerView,需要自己新建一个lib文件夹,放入存有RecyclerView的jar包,还不够,还要吧这个包Add As Library.才正确导入,可以调用RecyclerView空间,设置它的属性横行滚动

<android.support.v7.widget.RecyclerView        android:layout_width="wrap_content"        android:scrollbars="horizontal"        android:id="@+id/recyclerview"        android:layout_height="match_parent">    </android.support.v7.widget.RecyclerView>

这里写图片描述

MainActivity.java

        首先AS新建一个工程network,布局啥的该设计就设计好,直接从MainActivity开始吧。首先,所有事件,都是基于点击search按钮来进行,点击按钮,首先要判断的是,有没有网络连接,网络连接正常,才回去访问这个url.
本次实验我们固定String url=”http://ws.webxml.com.cn/WebServices/WeatherWS.asmx/getWeather”;
这个跟上面是不同的,可以点击访问一下看看。我们最终需要的是http://ws.webxml.com.cn/WebServices/WeatherWS.asmx/getWeather?theCityCode=2350&theUserID=ecefcf4c81b847a189ff94a159d54dd0(试了好久。)比url多了俩个参数theCityCode和theUserID,就是根据我们的输入城市不同,会请求到不同的url
第一步在 manifest 中添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

        检查网络连接是否正常:ConnectivityManager主要管理和网络连接相关的操作 。getActiveNetworkInfo() 方法返回一个 NetworkInfo实例,它表示可以找到的第一个已连接的网络接口,如果返回 null,则表示没有已连接的网络接口(意味着网络连接不可用)
在点击按钮后进行判断,网络访问,则用sendRequestWithHttpURLConnection();函数进行HTTP请求建立连接

button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                ConnectivityManager connMgr =(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);//获取管理和网络连接相关的操作对象                NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();//获取网络接口                if(networkInfo!= null && networkInfo.isConnected())                {                    Toast.makeText(MainActivity.this, "you 网络访问", Toast.LENGTH_SHORT).show();                    sendRequestWithHttpURLConnection();                }                else                    Toast.makeText(MainActivity.this, "无 网络访问", Toast.LENGTH_SHORT).show();            }        });    }

        对于HTTP函数,由于网络访问,是比较耗时的操作,所以开个线程慢慢的跑啊跑,不要影响到主线程的耗时,蓝后conection首先要做到就是对我们这次的URL尝试建立连接,然后设置你申请访问的时候的一些超时读取,超时请求的函数等,这些都在HttpURLConnection类中已经申明。然后用DataOutputStream 把我们在app中的输入citycode值,转为字节流传给网页,该网页会作为参数进行递交。后台会把这个参数和之前的URL结合一起组成一个有参数的URL访问。这样才是一个完整的connection。如果你单独访问URL会提示

缺少参数: theCityCode

        访问一个网页,正确建立连接时返回的request=200,假如报错,根据request的数值自己百度报错类型解决即可。用InputStream来获取返回的xml文件的字节流吧,(应该是)然后一顿操作变成BufferedReader ,用StringBuilder 读取每一行,再转为字符串来给我们操作= =,这里懵逼了。这边获取了字符串形式的xml文件,主要用于来更新我们APP的UI界面,所以通过Handler来进行,handler.sendEmptyMessage(1);传给消息给他,你可以理解为类似广播的性质,其实是一个对于handler里面一个队列的无限的loop,队列中一有东西进来,就会触发handler进行操作,所以实时的吧,最后吧连接断掉,开启线程。而我们获取到的xml文件,就通过toString赋值给一个公有变量String r,给 字符串r 重新赋值后,handler不用传字符串参数,直接就可以调用改变后的r。

private void sendRequestWithHttpURLConnection()    {        new Thread(new Runnable() {            @Override            public void run() {                HttpURLConnection connection=null;                try{                    Log.d("Tag","begin connectin");                    connection=(HttpURLConnection)((new URL(url).openConnection()));                    connection.setRequestMethod("POST");                    connection.setReadTimeout(8000);                    connection.setConnectTimeout(8000);                    String request=city.getText().toString();                    request= URLEncoder.encode(request,"utf-8");                    connection.connect();//发送Http请求,建立跟网页的连接                    DataOutputStream out=new DataOutputStream(connection.getOutputStream());                    out.writeBytes("theCityCode="+request+"&theUserID=ecefcf4c81b847a189ff94a159d54dd0");//theUserID是本人在那个网站申请的ID,暂时应该还可以用,out作为参数,连同URL一起,形成一个新的真正的url地址                    int back =connection.getResponseCode();                    Log.d("Tag","The response is"+back);                    InputStream in=connection.getInputStream();//获取http返回的xml文件的字节流                    BufferedReader reader=new BufferedReader(new InputStreamReader(in));//转为BufferedReader                     StringBuilder response=new StringBuilder();                    String line=new String();                    while((line=reader.readLine())!=null)//按行读取,存入StringBuilder                     {                        response.append(line);                    }                    Message message=new Message();                    //message.what=1;                    //message.obj=parseXMLWithPull(response.toString());                    handler.sendEmptyMessage(1);                    r=new String();                    r=response.toString();//r是一个公有有成员,相当于全局变量                    Log.d("Tag",response.toString());                }                catch (Exception e)                {                    e.printStackTrace();                    Log.d("Tag","err");                }                finally {                        connection.disconnect();                }            }        }).start();    }

        handler函数,就是接收到一个meeage后根据他是什么来选择操作类型,然后就是根据你电脑去访问,看看他的xml格式,按照格式,用你java学到的一系列字符串数组的方法来进行分割,提取想要的在界面中显示。
        这里面有一个parseXMLWithPull函数,就是用来提取xml文件里的每个标签的之间的内容然后都扔到一个 ArrayList list=new ArrayList();里面。先要什么就去list里面提取就行,当然也可以用一个map设置,存的时候就处理好key-value,提取的时候就会比较简单,这边我写好了,也就不想改了 T T;然后你就把get到的字符串setText到你的view控件上就ok了。
listview其实也是根据你读到的String,来放到适配器里,动动咱们的小脑瓜应该挺简单的。
然后对于recyclerview的adapter,课件中有给出对应类的样例代码WeatherAdapter的class,我们只需要把那个类中存recyclerview的数据的容器,改为我们之前代码中用到的ArrayList

    private Handler handler=new Handler()    {        public void handleMessage(Message message){            Log.d("Tag","handle begin");            switch(message.what)            {                case 1:                {                    String a=r;                    Log.d("Tag","String a "+r);                    parseXMLWithPull(r);                    String t=list.get(0).toString();                    cityout.setText(t);                    t=list.get(3).toString();                    update.setText(t+" 更新");                    t=list.get(4).toString();                    String son= t.substring(7);                    String[] cut=son.split(";");                    fengli.setText(cut[1]);                    shidu.setText(cut[2]);                    wendu.setText(cut[0]);                    //Log.d("Tag","arraylist  "+son);                    t=list.get(13);                    bodong.setText(t);                    t=list.get(5);                    cut=t.split("。");                    zhiliang.setText(cut[1]);                    t=list.get(6);                    cut=t.split("。");                    List<Map<String, Object>> dataa=  new ArrayList<>();                    simpleAdapter=new SimpleAdapter(MainActivity.this,dataa,R.layout.item,new String[]{"name"},new int[]{R.id.name});                    for(int i=0;i<cut.length;i++)                    {                        Map<String, Object> temp = new LinkedHashMap<>();                        temp.put("name",cut[i]);                        dataa.add(temp);                    }                    listview.setAdapter(simpleAdapter);                      ArrayList<Map<String,String>>  weather_list=new ArrayList<Map<String,String>>();                    ArrayList<String> list2=new ArrayList<String>();                    for(int i=0;i<7;i++)                    {                        String tt=list.get(7+5*i)+" "+list.get(8+5*i);                        Log.d("Tag","tt : "+tt);                        cut=tt.split(" ");                        Map<String, String> temp = new LinkedHashMap<>();                        temp.put("date",cut[0].toString());temp.put("weather",cut[1].toString());temp.put("fromto",cut[2].toString());                        weather_list.add(temp);                    }                    WeatherAdapter adapter=new WeatherAdapter(MainActivity.this,weather_list);                    recyclerview.setAdapter(adapter);                    break;                }            }        }    };

        说一下parseXMLWithPull函数吧。对于我们现在一个字符串形式表示的xml文件内容,先用函数转为XmlPullParser 对象实例,然后XmlPullParser 里面有现成的函数调用,会根据标签来一个个读入parser.getEventType();就是读取标签类型,在后面的类中的文件都有申明,有兴趣alt+函数名,自己可以一级一级跳下去看。每次判断标签,我们这次只要标签名为string的具体内容。每次获取后,都add到 list 里面。所以我们申请访问的网页最好具有一定的格式,这样我们的代码针对这个网站才具有普遍性。否则,每次都需要修改我们对字符串处理代码。

 private  void parseXMLWithPull(String xmlData){        try{            Log.d("TAG", "parseXMLWithPull: begin");            XmlPullParserFactory factory=XmlPullParserFactory.newInstance();            XmlPullParser parser=factory.newPullParser();            parser.setInput(new StringReader(xmlData));            int eventType=parser.getEventType();            list=new ArrayList<String>();            //Log.d("Tag","eventType"+eventType);            while(eventType!=XmlPullParser.END_DOCUMENT){            switch (eventType)            {                case XmlPullParser.START_TAG:                    if("string".equals(parser.getName())){                        String str=parser.nextText();                        list.add(str);                        //Log.d("Tag","Get String "+str);                    }                    break;                case XmlPullParser.END_TAG:                    break;                default:break;            }                eventType=parser.next();                //Log.d("Tag","eventType"+eventType);            }        }        catch (Exception e)        {            Log.d("Tag ","ERR "+e);        }    }

(2)实验遇到困难以及解决思路

    一个就是导入recyclerview的jar包的时候,一开始,只是简单的复制到文件夹中,没有Add As Library.    还有就是在connection和DataOutputStream的时候有点乱,按字面意思是connection,已经建立连接了,但是还缺少参数citycode 和userID,所以DataOutputStream设置好后,应该吧参数一同跟之前的URL结合在一起生成一个正确的由内容的URL。后来经过试验,似乎是在DataOutputStream后getResponseCode才会建立连接,没有DataOutputStream,返回的getResponseCode是500报错

四、 课后实验结果

主界面

默认城市搜索

输入城市名搜索

五、 实验思考及感想

    网络访问,其实最关键的就是跟URL地址建立连接,然后设置编码类型,来通过返回值,类型转换,获取该网页可读的xml文件内容,通过读别人的xml文件,也给我们一个启示就是,我们自己以后在写网页的时候,同类型的网页也要尽量写成固定格式,方便解析,有一定的通性,然后对于recyclerview,百度了一些,似乎是一个功能很丰富的listview,说到底,大致功能跟listview类似,但更强大,多样,当特定需要的时候,去百度以下资料,应用应该不难。
0 0
原创粉丝点击