Android网络应用——疯狂android讲义笔记

    • 基于TCP协议的网络通信
      • TCP协议基础
      • 使用ServerSocket创建TCP服务器端
      • 使用Socket进行通信
      • 加入多线程
    • 使用URL访问网络资源
      • 使用URL读取网络资源
      • 使用URLConnection提交请求
    • 使用HTTP访问网络
      • HttpURLConnection类
      • 使用Apache HttpClient类
    • 使用webview视图显示网页
      • 使用webvie浏览网页
      • 用webview加载html代码
      • 使用webview中的javaScript调用android方法
    • 使用web service进行网络编程
      • web service平台概述
        • SOAP简单对象访问协议
        • WSDLWeb Service描述语言
        • UDDI统一描述发现和整合协议
      • 使用android应用调用Web Service

太简略,有些过时了,算一个简单总结吧,后面分开来分析。

基于TCP协议的网络通信

tcp/ip通信协议:可靠的网络协议,通信两端各建立一个Socket,在两端之间形成网络虚拟链路进行通信。java使用Socket对象来代表两端的通信接口,并通过Socket产生I/O流来进行网络通信。

TCP协议基础

IP协议(Internet Protocol):通过IP协议,使Internet成为一个允许连接不同类型的计算机和不同操作系统的网络。 

IP协议只保证计算机能发送和接收分组数据,负责将一个主机传送到另一个主机。消息在传送过程中被分割成一个个小包。

计算机通过安装IP软件,保证之间的收发数据,但是IP协议还不能解决数据分组在传输过程中可能出现的问题。SO,to slove,还需要安装TCP协议来提供可靠并且无差错的通信服务。

TCP协议被称为一种端对端协议。TCP协议收集信息包,并将其按照适当的序放好传送,在接收端收到后再将其正确的还原。保证了数据包在传输中的准确无误。使用重发机制(发送,等待对方的确认,没有确认?重发);

==》so,虽然IP TCP两个协议功能不尽相同,也可分开单独使用,但TCP/IP两者结合,才能保证INTERNET在复杂环境下正常运行,功能上也互补。

使用ServerSocket创建TCP服务器端

java中用来接收其他通信实体连接请求的类是ServerSocket,ServerSocket对象用来监听来自客户端的Socket连接,if no 连接,则一直处于等待状态。ServerSocket包含了一个监听来自客户端连接请求的方法。

==》Socket accept()如果接收到一个客户端Socket的连接请求,该方法将会返回一个与连接客户端Socker对应的Socket。否则该方法将一直处于等待状态,线程也被阻塞。
==》创建ServerSocket对象的几个构造器
  • ServerSocket(int port):用指定端口port来创建一个ServerSocket。有效端口整数值:0~65535.
    ==》通常推荐使用1024以上端口,避免与其他应用程序的通用端口冲突。
  • ServerSocket(int port, int backlog):增加一个用来改变连接队列长度的参数。
  • ServerSocket(int port,int backlog,inetAdress localAddr)在机器存在多个IP地址的情况下,允许通过localAddr这个参数来指定将ServerSocket绑定到指定的IP地址。

    ==》注意:当ServerSocket使用完毕后,应使用ServerSocket的close()方法来关闭该ServerSocket。usually,服务器不该只接收一个客户端请求,而应该不断地接收来自客户端的所有请求==》so,java程序通常会通过循环不断的调用ServerSocket的accept()方法。

//创建一个ServerSocket,用于监听客户端Socket的连接请求
ServerSocket ss = new ServerSocket(3000);
//采用循环不断接收来自客户端的请求
while(true){
    //每当接收到客户端Socket的请求,服务器端也对应产生一个Socket
    Socket s = ss.accept();
    //下面就可以使用Socket进行通信了
    ...
}
==》手机上网IP由移动运营公司动态分配,不固定,SO,很少在手机上运行服务器端,一般服务器端运行在有固定IP的服务器上。

使用Socket进行通信

==》使用Socket的构造器来连接到指定服务器。
  • Socket(InetAddress/String remoteAddress, int port)
    ==>创建连接到指定远程主机、远程端口的Socket。该构造器没有指定本地地址和端口,默认使用本地主机的默认IP地址,默认使用系统动态指定的IP地址。
  • Socket(InetAddress/String remoteAddress, int port, InetAddress localAddr, int localPort):适用于本地主机有多个IP地址的情形。

    ==》Socket提供如下两个方法来获取输入流和输出流。

  • InputStream getInputStream():返回该Socket对象对应的输入流,让程序通过该输入流从Socket中取出数据。

  • OutputStream getOutputStream():返回该Socket对象对应的输出流,让程序通过该输出流向Socket中输出数据。
    Android网络应用——疯狂android讲义笔记_第1张图片

    ==》注意:上面没把OutputStream流包装成PrintStream,然后使用PrintStream直接输出整个字符串,是因为服务器端程序运行在window主机上,直接使用PrintStream输出字符串默认使用系统平台字符串(默认GBK)进行编码;客户端android应用,在linux平台,客户端读取网络数据默认使用utf-8。这样会引起乱码,所以手动控制字符串编码,强行指定使用utf-8字符集进行编码。
    Android网络应用——疯狂android讲义笔记_第2张图片

==》将网络连接建立在新线程中,android不允许在UI线程中建立网络连接。下面代码增加了访问网络权限,因为应用需要联网。


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

==》注意:上面的代码没有增加异常处理等内容。

  • 使用Socket进行读、写操作进行超时监听
s.setSoTimeout(10000);

如果Socket读写超时,抛出SocketTimeoutException异常,程序可以进行捕捉,并进行适当的处理。

try{
    //使用Scanner来读取网络输入流中的数据
    Scanner scan = new Scanner(s.getInputStream())
    //
    String line = scan.nextLine();
    ...
}
//捕捉SocketTimeoutException异常
catch(SocketTimeoutException ex){
    //对异常进行处理
    ...
}
  • Socket连接服务器时指定超时时长
    ==》Socket的构造参数里未指定超时时长的参数,因为创建一个无连接的Socket,再调用Socket的connect()方法来连接远程服务器,该方法可以接受一个超时时长参数。
Socket s = new Socket();
s.connect(new InetAddress(host, port),10000);

加入多线程

==》当使用传统BufferedReader的readLine()方法读取数据时,在该方法成功返回之前,线程被阻塞,程序无法继续执行,所以,服务器应该为每个Socket单独启动一条线成,每条线程负责与一个客户端进行通信。

import java.net.*;
import java.io.*;
import java.util.*;

public class MyServer
{
    // 定义保存所有Socket的ArrayList
    public static ArrayList socketList
        = new ArrayList();
    public static void main(String[] args)
        throws IOException
    {
        ServerSocket ss = new ServerSocket(30000);
        while(true)
        {
            // 此行代码会阻塞,将一直等待别人的连接
            Socket s = ss.accept();
            socketList.add(s);
            // 每当客户端连接后启动一条ServerThread线程为该客户端服务
            new Thread(new ServerThread(s)).start();
        }
    }
}
import java.io.*;
import java.net.*;
import java.util.*;

// 负责处理每个线程通信的线程类
public class ServerThread implements Runnable
{
    // 定义当前线程所处理的Socket
    Socket s = null;
    // 该线程所处理的Socket所对应的输入流
    BufferedReader br = null;
    public ServerThread(Socket s)
        throws IOException
    {
        this.s = s;
        // 初始化该Socket对应的输入流
        br = new BufferedReader(new InputStreamReader(
            s.getInputStream() , "utf-8"));   //②
    }
    public void run()
    {
        try
        {
            String content = null;
            // 采用循环不断从Socket中读取客户端发送过来的数据
            while ((content = readFromClient()) != null)
            {
                // 遍历socketList中的每个Socket,
                // 将读到的内容向每个Socket发送一次
                for (Socket s : MyServer.socketList)
                {
                    OutputStream os = s.getOutputStream();
                    os.write((content + "\n").getBytes("utf-8"));
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
    // 定义读取客户端数据的方法
    private String readFromClient()
    {
        try
        {
            return br.readLine();
        }
        // 如果捕捉到异常,表明该Socket对应的客户端已经关闭
        catch (IOException e)
        {
            // 删除该Socket。
            MyServer.socketList.remove(s);    //①
        }
        return null;
    }
}

==》客户端

handler = new Handler() //①
        {
            @Override
            public void handleMessage(Message msg)
            {
                // 如果消息来自于子线程
                if (msg.what == 0x123)
                {
                    // 将读取的内容追加显示在文本框中
                    show.append("\n" + msg.obj.toString());
                }
            }
        };
        clientThread = new ClientThread(handler);
        // 客户端启动ClientThread线程创建网络连接、读取来自服务器的数据
        new Thread(clientThread).start(); //①
        send.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                try
                {
                    // 当用户按下发送按钮后,将用户输入的数据封装成Message,
                    // 然后发送给子线程的Handler
                    Message msg = new Message();
                    msg.what = 0x345;
                    msg.obj = input.getText().toString();
                    clientThread.revHandler.sendMessage(msg);
                    // 清空input文本框
                    input.setText("");
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
public class ClientThread implements Runnable
{
    private Socket s;
    // 定义向UI线程发送消息的Handler对象
    private Handler handler;
    // 定义接收UI线程的消息的Handler对象
    public Handler revHandler;
    // 该线程所处理的Socket所对应的输入流
    BufferedReader br = null;
    OutputStream os = null;

    public ClientThread(Handler handler)
    {
        this.handler = handler;
    }

    public void run()
    {
        try
        {
            s = new Socket("192.168.1.88", 30000);
            br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
            os = s.getOutputStream();
            // 启动一条子线程来读取服务器响应的数据
            new Thread()
            {
                @Override
                public void run()
                {
                    String content = null;
                    // 不断读取Socket输入流中的内容。
                    try
                    {
                        while ((content = br.readLine()) != null)
                        {
                            // 每当读到来自服务器的数据之后,发送消息通知程序界面显示该数据
                            Message msg = new Message();
                            msg.what = 0x123;
                            msg.obj = content;
                            handler.sendMessage(msg);
                        }
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }
            }.start();
            // 为当前线程初始化Looper
            Looper.prepare();
            // 创建revHandler对象
            revHandler = new Handler()
            {
                @Override
                public void handleMessage(Message msg)
                {
                    // 接收到UI线程中用户输入的数据
                    if (msg.what == 0x345)
                    {
                        // 将用户在文本框内输入的内容写入网络
                        try
                        {
                            os.write((msg.obj.toString() + "\r\n")
                                .getBytes("utf-8"));
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            };
            // 启动Looper
            Looper.loop();
        }
        catch (SocketTimeoutException e1)
        {
            System.out.println("网络连接超时!!");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

使用URL访问网络资源

统一资源定位符。通常,可以由协议名、主机、端口和资源组成。

格式:protocol://host:port/resourceName

==>JDK还提供了一个URI(Uniform Resource Identifiers)类,实例代表一个统一资源标识符。URIF不能用于定位任何资源,唯一作用就是解析。URL则包含一个可打开到达该资源的输入流。So,可以将URL理解成URI的特例。
URL类提供了多个构造器用于创建URL对象。一旦获得智慧,可以调用如下常用方法来访问该URL对应的资源。
![这里写图片描述](https://img-blog.csdn.net/20160509162953746)
![这里写图片描述](https://img-blog.csdn.net/20160509163006090)

使用URL读取网络资源

URL对象提供的openStream()可以读取该URL资源的InputStream,通过该方法可以非常方便地读取远程资源。
new Thread()
        {
            public void run()
            {
                try
                {
                    // 定义一个URL对象
                    URL url = new URL("http://www.crazyit.org/"
                        + "attachments/month_1008/20100812_7763e970f"
                        + "822325bfb019ELQVym8tW3A.png");
                    // 打开该URL对应的资源的输入流
                    InputStream is = url.openStream();
                    // 从InputStream中解析出图片
                    bitmap = BitmapFactory.decodeStream(is);
                    // 发送消息、通知UI组件显示该图片
                    handler.sendEmptyMessage(0x123);
                    is.close();
                    // 再次打开URL对应的资源的输入流
                    is = url.openStream();
                    // 打开手机文件对应的输出流
                    OutputStream os = openFileOutput("crazyit.png"
                        , MODE_WORLD_READABLE);
                    byte[] buff = new byte[1024];
                    int hasRead = 0;
                    // 将URL对应的资源下载到本地
                    while((hasRead = is.read(buff)) > 0)
                    {
                        os.write(buff, 0 , hasRead);
                    }
                    is.close();
                    os.close();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }.start();

使用URLConnection提交请求

URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和URL之间的通信连接。程序可以通过URLConnection实例向该URL发送请求,读取URL引用的资源。

Android网络应用——疯狂android讲义笔记_第3张图片
Android网络应用——疯狂android讲义笔记_第4张图片
Android网络应用——疯狂android讲义笔记_第5张图片

如果需要发送GET请求,只要调用URLConnection的connect()方法去建立实际的连接即可,如果需要发送POST请求,则需要获取URLConnection的OutputStream,然后再向网络中输出请求参数。
/**
     * 向指定URL发送GET方法的请求
     * @param url 发送请求的URL
     * @param params 请求参数,请求参数应该是name1=value1&name2=value2的形式。
     * @return URL所代表远程资源的响应
     */
    public static String sendGet(String url, String params)
    {
        String result = "";
        BufferedReader in = null;
        try
        {
            String urlName = url + "?" + params;
            URL realUrl = new URL(urlName);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            // 建立实际的连接
            conn.connect();  //①
            // 获取所有响应头字段
            Map> map = conn.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet())
            {
                System.out.println(key + "--->" + map.get(key));
            }
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null)
            {
                result += "\n" + line;
            }
        }
        catch (Exception e)
        {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally
        {
            try
            {
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
        return result;
    }
/**
     * 向指定URL发送POST方法的请求
     * @param url 发送请求的URL
     * @param params 请求参数,请求参数应该是name1=value1&name2=value2的形式。
     * @return URL所代表远程资源的响应
     */
    public static String sendPost(String url, String params)
    {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try
        {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(params);  //②
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null)
            {
                result += "\n" + line;
            }
        }
        catch (Exception e)
        {
            System.out.println("发送POST请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输出流、输入流
        finally
        {
            try
            {
                if (out != null)
                {
                    out.close();
                }
                if (in != null)
                {
                    in.close();
                }
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
        return result;
    }

使用HTTP访问网络

HttpURLConnection类

==》主要HttpURLConnection类,是URLConnection子类,在URLConnection的基础上做了改进,更方便进行HTTP资源操作。

Android网络应用——疯狂android讲义笔记_第6张图片
Android网络应用——疯狂android讲义笔记_第7张图片

public class DownUtil
{
    // 定义下载资源的路径
    private String path;
    // 指定所下载的文件的保存位置
    private String targetFile;
    // 定义需要使用多少线程下载资源
    private int threadNum;
    // 定义下载的线程对象
    private DownThread[] threads;
    // 定义下载的文件的总大小
    private int fileSize;

    public DownUtil(String path, String targetFile, int threadNum)
    {
        this.path = path;
        this.threadNum = threadNum;
        // 初始化threads数组
        threads = new DownThread[threadNum];
        this.targetFile = targetFile;
    }

    public void download() throws Exception
    {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setRequestMethod("GET");
        conn.setRequestProperty(
            "Accept",
            "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
            + "application/x-shockwave-flash, application/xaml+xml, "
            + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
            + "application/x-ms-application, application/vnd.ms-excel, "
            + "application/vnd.ms-powerpoint, application/msword, */*");
        conn.setRequestProperty("Accept-Language", "zh-CN");
        conn.setRequestProperty("Charset", "UTF-8");
        conn.setRequestProperty("Connection", "Keep-Alive");
        // 得到文件大小
        fileSize = conn.getContentLength();
        conn.disconnect();
        int currentPartSize = fileSize / threadNum + 1;
        RandomAccessFile file = new RandomAccessFile(targetFile, "rw");
        // 设置本地文件的大小
        file.setLength(fileSize);
        file.close();
        for (int i = 0; i < threadNum; i++)
        {
            // 计算每条线程的下载的开始位置
            int startPos = i * currentPartSize;
            // 每个线程使用一个RandomAccessFile进行下载
            RandomAccessFile currentPart = new RandomAccessFile(targetFile,
                "rw");
            // 定位该线程的下载位置
            currentPart.seek(startPos);
            // 创建下载线程
            threads[i] = new DownThread(startPos, currentPartSize,
                currentPart);
            // 启动下载线程
            threads[i].start();
        }
    }

    // 获取下载的完成百分比
    public double getCompleteRate()
    {
        // 统计多条线程已经下载的总大小
        int sumSize = 0;
        for (int i = 0; i < threadNum; i++)
        {
            sumSize += threads[i].length;
        }
        // 返回已经完成的百分比
        return sumSize * 1.0 / fileSize;
    }

    private class DownThread extends Thread
    {
        // 当前线程的下载位置
        private int startPos;
        // 定义当前线程负责下载的文件大小
        private int currentPartSize;
        // 当前线程需要下载的文件块
        private RandomAccessFile currentPart;
        // 定义已经该线程已下载的字节数
        public int length;

        public DownThread(int startPos, int currentPartSize,
            RandomAccessFile currentPart)
        {
            this.startPos = startPos;
            this.currentPartSize = currentPartSize;
            this.currentPart = currentPart;
        }

        @Override
        public void run()
        {
            try
            {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection)url
                    .openConnection();
                conn.setConnectTimeout(5 * 1000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty(
                    "Accept",
                    "image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
                    + "application/x-shockwave-flash, application/xaml+xml, "
                    + "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
                    + "application/x-ms-application, application/vnd.ms-excel, "
                    + "application/vnd.ms-powerpoint, application/msword, */*");
                conn.setRequestProperty("Accept-Language", "zh-CN");
                conn.setRequestProperty("Charset", "UTF-8");
                InputStream inStream = conn.getInputStream();
                // 跳过startPos个字节,表明该线程只下载自己负责哪部分文件。
                inStream.skip(this.startPos);
                byte[] buffer = new byte[1024];
                int hasRead = 0;
                // 读取网络数据,并写入本地文件
                while (length < currentPartSize
                    && (hasRead = inStream.read(buffer)) > 0)
                {
                    currentPart.write(buffer, 0, hasRead);
                    // 累计该线程下载的总大小
                    length += hasRead;
                }
                currentPart.close();
                inStream.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}

字节跳过已经失效。

使用Apache HttpClient类

==>一般情况下,如果只需要向web站点的某个简单页面提交请求并获取服务器响应,完全可以使用前面介绍的HttpURLConnection.为了更好的处理向Web站点请求,包括处理Session、Cookie的处理等细节问题,Apache开源组织提供了一个HttpClient。它是一个简单的HTTP客户端(非浏览器),用于发生和接收HTTP响应。但不会缓存服务器的响应,不能执行HTML页面中嵌入的JavaScript代码,也不会对页面内容进行任何解析,处理。
==》总的来说,HttpClient就是增强版的HttpURLConnection,HttpURLConnection能做的它都能做,HttpURLConnection没提供的有些功能,它也提供了,但它只关注如何发送请求,接收响应以及管理HTTP连接。
==》android已经成功地集成了HttpClient。
![这里写图片描述](https://img-blog.csdn.net/20160510111823787)
==》通过HttpClient来访问被保护页面,程序需要用HttpClient来登陆系统,只要应用程序使用同一个HttpClient发送请求,HttpClient会自动维护与服务器之间的Session状态。

关于get方式

new Thread()
        {
            @Override
            public void run()
            {
                // 创建一个HttpGet对象
                HttpGet get = new HttpGet(
                    "http://192.168.1.88:8888/foo/secret.jsp");  //①
                try
                {
                    // 发送GET请求
                    HttpResponse httpResponse = httpClient.execute(get);//②
                    HttpEntity entity = httpResponse.getEntity();
                    if (entity != null)
                    {
                        // 读取服务器响应
                        BufferedReader br = new BufferedReader(
                            new InputStreamReader(entity.getContent()));
                        String line = null;

                        while ((line = br.readLine()) != null)
                        {
                            Message msg = new Message();
                            msg.what = 0x123;
                            msg.obj = line;
                            handler.sendMessage(msg);
                        }
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        }.start();
    }

关于post方式

new Thread()
                    {
                        @Override
                        public void run()
                        {
                            try
                            {
                                HttpPost post = new HttpPost("http://192.168"
                                    + ".1.88:8888/foo/login.jsp");//③
                                // 如果传递参数个数比较多的话可以对传递的参数进行封装
                                List params = new
                                    ArrayList();
                                params.add(new BasicNameValuePair
                                    ("name", name));
                                params.add(new BasicNameValuePair
                                    ("pass", pass));                                
                                // 设置请求参数
                                post.setEntity(new UrlEncodedFormEntity(
                                    params, HTTP.UTF_8));
                                // 发送POST请求
                                HttpResponse response = httpClient
                                    .execute(post);  //④
                                // 如果服务器成功地返回响应
                                if (response.getStatusLine()
                                    .getStatusCode() == 200)
                                {
                                    String msg = EntityUtils
                                        .toString(response.getEntity());
                                    Looper.prepare();
                                    // 提示登录成功
                                    Toast.makeText(HttpClientTest.this,
                                        msg, Toast.LENGTH_SHORT).show();
                                    Looper.loop();
                                }
                            }
                            catch (Exception e)
                            {
                                e.printStackTrace();
                            }
                        }
                    }.start();

自己之前项目里面用到的post方式。

    public boolean getPostString(String date,String refer_text) 
    {

        try
        {
            StringEntity entity = new StringEntity(date,"utf-8");
            HttpPost httpRequest = new HttpPost(HttpUrl);//HttpPost??????? 
            httpRequest.setEntity(entity);
            httpRequest.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko");
            httpRequest.addHeader("Content-Type", "application/x-www-form-urlencoded");
            httpRequest.addHeader("Referer", refer_text);
            HttpClient httpclient = new DefaultHttpClient();//???I???HttpClient
            HttpResponse httpResponse = httpclient.execute(httpRequest);//???HttpResponse 


            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (ClientProtocolException e)
        {
            System.out.println(e.getMessage());
        }
        catch (IOException e)
        {
                System.out.println(e.getMessage());
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }  
        return false;
    }


    public String getPost()
    {
        HttpGet httpRequest = new HttpGet(HttpUrl);
        try
        {  
            HttpClient httpclient = new DefaultHttpClient();//???HttpClient????
            HttpResponse httpResponse = httpclient.execute(httpRequest);//????HttpClient?????HttpResponse   
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
            {
                String strResult = EntityUtils.toString(httpResponse.getEntity());//??�?????????

                return strResult;
            }
            else
            {
                System.out.println(httpResponse.getStatusLine().getStatusCode());
                return null;
            }
        }
        catch (ClientProtocolException e)
        {
            System.out.println(e.getMessage());
        }
        catch (IOException e)
        {
                System.out.println(e.getMessage());
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }  
        return null;
    }

使用webview视图显示网页

webview本身就是一个浏览器实现,它的内核基于开源webkit引擎。

使用webvie浏览网页

Android网络应用——疯狂android讲义笔记_第8张图片

Android网络应用——疯狂android讲义笔记_第9张图片

默认的,点击系统“Back”键,整个Browser会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并屏蔽掉该Back事件。2.0以后版本中,不需要再使用onKeyDown(),直接重写onBackPressed 方法即可。
用webview做一个迷你的浏览器,实现效果变成会打开浏览器在百度里搜索你在文本框输入的网址。这是因为:默认情况下,点击webview中的链接,会使用Android系统自带的浏览器打开这个链接。如果希望点击链接继续在我们自己的Browser中响应,必须覆盖 webview的WebViewClient对象。
mWebView.setWebViewClient(new WebViewClient(){
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
    view.loadUrl(url);
    return true;
    }
}); 

如果webView中需要用户手动输入用户名、密码或其他,则webview必须设置支持获取手势焦点。方法如下:

webview.requestFocusFromTouch();

用webview加载html代码

前情:EditText不会对html标签进行任何解析,而是直接显示所有标签。==》直接解析html字符串,当初html页面来显示。
webview提供了一个loadData(...)方法,可用于加载并显示html代码。==》问题:如果包含中文html内容时,会显示乱码。
楼上的升级版:loadDataWithBaseURL(String baseUril, String data, String mimeType, String encoding, String historyUrl),不会产生乱码。
  • data:指定需要加载的HTML代码
  • mimeType:指定HTML代码的MIME类型,对于HTML代码可指定为text/html。
  • encoding:指定HTML代码编码所用的字符集。比如GBK等。

使用webview中的javaScript调用android方法

场景:webview加载的页面上带有javaScript脚本。(比如按钮点击打开提示框或者列表等)由于该按钮是HTML上的按钮,只能激发一段javaScript脚本,这就需要让javaScript脚本来调用android方法了。
实现:提供了配套的WebSettings工具类,该工具类提供了大量方法来管理webview的选项设置。
步骤:
  1. 调用WebView关联的WebSettings的setJavaScriptEnabled(true)启用JavaScript调用功能。
  2. 调用WebView的addJavaScriptInterface(Object object, String name)方法将object对象暴露给JavaScript。
  3. 在JavaScript脚本中通过刚才暴露的name对象调用android方法。
public class JsCallAndroid extends Activity 
{
    WebView myWebView;
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        myWebView = (WebView) findViewById(R.id.webview);
        // 此处为了简化编程,使用file协议加载本地assets目录下的HTML页面
        // 如果有需要,也可使用http协议加载远程网站的HTML页面。
        myWebView.loadUrl("file:///android_asset/test.html");
        // 获取WebView的设置对象
        WebSettings webSettings = myWebView.getSettings();
        // 开启JavaScript调用
        webSettings.setJavaScriptEnabled(true);
        // 将MyObject对象暴露给JavaScript脚本
        // 这样test.html页面中的JavaScript可以通过myObj来调用MyObject的方法
        myWebView.addJavascriptInterface(new MyObject(this), "myObj");
    }
}
public class MyObject
{
    Context mContext;

    MyObject(Context c)
    {
        mContext = c;
    }
    // 该方法将会暴露给JavaScript脚本调用
    public void showToast(String name)
    {
        Toast.makeText(mContext, name + ",您好!"
            , Toast.LENGTH_LONG).show();
    }
    // 该方法将会暴露给JavaScript脚本调用
    public void showList()
    {
        // 显示一个普通的列表对话框
        new AlertDialog.Builder(mContext)
            .setTitle("图书列表")
            .setIcon(R.drawable.ic_launcher)
            .setItems(new String[]{"疯狂Java讲义"
            , "疯狂Android讲义" , "轻量级Java EE企业应用实战"} , null)
            .setPositiveButton("确定", null)
            .create()
            .show();
    }
}

assets目录下的html文件


<html>
<head>
    <meta name="author" content="Yeeku.H.Lee(CrazyIt.org)" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title> Js调用Android title>
head>
<body>

<input type="button" value="打招呼" 
    onclick="myObj.showToast('孙悟空');" />
<input type="button" value="图书列表" 
    onclick="myObj.showList();" />  
body>
html>

使用web service进行网络编程

web service平台概述

web service平台主要涉及的技术有SOAP(Simple Object Access Protocol, 简单对象访问协议),WSDL(Web Service Description Language, Web Service 描述语言),UDDI(Universal Description, Description and Integration, 统一描述、发现和整合协议)。

SOAP简单对象访问协议

    一种具有扩展性的XML消息协议。SOAP允许一个应用程序向另一个应用程序发送XML消息(单路消息)。任何应用程序均可作为发送者或接收者。SOAP仅定义消息结构和消息处理的协议,与底层的传输协议独立。SO,SOAP协议能够通过HTTP,JMS或SMTP协议传输。
    ![这里写图片描述](https://img-blog.csdn.net/20160504164626645)

WSDL(Web Service描述语言)

使用XML描述Web Service,包括访问和使用Web Service所必须的信息,定义该Web Service的位置、功能以及如何通信等描述信息。
只要调用者能够获取Web Service对应的WSDL,就可以从中了解它提供的服务及如何让调用Web Service。WSDL文件清晰的定义了三个内容。
  • WHAT部分:用于定义Web Service所提供的方法,即Web Service能做些什么。由WSDL中的

UDDI(统一描述、发现和整合协议)

UDDI(Universal Description, Description and Integration, 统一描述、发现和整合协议)是一套信息注册规范。特点:基于Web、分布式。
UDDI包括一组允许企业向外注册Web Service、以使其他企业发现访问的实现标准。UDDI的核心组件是UDDI注册中心,使用XML文件来描述企业及其提供的Web Service。
Web Service使用者也通过UDDI注册中心查找、发现自己所需的服务,将自己绑定到指定的Web Service提供者,再根据该Web Service对应的WSDL文档来调用对方的服务。

使用android应用调用Web Service

google为android平台开发Web Service客户端提供了ksoap2-android项目,但是并未集成到android平台中。需要自行下载。
使用ksoap2-android调用Web Service操作的步骤:
  1. 创建HttpTransportSE对象,该对象用于调用Web Service操作。
  2. 创建SoapSerializationEnvelope对象。(它是HttpTransportSE调用Web Service时信息的载体。客户端需要传入的参数,需要通过SoapSerializationEnvelope对象的bodyOut属性传给服务器;服务器响应生成的SOAP消息也通过该对象的bodyIn属性来获取。)
  3. 创建SoapObject对象,创建该对象时需要传入所要调用Web Service的命名空间,Web Service方法名。
  4. 如果有参数需要传给Web Service服务器端,调用SoapObject对象的addProperty(String name, Object value)方法来设置参数。
  5. 调用SoapSerializationEnvelope的setOutputSoapObject()方法,或者直接对bodyOut属性赋值,将前两步创建的SoapObject对象设为SoapSerializationEnvelope的传出SOAP消息体。
  6. 调用对象的call()方法,并以SoapSerializationEnvelope作为参数调用远程Web Service.
  7. 调用完成后,访问SoapSerializationEnvelope对象的bodyIn属性。该属性返回一个SoapObject对象,代表了Web Service 返回的消息,解析该对象,即可获取返回值。

你可能感兴趣的:(Android网络应用——疯狂android讲义笔记)