zoukankan      html  css  js  c++  java
  • [转]大话企业级Android应用开发实战 文件下载

                          25  Android文件下载 

    25.1  Android文件单线程下载

    25.1.1  J2SE文件单线程下载

    1.J2SE从网络获取图片

    3)源码再现

    package com.sharpandroid.junitTest;

     

    import java.io.ByteArrayOutputStream;

    import java.io.File;

    import java.io.FileOutputStream;

    import java.io.InputStream;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import org.junit.Test;

     

    public class InternetTest {

        @Test

    public void getImage() throws Exception {

                          // 首先我们要得到请求的路径, 路径为我们想要得到的资源

    String urlpath = "http://i1.itc.cn/20100326/3b8_921a1797_

    8fb1_4551_b4a3_dad3746f53fb_0.jpg";

        URL url = new URL(urlpath);                // 建立URL类对象,抛异常

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    //得到urlConnection对象

        conn.setRequestMethod("GET");                        // 声明请求方式

        conn.setConnectTimeout(6 * 1000);                   // 设置链接超时

        if(conn.getResponseCode() == 200) {

            InputStream inputStream = conn.getInputStream();   

    // 得到服务端传回来数据,相对客户为输入流

            byte[] data = readInstream(inputStream);   // 得到数据

            File file = new File("sohu.jpg");             // 创建保存文件

            FileOutputStream outputStream = new FileOutputStream(file);

    // 创建一个文件的输出流

                outputStream.write(data);

    // 把所得的二进制数据全部写入到我们建好的文件中

                outputStream.close();                           // 关闭输出流

            }

        }

    2.J2SE从网络获取文本

    1)源码回现

    在InternetTest类中添加getHtml()方法,具体代码为:

    @Test

        public void getHtml() throws Exception {

                              // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

            String urlpath = "http://www.sohu.com";

            URL url = new URL(urlpath);                       // 建立URL类对象,抛异常

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    // 得到urlConnection对象

            conn.setRequestMethod("GET");                     // 声明请求方式

            conn.setConnectTimeout(6 * 1000);                // 设置链接超时

            if (conn.getResponseCode() == 200) {

                InputStream inputStream = conn.getInputStream();             

    //得到输入流

                byte[] data = readInstream(inputStream);    //得到数据

                 System.out.println(new String(data));      //将字节转换为字符串打印

    在控制台上

            }

        }

    3.J2SE从网络获取可执行文件

    从网络上获取可执行文件和获取图片很相似,在InternetTest类中添加getFile()方法,具体代码如下:

         @Test

        public void getFile() throws Exception {

                        // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

            String urlpath = "http://ftpcnc-js.pconline.com.cn/pub/download/

    201003/Fetion_3.6.1900.exe";

            URL url = new URL(urlpath);                // 建立URL类对象,抛异常

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            // 得到urlConnection对象

            conn.setRequestMethod("GET");                        // 声明请求方式

            conn.setConnectTimeout(6 * 1000);                   // 设置链接超时

            if (conn.getResponseCode() == 200) {

            InputStream inputStream = conn.getInputStream();   

            // 得到输入流

            byte[] data = readInstream(inputStream);          // 得到数据

            File file = new File("feixin.exe");               // 创建保存文件

            FileOutputStream outputStream = new FileOutputStream(file);

            // 创建一个文件的输出流

            outputStream.write(data);

            // 把我们所得的二进制数据全部写入到我们建好的文件中

            outputStream.close();                           // 关闭输出流

            }

        }

    25.1.2  Android客户端单线程下载

    1.Android客户端从网络获取文本

    2)源码再现

    第一步:编写res下values中的string.xml文件。

     <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="hello">Hello World, DataActivity!</string>

        <string name="app_name">从internet中获取数据</string>

        <string name="path">图片路径</string>

    <string name="button">获取图片</string>

    </resources>

    第二步:编写res下Layout中的main.xml文件。

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

    <TextView 

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/path"

        />

      <EditText

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text=" http://i1.itc.cn/20100326/3b8_921a1797_8fb1_4551_

    b4a3_dad3746f53fb_0.jpg "

        android:id="@+id/path"

      ></EditText>

      <Button

       android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/button"

        android:id="@+id/button"

      ></Button>

      <ImageView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:id="@+id/ImageView"

      ></ImageView>

    </LinearLayout>

    第三步:编写核心代码DataActivity.java。

    package com.sharpandroid.activity;

     

    import com.sharpandroid.net.utils.NetTool;

    import android.app.Activity;

    import android.content.Intent;

    import android.graphics.Bitmap;

    import android.graphics.BitmapFactory;

    import android.os.Bundle;

    import android.util.Log;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import
    android.widget.ImageView;

    import android.widget.Toast;

     

      public class DataActivity extends Activity {

        private static final String TAG ="DataActivity";

         private EditText imageEditText;

         private ImageView imageView;

        @Override

    public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

    imageEditText = (EditText) this.findViewById(R.id.path);

    //根据id得到EditText

    imageView = (ImageView) this.findViewById(R.id.ImageView);

    //根据 id得到imageView

     Button button =  (Button) this.findViewById(R.id.button);

    //根据id得到button

     button.setOnClickListener(new View.OnClickListener() {

    //给button添加一个单击事件

               

    @Override

    public void onClick(View v) {

    String path = imageEditText.getText().toString();//从imageEditText中取出

    路径

        try {

            byte [] data =NetTool.getImage(path);             //得到图片

            Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);

             imageView.setImageBitmap(bm);

        } catch (Exception e) {

             Log.i(TAG, e.getMessage());//有异常打印在控制台上

            Toast.makeText(DataActivity.this, "获取图片失败", 1).show();

            }

           }

    });

       }

    }    

    新建工具类NetTool.java。

    package com.sharpandroid.net.utils;

     

    import java.io.ByteArrayOutputStream;

    import java.io.InputStream;

    import java.net.HttpURLConnection;

    import java.net.URL;

    public class NetTool {

    public static byte[] getImage(String path) throws Exception {

                              // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

            URL url = new URL(path);                         // 建立URL类对象,抛

    异常

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 得到

    urlConnection对象

            conn.setRequestMethod("GET");                          // 声明请求方式

            conn.setConnectTimeout(6 * 1000);                      // 设置链接超时

            if (conn.getResponseCode() == 200) {

                InputStream inputStream = conn.getInputStream();  // 得到输入流

                  return readInstream(inputStream);              // 返回得到的数组

              }

            return null;//

        }

    // 读取流文件的内容

        public static byte[] readInstream(InputStream inputStream) throws

    Exception {

            ByteArrayOutputStream byteArrayOutputStream =

     new ByteArrayOutputStream();        // 创建ByteArrayOutputStream类

            byte[] buffer = new byte[1024];                         // 声明缓冲区

            int length = -1;// 定义读取默认的长度

             while ((length = inputStream.read(buffer)) != -1) {

                byteArrayOutputStream.write(buffer, 0, length);// 把缓存区中输

    出到内存中

            }

           

            byteArrayOutputStream.close();                           // 关闭输出流

            inputStream.close();// 关闭输入流

            return byteArrayOutputStream.toByteArray();// 返回这个输出流的字节数组

        }

     

    }

     

    2.Android客户端从网络获取文本

    1)实现流程

    第一步,新添加两个布局文件:gettext.xml和text.xml。

    gettext.xml中代码:

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout

      xmlns:android="http://schemas.android.com/apk/res/android"

      android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:orientation="vertical">

      <EditText android:id="@+id/text"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="http://www.sohu.com"

      ></EditText>

      <Button android:id="@+id/textbutton"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/textbutton"

      ></Button>

    </LinearLayout>

    text.xml中的代码:

     <?xml version="1.0" encoding="utf-8"?>

     <ScrollView

       xmlns:android="http://schemas.android.com/apk/res/android"

       android:layout_width=fill_parent"

       android:layout_height="fill_parent"

        android:orientation="vertical">

     

     <TextView android:layout_width="fill_parent"

      android:layout_height="wrap_content"

      android:id="@+id/sohu"/>

    </ScrollView>

    在main.xml文件中添加一个Button控件:

             <Button android:id="@+id/totextbutton"

               android:layout_width="wrap_content"

              android:layout_height="wrap_content"

              android:text="@string/toTextButton"

      ></Button>

    第二步:

    (1)在NetTool.java类中添加方法getHtml()。

        public static String getHtml(String path,String encoding) throws

    Exception {

                 URL url = new URL(path);          // 建立URL类对象,抛出异常

                HttpURLConnection conn = (HttpURLConnection)

    url.openConnection();                          // 得到urlConnection对象

                conn.setRequestMethod("GET");                 // 声明请求方式

                conn.setConnectTimeout(6 * 1000);            // 设置链接超时

                if (conn.getResponseCode() == 200) {

                    InputStream inputStream = conn.getInputStream();   

    // 得到输入流

                    byte[] data = readInstream(inputStream);   // 得到数据

                    return new String(data,encoding);

    //将字节转换为字符串打印在控制台上

          }

                return null;

    }

    (2)在DataActivity.java中添加totextbutton的单击事件。

    Button totextbutton = (Button) this.findViewById(R.id.totextbutton);

                totextbutton.setOnClickListener(new View.OnClickListener() {

                    @Override

                    public void onClick(View v) {

                        Intent intent = new Intent(DataActivity.this,

    SohuActivity.class);

                        startActivity(intent);

                        }

                });    

    (3)在com.sharpandroid.activity中,新建一个继承了android.app.Activity的SohuActivity.  java类。

    package com.sharpandroid.activity;

     

    import com.sharpandroid.net.utils.NetTool;

    import android.app.Activity;

    import android.os.Bundle;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.TextView;

    import android.widget.Toast;

     

     public class SohuActivity extends Activity {

        private static final String TAG ="GetTextActivity";

        private EditText editText;

        private Button textButton;

        private TextView textView;

          @Override

        protected void onCreate(Bundle savedInstanceState) {

            // TODO Auto-generated method stub

            super.onCreate(savedInstanceState);

            setContentView(R.layout.gettext);

            editText = (EditText) this.findViewById(R.id.text);

            textButton = (Button) this.findViewById(R.id.textbutton);

           

            textButton.setOnClickListener(new View.OnClickListener() {

               

                @Override

                public void onClick(View v) {

                   String path = editText.getText().toString();

                   try {

                    String html = NetTool.getHtml(path,"GBK");

                    setContentView(R.layout.text);

                    textView = (TextView)SohuActivity.this.findViewById

    (R.id.sohu);

                    textView.setText(html);

     

                    Toast.makeText(SohuActivity.this, "获取文本成功", Toast.

    LENGTH_LONG).show();

                } catch (Exception e) {

                     Toast.makeText(SohuActivity.this, "获取文本失败", Toast.

    LENGTH_LONG).show();

                    e.printStackTrace();

                }

                   

               

                }

            });

           

        }

    }

    25.2  Android文件多线程下载

    25.2.1  J2SE文件多线程下载

    源码再现:

    package junit.test;

    import java.io.InputStream;

    import java.io.RandomAccessFile;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import org.junit.Test;

     

    public class DownLoader {

     

        @Test

        public void download() throws Throwable{

            String filename ="qqGame.exe";

            String path="http://dl_dir.qq.com/minigamefile/QQGame2010Beta1

    Patch1_setup_web.EXE";

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            conn.setConnectTimeout(5*1000);

            conn.setRequestMethod("GET");

            int filelength = conn.getContentLength();  //获取下载文件的长度

            System.out.println(filelength);

           

            RandomAccessFile file = new RandomAccessFile(filename, "rw");

            file.setLength(filelength);                    //设置本地文件的长度

            file.close();

            conn.disconnect();

            int threadsize = 3;                             //线程数

            int threadlength=filelength % 3==0? filelength/3 : filelength/3+1;

    //每条线程下载的长度

            for(int i=0; i<threadsize ; i++){

                int startposition = i * threadlength;

    //计算每条线程应该从文件的什么位置开始下载

                RandomAccessFile threadfile = new RandomAccessFile(filename,"

    rw");

                threadfile.seek(startposition);//从文件的什么位置开始写入数据

                //启动3条线程分别从startposition指定的位置下载文件

                new DownLoadThread(i, path, startposition, threadfile, threadl

    ength).start();

            }

            int quit = System.in.read();

            while('q' != quit){        

                Thread.sleep(2*1000);

            }

        }

       

        private class DownLoadThread extends Thread{

            private int threadid;

            private int startposition;

            private RandomAccessFile threadfile;

            private int threadlength;

            private String path;

           

            public DownLoadThread(int threadid, String path, int startposition,

    RandomAccessFile threadfile, int threadlength) {

                this.threadid = threadid;

                this.startposition = startposition;

                this.threadfile = threadfile;

                this.threadlength = threadlength;

                this.path = path;

            }

     

            @Override

            public void run() {

                try {

                    URL url = new URL(path);

                    HttpURLConnection conn = (HttpURLConnection)url.openCon

    nection();

                    conn.setConnectTimeout(5*1000);

                    conn.setRequestMethod("GET");

                    conn.setRequestProperty("Range", "bytes="+startposi

    tion+ "-");

    //指定从文件的什么位置开始下载

                    InputStream inStream = conn.getInputStream();

                    byte[] buffer = new byte[1024];

                    int len = -1;

                    int length = 0;

                    while(length<threadlength && (len = inStream.read

    (buffer))!=-1){

                        threadfile.write(buffer, 0, len);

                        length += len;                         //累计下载的长度

                    }

                    threadfile.close();

                    inStream.close();

                    System.out.println("线程"+ (threadid+1)+ "已经下载完

    成");

                } catch (Exception e) {

                    System.out.println("线程"+ (threadid+1)+ "下载出错:"+ e);

                }

            }

        }

    }

     

    25.2.2  Android客户端断点、多线程下载

    1.准备阶段

    String.xml中的代码:

     <?xml version="1.0" encoding="utf-8"?>

    <resources>

      <string name="hello">Hello World, DownLoaderActivity!</string>

         <string name="app_name">多线程下载器</string>

         <string name="path">下载路径</string>

         <string name="button">下载</string>

         <string name="success">下载成功</string>

         <string name="fail">下载失败</string>

         <string name="sdcarderror">SDCard不存在或者写保护</string>

    </resources>

    Main.xml中的代码:

      <?xml version="1.0" encoding="utf-8" ?>

     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/

    android"

       android:orientation="vertical"

       android:layout_width="fill_parent"

       android:layout_height="fill_parent">

         <TextView android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="@string/path" />

        <EditText android:layout_width="fill_parent"

           android:layout_height="wrap_content"

    android:text="http://

    bj.itxiazai.com/soft/media/music/ITxiazai_ttpsetup_552.exe"android:id=

    "@+id/path" />

      <Button android:layout_width="wrap_content"

         android:layout_height="wrap_content"

         android:text="@string/button"

         android:id="@+id/button" />

      <ProgressBar android:layout_width="fill_parent"

         android:layout_height="18dip"

      style="?android:attr/progressBarStyleHorizontal"

         android:id="@+id/progressBar" />

      <TextView android:layout_width="fill_parent"

         android:layout_height="wrap_content"

         android:gravity="center"

         android:id="@+id/result" />

      </LinearLayout>

    2.数据库阶段

    1)完成activity中的代码,给button添加单击事件

    首先我们把我们页面上需要的控件都找出来。

         public class DownLoaderActivity extends Activity {

       

        private EditText pathText;

        private TextView resultView;

        private ProgressBar progressBar;

        private Button button;

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

           resultView =  (TextView) this.findViewById(R.id.result);

                                                           //文件的进度的信息

           button = (Button) this.findViewById(R.id.button);

                                                    //得到下载按钮

           progressBar =  (ProgressBar)this.findViewById(R.id.downloadbar);

                                                           //得到下载的进度条

           pathText = (EditText) this.findViewById(R.id.path);

                                                           //得到下载路径

          button.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                // TODO Auto-generated method stub

               

            }

        });

        }

    }

    2)在单击事件的onClick()方法中,下载文件并保存到SD卡中

    下面是在这个类中的代码:

    package com.sharpandroid.service;

     

    import android.content.Context;

    import android.database.sqlite.SQLiteDatabase;

    import android.database.sqlite.SQLiteOpenHelper;

     

    public class DBOpenHelper extends SQLiteOpenHelper {

        private static final String DBNAME = "sharpandroid.db";

        private static final int VERSION = 1;

       

        public DBOpenHelper(Context context) {

            super(context, DBNAME, null, VERSION);

        }

    创建表:

        @Override

        public void onCreate(SQLiteDatabase db) {

            db.execSQL("CREATE TABLE IF NOT EXISTS filedown (id integer primary

    key autoincrement, downpath varchar(100), threadid INTEGER, position

    INTEGER)");

        }

    对表的表本进行更新:

        @Override

        public void onUpgrade(SQLiteDatabase db, int oldVersion,int newVersion){

            db.execSQL("DROP TABLE IF EXISTS filedown");

            onCreate(db);

        }

    }

    大致:呵呵,还是不错的嘛!下面我来完成在工程中需要的对线程相关的业务操作。

    3)对各个线程的下载记录进行操作

    FileService.java

    import java.util.HashMap;

    import java.util.Map;

    import android.content.Context;

    import android.database.Cursor;

    import android.database.sqlite.SQLiteDatabase;

    /**

     * 业务bean

     *

     */

    public class FileService {

        private DBOpenHelper openHelper;

     

        public FileService(Context context) {

            openHelper = new DBOpenHelper(context);

        }

        /**

         * 获取线程最后下载位置

         * @param path

         * @return

         */

        public Map<Integer, Integer> getData(String path){

            SQLiteDatabase db = openHelper.getReadableDatabase();

            Cursor cursor = db.rawQuery("select threadid, position from

    filedown where downpath=?", new String[]{path});

            Map<Integer, Integer> data = new HashMap<Integer, Integer>();

            while(cursor.moveToNext()){

                data.put(cursor.getInt(0), cursor.getInt(1));

            }

            cursor.close();

            db.close();

            return data;

        }

        /**

         * 保存下载线程初始位置

         * @param path

         * @param map

         */

        public void save(String path,  Map<Integer, Integer> map){//int

    threadid, int position

            SQLiteDatabase db = openHelper.getWritableDatabase();

            db.beginTransaction();

            try{

                for(Map.Entry<Integer, Integer> entry : map.entrySet()){

                    db.execSQL("insert into filedown(downpath, threadid,

    position) values(?,?,?)",

                        new Object[]{path, entry.getKey(), entry.getValue()});

                }

                db.setTransactionSuccessful();

            }finally{

                db.endTransaction();

            }

            db.close();

        }

        /**

         * 实时更新线程的最后下载位置

         * @param path

         * @param map

         */

        public void update(String path, Map<Integer, Integer> map){

            SQLiteDatabase db = openHelper.getWritableDatabase();

            db.beginTransaction();

            try{

                for(Map.Entry<Integer, Integer> entry : map.entrySet()){

                    db.execSQL("update filedown set position=? where downpath=?

    and threadid=?",

                            new Object[]{entry.getValue(), path, entry.

    getKey()});

                }

                db.setTransactionSuccessful();

            }finally{

                db.endTransaction();

            }

            db.close();

        }

        /**

         * 当文件下载完成后,清掉该文件对应的下载记录

         * @param path

         */

        public void delete(String path){

            SQLiteDatabase db = openHelper.getWritableDatabase();

            db.execSQL("delete from filedown where downpath=?", new Object

    []{path});

            db.close();

        }

       

    }

    3.实现文件下载阶段

    新建com.sharpandroid.net.download包下FileDownloader.java类。

     

    package com.sharpandroid.net.download;

     

    import java.io.File;

    import java.io.RandomAccessFile;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import java.util.LinkedHashMap;

    import java.util.Map;

    import java.util.UUID;

    import java.util.concurrent.ConcurrentHashMap;

    import java.util.regex.Matcher;

    import java.util.regex.Pattern;

    import com.sharpandroid.service.FileService;

    import android.content.Context;

    import android.util.Log;

    /**

     * 文件下载器

     */

    public class FileDownloader {

        private Context context;

        private FileService fileService;

       

        private static final String TAG = "FileDownloader";

        /* 已下载文件大小 */

        private int downloadSize = 0;

        /* 原始文件大小 */

        private int fileSize = 0;

        /* 线程数 */

        private DownloadThread[] threads;

        /* 下载路径  */

        private URL url;

        /* 本地保存文件 */

        private File saveFile;

        /* 下载记录文件 */

        private File logFile;

        /* 缓存各线程最后下载的位置*/

        private Map<Integer, Integer> data = new ConcurrentHashMap<Integer,

    Integer>();

        /* 每条线程下载的大小 */

        private int block;

        private String downloadUrl;//下载路径

        /**

         * 获取线程数

         */

        public int getThreadSize() {

            return threads.length;

        }

        /**

         * 获取文件大小

         * @return

         */

        public int getFileSize() {

            return fileSize;

        }

        /**

         * 累计已下载大小

         * @param size

         */

        protected synchronized void append(int size) {

            downloadSize += size;

        }

        /**

         * 更新指定线程最后下载的位置

         * @param threadId 线程id

         * @param pos 最后下载的位置

         */

        protected void update(int threadId, int pos) {

            this.data.put(threadId, pos);

        }

        /**

         * 保存记录文件

         */

        protected synchronized void saveLogFile() {

            this.fileService.update(this.downloadUrl, this.data);

        }

    第三步,构造下载器。

        /**

         * 构建文件下载器

         * @param downloadUrl 下载路径

         * @param fileSaveDir 文件保存目录

         * @param threadNum 下载线程数

         */

        public FileDownloader(Context context,String downloadUrl,File fileSa

    veDir,int threadNum) {

            try {

                this.context = context;

                this.downloadUrl = downloadUrl;

                fileService = new FileService(context);

                this.url = new URL(downloadUrl);

                if(!fileSaveDir.exists()) fileSaveDir.mkdirs();

                this.threads = new DownloadThread[threadNum];              

                HttpURLConnection conn = (HttpURLConnection) url.openConn

    ection();

                conn.setConnectTimeout(6*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.m

    s-powerpoint,

    application/msword, */*");

                conn.setRequestProperty("Accept-Language", "zh-CN");

                conn.setRequestProperty("Referer", downloadUrl);

                conn.setRequestProperty("Charset", "UTF-8");

                conn.setRequestProperty("User-Agent","Mozilla/4.0

    (compatible;MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

    CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

                conn.setRequestProperty("Connection", "Keep-Alive");

                conn.connect();

                printResponseHeader(conn);        //打印返回服务器的响应数据

                if (conn.getResponseCode()==200) {

                    this.fileSize = conn.getContentLength();

    //根据响应获取文件大小

                    if (this.fileSize <= 0) throw new RuntimeException("无法

    获知文件大小");

                           

                    String filename = getFileName(conn);

                    this.saveFile = new File(fileSaveDir, filename);

    /* 保存文件 */

                    Map<Integer,Integer> logdata = fileService.getData

    (downloadUrl);

                    if(logdata.size()>0){

                        data.putAll(logdata);

                    }

                    this.block = this.fileSize / this.threads.length + 1;

                    if(this.data.size()==this.threads.length){

                        for (int i = 0; i < this.threads.length; i++) {

                            this.downloadSize += this.data.get(i+1)-(this.

    block * i);

                        }

                        print("已经下载的长度"+ this.downloadSize);

                    }              

                }else{

                    throw new RuntimeException("服务器响应错误 ");

                }

            } catch (Exception e) {

                print(e.toString());

                throw new RuntimeException("连接不到下载路径 ");

            }

        }

        

            /**

         * 获取文件名

         */

        private String getFileName(HttpURLConnection conn) {

            String filename = this.url.toString().substring(this.url.toString

    ().lastIndexOf('/') + 1);

            if(filename==null || "".equals(filename.trim())){

    //如果获取不到文件名称

                for (int i = 0;; i++) {

                    String mine = conn.getHeaderField(i);

                    if (mine == null) break;

                    if("content-disposition".equals(conn.getHeaderFieldKey

    (i).toLowerCase())){

                        Matcher m = Pattern.compile(".*filename=(.*)").

    matcher(mine.toLowerCase());

                        if(m.find()) return m.group(1);

                    }

                }

                filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名

            }

            return filename;

        }

    第四步,实现下载功能,并同时可以得到此时各个线程的下载数量。

        /**

         *  开始下载文件

         * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为

    null

         * @return 已下载文件大小

         * @throws Exception

         */

        public int download(DownloadProgressListener listener) throws

    Exception{

            try {          

                if(this.data.size() != this.threads.length){

                    this.data.clear();

                    for (int i = 0; i < this.threads.length; i++) {

                        this.data.put(i+1, this.block * i);

                    }

                }

                for (int i = 0; i < this.threads.length; i++) {

                    int downLength = this.data.get(i+1) - (this.block * i);

                    if(downLength < this.block && this.data.get(i+1)<this.

    fileSize){        //该线程未完成下载时,继续下载

                        RandomAccessFile randOut = new RandomAccessFile(this.

    saveFile, "rw");

                        if(this.fileSize>0) randOut.setLength(this.fileSize);

                        randOut.seek(this.data.get(i+1));

                        this.threads[i] = new DownloadThread(this, this.url,

    randOut, this.block, this.data.get(i+1), i+1);

                        this.threads[i].setPriority(7);

                        this.threads[i].start();

                    }else{

                        this.threads[i] = null;

                    }

                }

                this.fileService.save(this.downloadUrl, this.data);

                boolean notFinish = true;                    //下载未完成

                while (notFinish) {                 // 循环判断是否下载完毕

                    Thread.sleep(900);

                    notFinish = false;                       //假定下载完成

                    for (int i = 0; i < this.threads.length; i++){

                        if (this.threads[i] != null && !this.threads[i].

    isFinish()) {

                            notFinish = true;                 //下载没有完成

                            if(this.threads[i].getDownLength() == -1){

    //如果下载失败,再重新下载

                                RandomAccessFile randOut = new RandomAcc

    essFile(this.saveFile, "rw");

                                randOut.seek(this.data.get(i+1));

                                this.threads[i] = new DownloadThread(this,

    this.url, randOut, this.block, this.data.get(i+1), i+1);

                                this.threads[i].setPriority(7);

                                this.threads[i].start();

                            }

                        }

                    }              

                if(listener!=null) listener.onDownloadSize(this.downloadSize);

                }

                fileService.delete(this.downloadUrl);

            } catch (Exception e) {

                print(e.toString());

                throw new Exception("下载失败");

            }

            return this.downloadSize;

        }

        /**

         * 获取HTTP响应头字段

         * @param http

         * @return

         */

        public static Map<String, String> getHttpResponseHeader(HttpURLConne

    ction http) {

            Map<String, String> header = new LinkedHashMap<String, String>();

            for (int i = 0;; i++) {

                String mine = http.getHeaderField(i);

                                               //得到响应头的各个属性

                if (mine == null) break;

                header.put(http.getHeaderFieldKey(i), mine);

                                                  //得到各个属性值

            }

            return header;

        }

        /**

         * 打印HTTP头字段

         * @param http

         */

        public static void printResponseHeader(HttpURLConnection http){

            Map<String, String> header = getHttpResponseHeader(http);

            for(Map.Entry<String, String> entry : header.entrySet()){

                String key = entry.getKey()!=null ? entry.getKey()+":" : "";

                print(key+ entry.getValue());

            }

        }

     

        private static void print(String msg){

            Log.i(TAG, msg);

        }

    }

    编写DownloadThread.java:

    package com.sharpandroid.net.download;

     

    import java.io.InputStream;

    import java.io.RandomAccessFile;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import android.util.Log;

     

    public class DownloadThread extends Thread {

        private static final String TAG = "DownloadThread";

        private RandomAccessFile saveFile;

        private URL downUrl;

        private int block;

        /* 下载开始位置  */

        private int threadId = -1;

        private int startPos;

        private int downLength;

        private boolean finish = false;

        private FileDownloader downloader;

     

        public DownloadThread(FileDownloader downloader, URL downUrl,

    RandomAccessFile saveFile, int block, int startPos, int threadId) {

            this.downUrl = downUrl;

            this.saveFile = saveFile;

            this.block = block;

            this.startPos = startPos;

            this.downloader = downloader;

            this.threadId = threadId;

            this.downLength = startPos - (block * (threadId - 1));

        }

       

        @Override

        public void run() {

            if(downLength < block){//未下载完成

                try {

                    HttpURLConnection http = (HttpURLConnection) downUrl.

    openConnection();

                    http.setRequestMethod("GET");

                    http.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,applica

    tion/vnd.ms-powerpoint, application/msword, */*");

                    http.setRequestProperty("Accept-Language", "zh-CN");

                    http.setRequestProperty("Referer", downUrl.toString());

                    http.setRequestProperty("Charset", "UTF-8");

                    http.setRequestProperty("Range", "bytes=" + this.

    startPos + "-");

                    http.setRequestProperty("User-Agent", "Mozilla/4.0

    (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

    CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

                    http.setRequestProperty("Connection", "Keep-Alive");

                   

                    InputStream inStream = http.getInputStream();

                    int max = block>1024 ? 1024 : (block>10 ? 10 : 1);

                    byte[] buffer = new byte[max];

                    int offset = 0;

                    print("线程 " + this.threadId + "从位置"+ this.startPos+

    "开始下载 ");

                    while(downLength < block && (offset=inStream.read(buffer,0,

    max)) != -1) {

                        saveFile.write(buffer, 0, offset);

                        downLength += offset;

                        downloader.update(this.threadId, block * (threadId –

    1) + downLength);

                        downloader.saveLogFile();

                        downloader.append(offset);

                        int spare = block-downLength;//求剩下的字节数

                        if(spare < max) max = (int) spare;

                    }

                    saveFile.close();

                    inStream.close();          

                    print("线程 " + this.threadId + "完成下载 ");

                    this.finish = true;

                    this.interrupt();

                } catch (Exception e) {

                    this.downLength = -1;

                    print("线程"+ this.threadId+ ":"+ e);

                }

            }

        }

        private static void print(String msg){

            Log.i(TAG, msg);

        }

        /**

         * 下载是否完成

         * @return

         */

        public boolean isFinish() {

            return finish;

        }

        /**

         * 已经下载的内容大小

         * @return 如果返回值为-1,代表下载失败

         */

        public long getDownLength() {

            return downLength;

        }

    }

    编写DownloadProgressListener.java:

     package com.sharpandroid.net.download;

     

    public interface DownloadProgressListener {

        public void onDownloadSize(int size);

    }

    完成Activity中的内容:

    package com.sharpandroid.download.activity;

     

    import java.io.File;

    import com.sharpandroid.net.download.DownloadProgressListener;

    import com.sharpandroid.net.download.FileDownloader;

    import android.app.Activity;

    import android.os.Bundle;

    import android.os.Environment;

    import android.os.Handler;

    import android.os.Message;

    import android.util.Log;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.ProgressBar;

    import android.widget.TextView;

    import android.widget.Toast;

     

    public class DownLoaderActivity extends Activity {

        private static final String TAG = "DownLoaderActivity";

        private EditText pathText;

        private ProgressBar progressBar;

        private TextView resultView;

        private Handler handler = new Handler(){

            @Override

            public void handleMessage(Message msg) {

                if(!Thread.currentThread().isInterrupted()){

                    switch (msg.what) {

                    case 1:

                        int size = msg.getData().getInt("size");

                        progressBar.setProgress(size);//设置当前刻度

                        int result =(int)(((float)progressBar.getProgress()/

    (float)progressBar.getMax()) * 100);

                        resultView.setText(result+ "%");

                        if(progressBar.getMax()==progressBar.getProgress()){

                            Toast.makeText(DownLoaderActivity.this, R.

    string.success, 1).show();

                        }

                        break;

     

                    case -1:

                        String error = msg.getData().getString("error");

                        Toast.makeText(DownLoaderActivity.this, error, 1).

    show();

                        break;

                    }

                   

                }

                super.handleMessage(msg);

            }

        };//用于往线程绑定的消息队列中发送或者处理消息

       

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            pathText = (EditText)findViewById(R.id.path);

            progressBar = (ProgressBar)findViewById(R.id.progressBar);

            resultView = (TextView)findViewById(R.id.result);

            Button button = (Button)findViewById(R.id.button);

            button.setOnClickListener(new View.OnClickListener() {          

                @Override

                public void onClick(View v) {

                    //下载文件,并保存到SDCard

                    if(Environment.getExternalStorageState().equals

    (Environment.MEDIA_MOUNTED)){

                        try {

                            download(pathText.getText().toString(),

    Environment.getExternalStorageDirectory());//1

                        } catch (Exception e) {

                            Toast.makeText(DownLoaderActivity.this,

    R.string.fail, 1).show();

                            Log.e(TAG, e.toString());

                        }

                    }else{

                        Toast.makeText(DownLoaderActivity.this,

    R.string.sdcarderror, 1).show();

                    }

                }

            });

        }

        //运行在主线程(UI线程负责显示控件的显示更新[重绘界面])

       private void download(final String path, final File saveDir) throws

    Exception{

          new Thread(new Runnable() {      

            @Override

            public void run() {

                 try {

                    FileDownloader downloader = new FileDownloader

    (DownLoaderActivity.this, path, saveDir, 3);

                    progressBar.setMax(downloader.getFileSize());

    //设置进度条的最大刻度

                    downloader.download(new DownloadProgressListener() {   

                            @Override

                            public void onDownloadSize(int size) {

    //得到文件实时的下载长度

                                Message msg = new Message();

                                msg.what = 1;

                                msg.getData().putInt("size", size);

                                handler.sendMessage(msg);

                            }

                       });

                } catch (Exception e) {

                    Message msg = new Message();

                    msg.what = -1;

                    msg.getData().putString("error", "下载失败");

                    handler.sendMessage(msg);

                    Log.e(TAG, e.toString());

                }

            }

        }).start();

    }

    }    

    在download方法中的代码:

    try {loader.download(new DownloadProgressListener() {                  

                    @Override

                    public void onDownloadSize(int size) {//得到当前下载的数量                     ...

    msg.setData(data);

                        handler.sendMessage(msg);

                    }

     

    在Handle的内部类的中的代码:

            public void handleMessage(Message msg) {

                if(!Thread.currentThread().isInterrupted()){

                    ...

    Toast.makeText(DownLoadActivity.this, error, 1).show();

                        break;

                    }              

                }

                super.handleMessage(msg);

            }

        };

    最后在AndroidManifest.xml加入相关的权限:

      <!--

     访问internet权限

      -->

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

    - <!--

     在SDCard中创建与删除文件权限

     -->

      <uses-permission android:name="android.permission.

    MOUNT_UNMOUNT_FILESYSTEMS" />

    - <!--

     往SDCard写入数据权限

      -->

      <uses-permission android:name="android.permission.

    WRITE_EXTERNAL_STORAGE" />

    26  Android文件上传 

    26.1  Android客户端上传初体验

    26.1.1  知识回顾

    3.第三步,核心代码实现

    新建一个Contact.java类:

    package com.sharpandroid.domain;

     

    public class Contact {

        private Integer id;

        private String name;

        private short age;

     

        public Contact(){

             

         }

        public Contact(Integer id, String name, short age) {

            super();

            this.id = id;

            this.name = name;

            this.age = age;

        }

     

        public Integer getId() {

            return id;

        }

        public void setId(Integer id) {

            this.id = id;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public short getAge() {

            return age;

        }

        public void setAge(short age) {

            this.age = age;

        }

    }

    新建ContactAction类图解。

    package com.sharpandroid.action;

     

    import java.util.ArrayList;

    import java.util.List;

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.Action;

    import org.apache.struts.action.ActionForm;

    import org.apache.struts.action.ActionForward;

    import org.apache.struts.action.ActionMapping;

    import com.sharpandroid.domain.Contact;

     

    public class ContactAction extends Action {

     

        @Override

        public ActionForward execute(ActionMapping mapping, ActionForm form,

                HttpServletRequest request, HttpServletResponse response)

                throws Exception {

    List<Contact> contacts = new ArrayList<Contact>();

               contacts.add(new Contact(01, "laoli", (short) 25));

               contacts.add(new Contact(02, "laozhang", (short) 28));

               contacts.add(new Contact(03,"laowen",(short) 30));

               contacts.add(new Contact(04,"laohou  ",(short) 29));

               request.setAttribute("contacts", contacts);

    return mapping.findForward("contacts");

        }

    }

    26.1.2  Android客户端直通CRM系统

    2.第二步,核心代码实现

    2)新建一个Contact.java实体类

       package com.sharpandroid.domain;

    public class Contact {

       

           private Integer id;

           private String name;

           private short age;

       

           public Contact(){

           

          }

       

        public Contact(Integer id, String name, short age) {

            super();

               this.id = id;

               this.name = name;

               this.age = age;

        }

           public Integer getId() {

               return id;

           }

           public void setId(Integer id) {

               this.id = id;

           }

           public String getName() {

              return name;

           }

           public void setName(String name) {

               this.name = name;

            }

           public short getAge() {

               return age;

            }

           public void setAge(short age) {

               this.age = age;

           }

     

         @Override

          public String toString() {

            return "Contact [age=" + age + ", id=" + id + ", name=" + name

     + "]";

        }

    }

    代码解析:

    分别定义了联系人Contact对象的id、name、age属性,并生成有参数和无参数的构造方法以及相应的set和get方法,为了后面输出的需要,覆盖它的toString方法。

    3)建立一个ContactService.java业务bean

     

    package com.sharpandroid.service;

     

    import java.io.InputStream;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import java.util.List;

    import javax.xml.parsers.SAXParser;

    import javax.xml.parsers.SAXParserFactory;

    import com.sharpandroid.domain.Contact;

     

     public class ContactService{

          

          /**

         * 获取CRM返回的客户数据

         * @return

         */

    private static InputStream requestContact() throws Exception{

          String path = "http://192.168.1.100:8080/CRM/contacts.do";

          URL url = new URL(path);

    HttpURLConnection conn =(HttpURLConnection)url.openConnection();

        conn.setConnectTimeout(5 * 1000);

        conn.setRequestMethod("GET");

        return conn.getInputStream();

    }

    }

    4)新建一个继承org.xml.sax.helpers.DefaultHandler的ContactDefaultHandler.java类

    package com.sharpandroid.service;

    import java.util.ArrayList;

    import java.util.List;

    import org.xml.sax.Attributes;

    import org.xml.sax.SAXException;

    import org.xml.sax.helpers.DefaultHandler;

    import com.sharpandroid.domain.Contact;

     

    public class ContactDefaultHandler extends DefaultHandler {

        private List<Contact> contacts;

        private Contact contact;//记录当前person

        private String preTag;//记录前一个标签的名称

     

        public List<Contact> getContacts() {

            return contacts;

        }

    /**

         * 第一个参数为:整个xml字符串

         */

        @Override

        public void characters(char[] ch, int start, int length) throws

     SAXException {

            if(preTag!=null){

                String data = new String(ch, start, length);

                if("name".equals(preTag)){             

                    contact.setName(data);

                }else if("age".equals(preTag)){

                    contact.setAge(new Short(data));

                }

            }

        }

        //适合在此方法完成初始化行为

        @Override

        public void startDocument() throws SAXException {

            contacts = new ArrayList<Contact>();

        }

    @Override

        public void startElement(String uri, String localName, String qName,

    Attributes attributes) throws SAXException {

            if("contact".equals(localName)){

                Integer id = new Integer(attributes.getValue(0));

                contact = new Contact();

                contact.setId(id);

            }

            preTag = localName;

        }

     

        @Override

        public void endElement(String uri, String localName, String qName)

     throws SAXException {

            if("contact".equals(localName)){

                contacts.add(contact);

                contact = null;

            }

            preTag = null;

        }

     

    }

    5)在ContactService类中创建getContacts()方法

            public static List<Contact> getContacts() throws Exception{

              

               InputStream inputStream = requestContact();

               SAXParserFactory factory = SAXParserFactory.newInstance();

               SAXParser saxParser = factory.newSAXParser();

    ContactDefaultHandler handler = new ContactDefaultHandler();

               saxParser.parse(inputStream, handler);

               inputStream.close();

               return handler.getContacts();

           }

    6)在com.sharpandroid.com.activity中建立单元测试类ContactTest.java

     

    public class ContactTest extends AndroidTestCase {

         private static final String TAG = "ContactTest";

     

         public void testContacts() throws Throwable{

            List<Contact> contacts = ContactService.getContacts();

            for(Contact contact : contacts){

                Log.i(TAG, contact.toString());

            }

        }

    }

    26.2  Android客户端实现请求参数数据上传

    26.2.1  知识回顾

    2.第二步,核心代码实现

    1)新建一个客户信息实体

    继承了org.apache.struts.action.ActionForm的ContactForm。

    package com.sharpandroid.formbean;

     

    import org.apache.struts.action.ActionForm;

     

    public class ContactForm extends ActionForm {

       

        private String name;

        private short age;

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public short getAge() {

            return age;

        }

        public void setAge(short age) {

            this.age = age;

        }

    }

    2)新建一个处理业务操作ContactManageAction.java类

    package com.sharpandroid.action;

     

    import javax.servlet.http.HttpServletRequest;

    import javax.servlet.http.HttpServletResponse;

    import org.apache.struts.action.ActionForm;

    import org.apache.struts.action.ActionForward;

    import org.apache.struts.action.ActionMapping;

    import org.apache.struts.actions.DispatchAction;

    import com.sharpandroid.formbean.ContactForm;

     

       public class ContactManageAction extends DispatchAction {

        //保存数据

        public ActionForward save(ActionMapping mapping, ActionForm form,

                HttpServletRequest request, HttpServletResponse response)

                throws Exception {

           

            ContactForm formbean = (ContactForm)form;

            System.out.println("name="+ formbean.getName());//姓名

            System.out.println("age="+ formbean.getAge());//年龄

           

            return mapping.findForward("result");

        }

    }

    26会那么高呢,原来里面有这么多的学问啊!

    第一步,业务分析

    新建一个单元测试类。

    package com.sharpandroid.test;

     

    import java.io.DataOutputStream;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import org.junit.Test;

     

     public class SendDataToCRMTest {

        private String name;

            private Short age;

          @Test

        public void testSave() throws Exception{

           

            save(name,age);

            }

    }

    新建testSave()单元测试方法:

       private  void save(String name, Short age) throws Exception{

           

                String path ="http://192.168.1.100:8080/CRM/contact/

    manage.do";

                String params ="method=save&name=li&age=36";

                byte[] data = params.getBytes();

                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection)url.

    openConnection();

                conn.setDoOutput(true);            //允许对外发送请求参数

                conn.setUseCaches(false);          //不进行缓存

                conn.setConnectTimeout(5 * 1000);

                conn.setRequestMethod("POST");

                                                       //下面设置http请求头

    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/vnd.

    application/x-ms-application, application/vnd.ms-excel, ms-powerpoint,

     application/msword, */*");

                conn.setRequestProperty("Accept-Language", "zh-CN");

                conn.setRequestProperty("User-Agent", "Mozilla/4.0

    (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

    CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

                conn.setRequestProperty("Content-Type", "application/

    x-www-form-urlencoded");

        conn.setRequestProperty("Content-Length", String.valueOf

    (data.length));

                conn.setRequestProperty("Connection", "Keep-Alive");

                                                                    //发送参数

            DataOutputStream outStream = new DataOutputStream

    (conn.getOutputStream());

                outStream.write(data);                      //把参数发送出去

                outStream.flush();

                outStream.close();

                if(conn.getResponseCode()==200){

             byte[] returndata =  StreamTool.readInputStream(conn.

    getInputStream());

                    System.out.print(new String(returndata));

                }

               

            }

    }

    编写StreamTool.java:

    public class StreamTool {

       

        public static byte[] readInputStream(InputStream inputStream) throws

    Exception {

            byte[] buffer = new byte[1024];

            int len = -1;

            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

            while( (len = inputStream.read(buffer)) != -1 ){

                outSteam.write(buffer, 0, len);

            }

            outSteam.close();

            inputStream.close();

            return outSteam.toByteArray();

        }

    }

    26.2.3  Android客户端之请求参数优化

    1.解决Android客户端的中文乱码问题

    1)第一种情况,J2EE中表单的post提交上传数据中文乱码问题

    用这种方式建立Filter可以自动在web.xml文件中进行配置:

    <filter>

            <display-name>EncodingFilter</display-name>

            <filter-name>EncodingFilter</filter-name>

    <filter-class>com.sharpandroid.filter.EncodingFilter</filter-class>

        </filter>

        <filter-mapping>

            <filter-name>EncodingFilter</filter-name>

            <url-pattern>*.do</url-pattern>

        </filter-mapping>

    程序代码:

       package com.sharpandroid.filter;

       import java.io.IOException;

    import javax.servlet.Filter;

    import javax.servlet.FilterChain;

    import javax.servlet.FilterConfig;

    import javax.servlet.ServletException;

    import javax.servlet.ServletRequest;

    import javax.servlet.ServletResponse;

    import javax.servlet.http.HttpServletRequest;

     

    public class EncodingFilte implements Filter {

     

    public void doFilter(ServletRequest request, ServletResponse response,

    FilterChain chain) throws IOException, ServletException {

            HttpServletRequest req = (HttpServletRequest) request;

            req.setCharacterEncoding("UTF-8");

            chain.doFilter(request, response);

        }

     

        public void init(FilterConfig fConfig) throws ServletException {

           

        }

         public void destroy() {

               

        }

    3)第三种,解决客户端应用中get方式发送请求参数中文乱码问题

    实现代码如下:

       @Test

            public void testGetSendData() throws Throwable{

                //以get方式发送请求参数

                String path = "http://192.168.1.100:8080/CRM/contact/

    manage.do?method=save&name="+ URLEncoder.encode("世界","UTF-8") + "

    &age=30";

                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection)url.

    openConnection();

                conn.setConnectTimeout(5 * 1000);

                conn.setRequestMethod("GET");

                if(conn.getResponseCode()==200){

                    byte[] data = StreamTool.readInputStream(conn.

    getInputStream());

                    System.out.println(new String(data));;

                }

    }

    2.Android客户端post方式发送请求参数优化

    post()方法具体代码如下:

    public static byte[] post(String path,Map<String, String> params,String

    encode) throws Exception{

            StringBuilder paramBuilder = new StringBuilder();

            if(params!=null && !params.isEmpty()){

            for(Map.Entry<String, String> entry : params.entrySet()){

                paramBuilder.append(entry.getKey()).append("=").append

    (URLEncoder.encode(entry.getValue(), encode))

                 .append("&");

                }

            paramBuilder.deleteCharAt(paramBuilder.length()-1);

            }

            byte[] data = paramBuilder.toString().getBytes();

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            conn.setDoOutput(true);//允许对外发送请求参数

            conn.setUseCaches(false);//不进行缓存

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("POST");

            //下面设置http请求头

            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, appl

    ication/x-ms-application, application/vnd.ms-excel, application/vnd.

    ms-powerpoint, application/msword, */*");

            conn.setRequestProperty("Accept-Language", "zh-CN");

            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible;

    MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR

    2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

            conn.setRequestProperty("Content-Type", "application/x-www-

    form-urlencoded");

            conn.setRequestProperty("Content-Length", String.valueOf(data.

    length));

            conn.setRequestProperty("Connection", "Keep-Alive");

           

                                                                 //发送参数

            DataOutputStream outStream = new DataOutputStream(conn.

    getOutputStream());

            outStream.write(data);//把参数发送出去

            outStream.flush();

            outStream.close();

            if(conn.getResponseCode()==200){

                return  StreamTool.readInputStream(conn.getInputStream());

            }

            return null;

        }

    }

    26.2.4  Android客户端之发送内容实体

    1.自定义HTTP协议发送内容实体

    核心代码sendXML方法实现:

       /**

         * 发送内容

         * @param path //请求路径

         * @param xml //XML数据

         */

        public static byte[] sendXML(String path, String xml) throws Exception{

            byte[] data = xml.getBytes();              //要发送的实体数据

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            conn.setDoOutput(true);                   //允许对外发送请求参数

            conn.setUseCaches(false);                 //不进行缓存

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("POST");

            //下面设置http请求头

            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,applicati

    on/x-ms-application, application/vnd.ms-excel, application/vnd.ms-

    powerpoint, application/msword, */*");

            conn.setRequestProperty("Accept-Language", "zh-CN");

            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible;

    MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR

    2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

            conn.setRequestProperty("Content-Type", "text/xml; charset=

    UTF-8");

            conn.setRequestProperty("Content-Length", String.valueOf(data.

    length));

            conn.setRequestProperty("Connection", "Keep-Alive");

           

                                                              //发送参数

            DataOutputStream outStream = new DataOutputStream(conn.

    getOutputStream());

            outStream.write(data);                    //把XML数据发送出去

            outStream.flush();

            outStream.close();

            if(conn.getResponseCode()==200){

                return StreamTool.readInputStream(conn.getInputStream());

            }

            return null;

        }

    }

    2.写一个单元测试方法准备实体并调用sendXML方法

    testsendXML()方法源码:

    @Test

    public void testsendXML()throws Throwable{

            String path = "http://192.168.1.100:8080/CRM/contact/manage.do?

    method=getXML";

            String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>

    <persons><person id=\"23\"><name>李明</name><age>30</age></person>

    </persons>";

            sendXML(path, xml);

        }

    3.在CRM客户关系管理系统接受实体

    getXML方法源码:

     public ActionForward getXML(ActionMapping mapping, ActionForm form,

                HttpServletRequest request, HttpServletResponse response)

                throws Exception {

            InputStream inStream = request.getInputStream();

            byte[] data = StreamTool.readInputStream(inStream);

            String xml = new String(data);

            System.out.println(xml);

            return mapping.findForward("result");

        }

    26.2.5  Android客户端发送数据参数到服务器

    1.第一种,Android客户端实现post方式发送数据到服务器

    1)完成View层

    String.xml的代码:

     <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="hello">Hello World, ContactActivity!</string>

        <string name="app_name">CRM客户端</string>

        <string name="name">姓名</string>

        <string name="age">年龄</string>

        <string name="button">保存</string>

    </resources>

    Main.xml的代码:

     <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

    <TextView 

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/name"

        />

        <EditText android:id="@+id/name"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        ></EditText>

        <TextView 

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/age"

        />

        <EditText android:id="@+id/age"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        ></EditText>

        <Button android:id="@+id/button"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/button"

        ></Button>

    </LinearLayout>

    2)核心代码实现——Controll层

    package com.sharpandroid.crm.activity;

     

    import com.sharpandroid.service.ContactService;

    import android.app.Activity;

    import android.os.Bundle;

    import android.util.Log;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.Toast;

     

    public class ContactActivity extends Activity {

        private static final String TAG = "ContactActivity";

        private EditText nameText;

        private EditText ageText;

       

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            nameText = (EditText) this.findViewById(R.id.name);

            ageText = (EditText) this.findViewById(R.id.age);

            Button button = (Button) this.findViewById(R.id.button);

            button.setOnClickListener(new View.OnClickListener() {          

                @Override

                public void onClick(View v) {

                    String name = nameText.getText().toString();

                    String age = ageText.getText().toString();

                    try {

                        ContactService.save(name, new Short(age));

                        Toast.makeText(ContactActivity.this, R.string.

    success, 1).show();

                    } catch (Exception e) {

                        Toast.makeText(ContactActivity.this, R.string.fail,

    1).show();

                        Log.e(TAG, e.toString());

                    }

                }

            });

           

        }

    }

    3)业务模型实现——Model层

    在ContactService业务bean中实现数据上传的功能,具体代码如下:

      public static  void save(String name,Short age) throws Exception{

                String path = "http://192.168.1.100:8080/CRM/contact/

    manage.do";

                Map<String, String> params = new HashMap<String, String>();

                params.put("method", "save");

                params.put("name", name);

                params.put("age", String.valueOf(age));

           post(path, params, "UTF-8");

           }

    (2)params.put("age", String.valueOf(age))

    要将age进行类型转换成需要的String类型。

           public static byte[] post(String path,Map<String, String>

    params,String encode) throws Exception{

                StringBuilder paramBuilder = new StringBuilder();

                if(params!=null && !params.isEmpty()){

                for(Map.Entry<String, String> entry : params.entrySet()){

                    paramBuilder.append(entry.getKey()).append("=").append

    (URLEncoder.encode(entry.getValue(), encode))

                     .append("&");

                    }

                paramBuilder.deleteCharAt(paramBuilder.length()-1);

                }

                byte[] data = paramBuilder.toString().getBytes();

                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection)url.

    openConnection();

                conn.setDoOutput(true);//允许对外发送请求参数

                conn.setUseCaches(false);//不进行缓存

                conn.setConnectTimeout(5 * 1000);

                conn.setRequestMethod("POST");

    //下面设置http请求头

                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("User-Agent", "Mozilla/4.0

    (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

    CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

    3.5.30729)");

                conn.setRequestProperty("Content-Type", "application/x-

    www-form-urlencoded");

                conn.setRequestProperty("Content-Length", String.valueOf

    (data.length));

                conn.setRequestProperty("Connection", "Keep-Alive");

               

                                                         //发送参数

                DataOutputStream outStream = new DataOutputStream(conn.

    getOutputStream());

                outStream.write(data);                //把参数发送出去

                outStream.flush();

                outStream.close();

                if(conn.getResponseCode()==200){

                  return  StreamTool.readInputStream(conn.getInputStream());

                }

                return null;

            }

    2.第二种,Android客户端实现get方式发送数据到服务器

    在ContactService业务bean中添加GetSendData()方法:

      public static void GetSendData(String name,Short age) throws Exception{

                //以get方式发送请求参数

                String path = "http://192.168.1.100:8080/CRM/contact/manage.

    do?method=save&name="+

                    URLEncoder.encode(name,"UTF-8") + "&age="+age;

                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection)url.

    openConnection();

                conn.setConnectTimeout(5 * 1000);

                conn.setRequestMethod("GET");

                if(conn.getResponseCode()==200){

                    byte[] data = StreamTool.readInputStream(conn.

    getInputStream());

                    System.out.println(new String(data));;

                }

            }

    3.用开源框架实现Android客户端发送实体

    在ContactService业务bean添加postFromHttpClient()方法:

       public static byte[] postFromHttpClient(String path, Map<String, String>

     params, String encode) throws Exception{

        List<NameValuePair> formparams = new ArrayList<NameValuePair>();    for(Map.Entry<String, String> entry : params.entrySet()){

             formparams.add(new BasicNameValuePair(entry.getKey(), entry.

    getValue()));

                }      

                UrlEncodedFormEntity entity = new UrlEncodedFormEntity

    (formparams, "UTF-8");

                HttpPost httppost = new HttpPost(path);

                httppost.setEntity(entity);

                HttpClient httpclient = new DefaultHttpClient();

    //看做是浏览器

                HttpResponse response = httpclient.execute(httppost);

    //发送post请求     

                return StreamTool.readInputStream(response.getEntity().

    getContent());

            }

     

    26.3  Android客户端实现文件上传

    26.3.1  知识回顾

    1)业务模型实现——Model层

    在ContactForm中定义上传的参数类型:

    Com.sharpandroid.formbean.ContactForm.java

     

    public class ContactForm extends ActionForm {

           private String name;

           private Short age;

           private FormFile image;

       

        public FormFile getImage() {

            return image;

        }

        public void setImage(FormFile image) {

            this.image = image;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public Short getAge() {

            return age;

        }

        public void setAge(Short age) {

            this.age = age;

        }

       

    }

    2)核心代码实现——Controll层

    save()方法源码:

    public ActionForward save(ActionMapping mapping, ActionForm form,

                HttpServletRequest request, HttpServletResponse response)

                throws Exception {

           ContactForm formbean = (ContactForm)form;

            //System.out.println("get : name="+ new String(request.

    getParameter("name").getBytes("ISO-8859-1"),"UTF-8"));

            System.out.println("name="+ formbean.getName());

            System.out.println("age="+ formbean.getAge());

            if(formbean.getImage()!=null && formbean.getImage().

    getFileSize()>0){

            String dirRealPath = request.getSession().getServletContext().

    getRealPath("/images");

                System.out.println(dirRealPath);

                File dir = new File(dirRealPath);

                if(!dir.exists()) dir.mkdirs();

                File saveFile = new File(dir, formbean.getImage().

    getFileName());

                FileOutputStream outStream = new FileOutputStream(saveFile);

                outStream.write(formbean.getImage().getFileData());

                outStream.close();

            }

            return mapping.findForward("result");

        }

    3)页面美化——View层

    index.jsp页面中的代码:

      <body>

        <form action="${pageContext.request.contextPath}/contact/manage.

    do" method="post" enctype="multipart/form-data">

            <input type="hidden" name="method" value="save"/>

            姓名:<input type="text" name="name"/><br/>

            年龄:<input type="text" name="age"/><br/>

            图片:<input type="file" name="image"/><br/>

            <input type="submit" value="保存"/>

        </form>

    </body>

    26.3.2  Android客户端之文件上传

    1)模型实现——Model层

    FormFile.java 源代码:

      import java.io.InputStream;

     

    /**

     * 上传文件

     */

    public class FormFile {

        private byte[] data;

        private InputStream inStream;

        private String filname;

        private String formname;

        private String contentType = "application/octet-stream";

       

        public FormFile(String filname, byte[] data, String formname, String

    contentType) {

            this.data = data;

            this.filname = filname;

            this.formname = formname;

            if(contentType!=null) this.contentType = contentType;

        }

       

        public FormFile(String filname, InputStream inStream, String formname,

    String contentType) {

            this.filname = filname;

            this.formname = formname;

            this.inStream = inStream;

            if(contentType!=null) this.contentType = contentType;

        }

       

        public InputStream getInStream() {

            return inStream;

        }

     

        public byte[] getData() {

            return data;

        }

     

        public String getFilname() {

            return filname;

        }

     

        public void setFilname(String filname) {

            this.filname = filname;

        }

     

        public String getFormname() {

            return formname;

        }

     

        public void setFormname(String formname) {

            this.formname = formname;

        }

     

        public String getContentType() {

            return contentType;

        }

     

        public void setContentType(String contentType) {

            this.contentType = contentType;

        }

       

    }

    通过面向HTTP协议,实现如下面表单提交功能,具体的代码如下:

    package com.sharpandroid.utils;

     

    import java.io.DataOutputStream;

    import java.io.InputStream;

    import java.net.HttpURLConnection;

    import java.net.URL;

    import java.util.Map;

       

    public class HttpRequester {

        public static String post(String actionUrl, Map<String, String> params,

     FormFile[] files) {

            try {           

                String BOUNDARY = "---------7d4a6d158c9";      //数据分隔线

                String MULTIPART_FORM_DATA = "multipart/form-data";

               

                URL url = new URL(actionUrl);

                HttpURLConnection conn = (HttpURLConnection)

    url.openConnection();

                conn.setConnectTimeout(5* 1000);

                conn.setDoInput(true);                      //允许输入

                conn.setDoOutput(true);                    //允许输出

                conn.setUseCaches(false);                  //不使用Cache

                conn.setRequestMethod("POST");          

                conn.setRequestProperty("Connection", "Keep-Alive");

                conn.setRequestProperty("Charset", "UTF-8");

                conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA

    + "; boundary=" + BOUNDARY);

     

                StringBuilder sb = new StringBuilder();

                for (Map.Entry<String, String> entry : params.entrySet()) {

    //构建表单字段内容

                    sb.append("--");

                    sb.append(BOUNDARY);

                    sb.append("\r\n");

                    sb.append("Content-Disposition: form-data; name=\""+

    entry.getKey() + "\"\r\n\r\n");

                    sb.append(entry.getValue());

                    sb.append("\r\n");

                }

                DataOutputStream outStream = new DataOutputStream

    (conn.getOutputStream());

                outStream.write(sb.toString().getBytes());   //发送表单字段数据

                for(FormFile file : files){                    //发送文件数据

                StringBuilder split = new StringBuilder();

                    split.append("--");

                    split.append(BOUNDARY);

                    split.append("\r\n");

                    split.append("Content-Disposition: form-data;name=\""+

    file.getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");

                    split.append("Content-Type: "+ file.getContentType()+"

    \r\n\r\n");

                    outStream.write(split.toString().getBytes());

                    if(file.getInStream()!=null){

                    byte[] buffer = new byte[1024];

                    int len = 0;

                    while((len = file.getInStream().read(buffer))!=-1){

                         outStream.write(buffer, 0, len);

                    }

                    file.getInStream().close();

                    }else{

                    outStream.write(file.getData(), 0, file.getData().length);

                    }

                    outStream.write("\r\n".getBytes());

                }

                byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();

    //数据结束标志          

                outStream.write(end_data);

                outStream.flush();

                int cah = conn.getResponseCode();

                if (cah != 200) throw new RuntimeException("请求url失败");

                InputStream is = conn.getInputStream();

                int ch;

                StringBuilder b = new StringBuilder();

                while( (ch = is.read()) != -1 ){

                b.append((char)ch);

                }           

                outStream.close();

                conn.disconnect();

                return b.toString();

            } catch (Exception e) {

            throw new RuntimeException(e);

            }

        }

       

        public static String post(String actionUrl, Map<String, String> params,

    FormFile file) {

           return post(actionUrl, params, new FormFile[]{file});

        }

    }

    HttpRequester.java上传数据模型如下:

         * 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能

         *   <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/

    fileload/test.do" enctype="multipart/form-data">

                <INPUT TYPE="text" NAME="name">

                <INPUT TYPE="text" NAME="id">

                <input type="file" name="imagefile"/>

                <input type="file" name="zip"/>

             </FORM>

         * @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径

    测试,因为它会指向手机模拟器,你可以使用像http://192.168.1.10:8080这样的路径测试)

         * @param params 请求参数 key为参数名,value为参数值

         * @param file 上传文件

    构造一个数据的内容:

    {

    sb.append("--");

              sb.append(BOUNDARY);

              sb.append("\r\n");

         sb.append("Content-Disposition: form-data; name=\""+ entry.getKey()

     + "\"\r\n\r\n");

              sb.append(entry.getValue());

              sb.append("\r\n");

    }

     

    sb.append("--");

    sb.append(BOUNDARY);

    文件可能有很多,我们构造一个,然后去迭代。

    split.append("--");

              split.append(BOUNDARY);

              split.append("\r\n");

    split.append("Content-Disposition: form-data;name=\""+ file.

    getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");

              split.append("Content-Type: "+ file.getContentType()+

    "\r\n\r\n");

              outStream.write(split.toString().getBytes());

              if(file.getInStream()!=null){

                    byte[] buffer = new byte[1024];

                    int len = 0;

                    while((len = file.getInStream().read(buffer))!=-1){

                         outStream.write(buffer, 0, len);

                    }

                    file.getInStream().close();

                    }else{

                    outStream.write(file.getData(), 0, file.getData().length);

                    }

    outStream.write("\r\n".getBytes());

                }

                byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();//

    数据结束标志        

    sb.append("--");

    sb.append(BOUNDARY);

    2)核心代码实现——Controll层

    编写ContactActivity.java:

    package com.sharpandroid.crm.activity;

     

    import java.io.File;

    import java.io.FileInputStream;

    import com.sharpandroid.service.ContactService;

    import com.sharpandroid.utils.FormFile;

    import android.app.Activity;

    import android.os.Bundle;

    import android.os.Environment;

    import android.util.Log;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.Toast;

    public class ContactActivity extends Activity {

        private static final String TAG = "ContactActivity";

        private EditText nameText;

        private EditText ageText;

       

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            nameText = (EditText) this.findViewById(R.id.name);

            ageText = (EditText) this.findViewById(R.id.age);

            Button button = (Button) this.findViewById(R.id.button);

            button.setOnClickListener(new View.OnClickListener() {          

                @Override

                public void onClick(View v) {

                    String name = nameText.getText().toString();

                    String age = ageText.getText().toString();

                    try {

                        String filename = " android.jpg";

                        FileInputStream inStream = new FileInputStream(new

    File(Environment.getExternalStorageDirectory(), filename));

                        FormFile file = new FormFile(filename, inStream, "

    image", "image/pjpeg");

                        ContactService.save(name, new Short(age), file);

                        Toast.makeText(ContactActivity.this, R.string.

    success, 1).show();

                    } catch (Exception e) {

                        Toast.makeText(ContactActivity.this, R.string.fail,

    1).show();

                        Log.e(TAG, e.toString());

                    }

                }

            });

           

        }

    }

    在ContactActivity.java中构建FormFile ContactActivity.java 关键代码:

    String filename = " android.jpg";

    FileInputStream inStream = new FileInputStream(new File(Environment.

    getExternalStorageDirectory(), filename));

    FormFile file = new FormFile(filename, inStream, "image", "image/

    pjpeg");

    ContactService.save(name, new Short(age), file);

    在ContactService.java中完成带文件的save()方法:

    public static void save(String name, Short age, FormFile file) throws

    Exception{

            String path = "http://192.168.1.100:8080/CRM/contact/manage.do";

            Map<String, String> params = new HashMap<String, String>();

    params.put("method", "save");

            params.put("name", name);

            params.put("age", String.valueOf(age));

            HttpRequester.post(path, params, file);

        }

    (2)调用HttpRequester中的上传单个文件的post()方法:HttpRequester.post(path, params, file)。

    加入访问网络和对SD卡读写的相关的权限:

    - <!--

     在SD Card中创建与删除文件权限

      -->

      <uses-permission android:name="android.permission.MOUNT_UNMOUNT_

    FILESYSTEMS" />

    - <!--

     在SD Card中写入数据权限

     --> 

     <uses-permission android:name="android.permission.WRITE_EXTERNAL_

    STORAGE" />

    27  Socket编程 

    27.3  Socket编程实战——Android聊天室实例

    27.3.1  编写PC端工程代码

    2.编写服务器端程序代码

    1)编写Server.java

    import java.awt.BorderLayout;

    import javax.swing.*;

    import java.awt.event.*;

    public class Sever extends JFrame implements ActionListener

    {   //服务器端主程序负责界面,以及服务段主线程ServerThread的启动     

        //服务端主线程ServerThread又产生BroadCast及ClientThread线程

        //建立服务器端主界面中所用到的布局方式

        BorderLayout borderLayout1 = new BorderLayout();

        BorderLayout borderLayout2 = new BorderLayout();

       

        JPanel jPanel1 = new JPanel();    //创建面板

        JPanel jPanel2 = new JPanel();

        JButton jButton1 = new JButton(); //创建按钮

        JButton jButton2 = new JButton();

        JScrollPane jScrollPane1 = new JScrollPane();

       

        //创建服务器端接收信息文本框

        static JTextArea jTextArea1 = new JTextArea();

        boolean bool = false, start = false;

       

        //声明ServerThread线程类对象

        ServerThread serverThread;

        Thread thread;

       

        //构造函数,用于初始化

        public Sever()  

        { 

        super("Server");

        //设置内容面板布局方式

            getContentPane().setLayout(borderLayout1);

           

            //初始化按钮组件

            jButton1.setText("启动服务器");

            jButton1.addActionListener(this);

            jButton2.setText("关闭服务器");

            jButton2.addActionListener(this);

           

            //初始化jPanel1面板对象,并向其中加入组件

            this.getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);

            jPanel1.add(jButton1);

            jPanel1.add(jButton2);

     

            //初始化jPanel2面板对象,并向其中加入组件

            jTextArea1.setText("");

            jPanel2.setLayout(borderLayout2);

            jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);

            jScrollPane1.getViewport().add(jTextArea1);

            this.getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);

           

            this.setSize(400, 400);  

            this.setVisible(true);

        }

     

        public static void main(String[] args)

        {

            Sever sever = new Sever();

            sever.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        }

     

        //服务器界面中按钮事件处理

        public void actionPerformed(ActionEvent e)

        {

            if(e.getSource() == jButton1)

           {

                serverThread = new ServerThread();

                 serverThread.start();

           }else if(e.getSource() == jButton2){

                bool = false;

                start = false;

                serverThread.finalize();

                this.setVisible(false);

         }

        }

    }

    2)编写ServerThread.java

    import java.net.*;

    import java.util.*;

    import java.io.*;

    public class ServerThread extends Thread        

        //服务器监听端口线程

    {

        //声明ServerSocket类对象

        ServerSocket serverSocket; 

        //指定服务器监听端口常量

        public static final int PORT = 8521;

     

        //创建一个Vector对象,用于存储客户端连接的ClientThread对象

        //ClientThread类维持服务器与单个客户端的连接线程

        //负责接收客户端发来的信息

        Vector<ClientThread> clients;

        //创建一个Vector对象,用于存储客户端发送过来的信息

        Vector<Object> messages;

        //声明BroadCast类对象

        //BroadCast类负责服务器向客户端广播消息

        BroadCast broadcast; 

       

        String ip;

        InetAddress myIPaddress=null;

     

        public ServerThread()

        {

        //创建两个Vector数组非常重要

        //clients负责存储所有与服务器建立连接的客户端

        //messages负责存储服务器接收到的未发送出去的全部客户端的信息

            clients=new Vector<ClientThread>();    

            messages=new Vector<Object>();

           

            try

            {

            //创建ServerSocket类对象

                serverSocket = new ServerSocket(PORT);

            }

            catch(IOException E){}

            //获取本地服务器地址信息

            try {

            myIPaddress=InetAddress.getLocalHost();

            }catch (UnknownHostException e){System.out.println(e.

    toString());}

            ip = myIPaddress.getHostAddress();

            Sever.jTextArea1.append("服务器地址:"+ ip +

                 "端口号:"+String.valueOf(serverSocket.getLocalPort())+"

    \n");

           

            //创建广播信息线程并启动

            broadcast = new BroadCast(this);

            broadcast.start();

        }

     

        //注意:一旦监听到有新的客户端创建即new Socket(ip, PORT)被执行,

        //就创建一个ClientThread来维持服务器与这个客户端的连接

         public void run()

         {

             while(true)

             {

                 try

                 {

                   //获取客户端连接,并返回一个新的Socket对象

                     Socket socket = serverSocket.accept();

                    

    System.out.println(socket.getInetAddress().getHostAddress());

                     //创建ClientThread线程并启动

                     //启动ClientTread之后,可以监听该连接对应的客户端是否发送来消息,

                     //并获取消息

                     ClientThread clientThread=new ClientThread(socket,this);

                     clientThread.start();

                     if(socket!=null)

                     {

                         synchronized (clients)

                         {

                            //将客户端连接加入到Vector数组中保存

                             clients.addElement(clientThread);

                         }

                     }

                 }

                 catch(IOException E)

                 {

                     System.out.println("发生异常:"+E);

                     System.out.println("建立客户端联机失败!");

                     System.exit(2);

                 }

             }

         }

     

         public void finalize()   

         {

             try

             {   //关闭serverSocket方法

                 serverSocket.close();

             }

             catch(IOException E){}

             serverSocket=null;

         }

    }

    3)编写ClientThread.java

    import java.net.*;

    import java.io.*;

    public class ClientThread extends Thread          

    {  

        //维持服务器与单个客户端的连接线程,负责接收客户端发来的信息

       

        //声明一个新的Socket对象,

        //用于保存服务器端用accept方法得到的客户端的连接

        Socket clientSocket;

       

        //声明服务器端中存储的Socket对象的数据输入/输出流

        DataInputStream in = null;

        DataOutputStream out = null;

       

        //声明ServerThread对象

        ServerThread serverThread;

    //    String str;

       

    //    public static int ConnectNumber=0;

     

        public ClientThread(Socket socket,ServerThread serverThread)

        {

        clientSocket=socket;  

            this.serverThread=serverThread;

            try

            {

             //创建服务器端数据输入/输出流

                in = new DataInputStream(clientSocket.getInputStream());

                out = new DataOutputStream(clientSocket.getOutputStream());

            }

            catch (IOException e2)

            {

                System.out.println("发生异常"+e2);

                System.out.println("建立I/O通道失败!");

                System.exit(3);

            }

        }

        //该方法监听该连接对应得客户端是否有消息发送

        public void run()

        {

            while(true)

            {

                try

                {

                  //读入客户端发送来的信息

                    String message=in.readUTF();

                    synchronized(serverThread.messages)

                    {

                        if(message!=null)

                        {

                           //将客户端发送来得信息存于serverThread的messages数组中

                            serverThread.messages.addElement(message);

                            //在服务器端的文本框中显示新消息

                            Sever.jTextArea1.append(message+'\n');

                        }

                    }

                }

                catch(IOException E){break;}

            }

        }

    }

    4)编写BroadCast.java

    import java.io.*;

    public class BroadCast extends Thread                 

    {   //服务器向客户端广播线程

        //声明ClientThread对象

        ClientThread clientThread;

        //声明ServerThread对象

        ServerThread serverThread;

        String str;

     

        public BroadCast(ServerThread serverThread)

        {

            this.serverThread = serverThread;

        }

       //该方法的作用是不停地向所有客户端发送新消息

        public void run()

        {

            while(true)

            {

                try  

                {

                  //线程休眠200 ms

                    Thread.sleep(200);

                }

                catch(InterruptedException E){}

             

                //同步化serverThread.messages

                synchronized(serverThread.messages)

                {

                  //判断是否有未发的消息

                    if(serverThread.messages.isEmpty()){

                      continue;

                    }

                    //获取服务器端存储的需要发送的第一条数据信息

                    str = (String)this.serverThread.messages.firstElement();

                }

                //同步化serverThread.clients

                synchronized(serverThread.clients)

                {

                  //利用循环获取服务器中存储的所有建立的与客户端的连接

                    for(int i=0;i<serverThread.clients.size();i++)

                    {

                        clientThread=(ClientThread)serverThread.clients.

    elementAt(i);

                        try

                        {

                           //向记录的每一个客户端发送数据信息

                            clientThread.out.writeUTF(str);

                        }

                        catch(IOException E){}

                    }

                    //从Vector数组中删除已经发送过的那条数据信息

                    this.serverThread.messages.removeElement(str);

                }

            }

        }

    }

    3.编写PC客户端程序代码

    PC客户端包括一个类,Client.java。Client.java的代码如下:

    import javax.swing.*;

    import java.awt.*;

    import java.net.*;

    import java.sql.Date;

    import java.text.SimpleDateFormat;

    import java.io.*;

    import java.awt.event.*;

    public class Client extends JFrame implements Runnable,ActionListener           

    {   //客户端程序

        private static final long serialVersionUID = 1L;

     

        //创建Socket通信端口号常量

        public static final int PORT = 8521;

       

        …

    Swing代码生成界面省略

        //声明套接字对象

        Socket socket;

        //声明线程对象

        Thread thread; 

       

        //声明客户器端数据输入/输出流

        DataInputStream in;

        DataOutputStream out;

        //是否登录的标记

        boolean flag=false;

       

        //声明字符串,name存储用户名,chat_txt存储发言信息,chat_in存储从服务器接收到

    的信息

        String name,chat_txt,chat_in;

        String ip=null;

       

        //构造方法,生成客户端界面

        public Client()

        {

        …

    Swing代码生成界面省略

        }

     

        public static void main(String[] args)

        {

            Client client = new Client();

            client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        }

     

        //客户端线程启动后的动作

        public void run()  

        {

         //循环执行,作用是一直监听服务器端是否有消息

            while(true)  

            {

                try

                {

                  //读取服务器发送来的数据信息

                   chat_in = in.readUTF();

                   //将消息并显示在客户端的对话窗口中

                   jTextArea1.append(chat_in+"\n\n");

                }

                catch(IOException e){}

            }

        }

       

        //界面按钮的事件处理机制

        public void actionPerformed(ActionEvent e)

        {

        //"进入聊天室"按钮的处理

        if(e.getSource() == loginJButton)

        {

            //获取用户名

            name=jTextField1.getText();

            //获取服务器ip

            ip=jTextField3.getText();

            //判断用户名是否有效及ip是否为空

            if(name!="用户名输入"&&ip!=null)

            {

                try

                {

                    //创建Socket对象

                    socket = new Socket(ip, PORT);

                    //创建客户端数据输入/输出流,用于对服务器端发送或接收数据

                    in = new DataInputStream(socket.getInputStream());

                    out = new DataOutputStream(socket.getOutputStream());

                    Date now = new Date(System.currentTimeMillis());

                      SimpleDateFormat format = new SimpleDateFormat("hh:mm:

    ss");

                      String nowStr = format.format(now);

                   

                      out.writeUTF("$$"+name +"  "+ nowStr + " 上线了!");

                } catch (IOException e1) {System.out.println("can not

    connect");}

                thread = new Thread(this);

                //开启线程,监听服务器端是否有消息

                thread.start();

                //说明已经登录成功

                flag = true;

            }

        }

        //"发送"按钮的处理

        else if(e.getSource() == sendMessageJButton)

        {

           

            //获取客户端输入的发言内容

                chat_txt=jTextField2.getText();

                if(chat_txt!=null)

                {

                  Date now = new Date(System.currentTimeMillis());

                  SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");

                  String nowStr = format.format(now);

                  //发言,向服务器发送发言的信息

                    try{out.writeUTF("^_^" +jTextField1.getText()+ "  " +

    nowStr + " 说\n"+chat_txt);}

                    catch(IOException e2){}

                }

                else

                {

                    try{out.writeUTF("请说话");}

                    catch(IOException e3){}

                }        

        }

        //"退出聊天室"按钮事件的处理

        else if(e.getSource() == leaveJButton)

        {

                if(flag==true)

                {

                 

                    try

                    {

                      out.writeUTF("##"+ name +"下线了!");

                      //关闭socket

                      out.close();

                      in.close();

                      socket.close();

                    } catch (IOException e4) {}

                }

                flag=false;

                this.setVisible(false);          

        }

        }

    }

    27.3.2  编写手机客户端工程代码

    2.编写strings.xml

    <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="hello">Hello World, ChatClientActivity!</string>

        <string name="app_name">聊天室Android客户端</string>

        <string name="username">用户名:</string>

        <string name="ip">服务器IP:</string>

        <string name="login">进入</string>

        <string name="leave">退出</string>

        <string name="send">发送</string>

    </resources>

    3.编写main.xml

    <?xml version="1.0" encoding="utf-8"?>

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

    android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

         <TextView

            android:text="@string/username"

            android:layout_width="70px"

            android:layout_height="40px"

            android:id="@+id/usernameText"/>

         <EditText

            android:text=" "

            android:layout_width="180px"

            android:layout_height="40px"

            android:maxLength="10"

            android:layout_toRightOf="@id/usernameText"

            android:id="@+id/username" >

        </EditText>

       

        <Button

        android:layout_width="wrap_content"

        android:layout_height="40px"

        android:text="@string/login"

            android:layout_toRightOf="@id/username"

            android:id="@+id/LoginButton"/>

         

         <TextView

            android:text="@string/ip"

            android:layout_width="70px"

            android:layout_height="40px"

            android:layout_below="@id/username"

            android:layout_alignParentLeft="true"

            android:id="@+id/ipText"/>

         <EditText

            android:text="192.168.1.188"

            android:layout_width="180px"

            android:layout_height="40px"

            android:layout_toRightOf="@id/ipText"

            android:layout_alignTop="@id/ipText"

            android:digits=".1234567890"

            android:id="@+id/ip" >

        </EditText>

        <Button

        android:layout_width="wrap_content"

        android:layout_height="40px"

        android:text="@string/leave"

            android:layout_toRightOf="@id/ip"

            android:layout_alignTop="@id/ip"

            android:id="@+id/LeaveButton"/> 

     

        <EditText

            android:layout_width="fill_parent"

            android:layout_height="280px"

            android:layout_below="@id/ipText"

            android:editable="false"

            android:gravity="top"

            android:id="@+id/history" >

        </EditText>

        <EditText

            android:layout_width="280px"

            android:layout_height="240px"

            android:layout_below="@id/history"

            android:gravity="top"

            android:id="@+id/message" >

        </EditText>

        <Button

        android:layout_width="wrap_content"

        android:layout_height="240px"

        android:text="@string/send"

        android:layout_toRightOf="@id/message"

        android:layout_alignTop="@id/message"

            android:id="@+id/SendButton"/>

    </RelativeLayout>

    4.编写功能清单文件,添加网络访问权限

    编写AndroidManifest.xml:

    <?xml version="1.0" encoding="utf-8"?>

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="com.sharpandroid.chatclient"

          android:versionCode="1"

          android:versionName="1.0">

        <application android:icon="@drawable/icon" android:label="@string/

    app_name">

            <activity android:name=".ChatClientActivity"

                      android:label="@string/app_name">

                <intent-filter>

                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER"

    />

                </intent-filter>

            </activity>

     

        </application>

        <uses-sdk android:minSdkVersion="7" />

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

    permission>

    </manifest>

    5.编写ChatClientActivity.java

    package com.sharpandroid.chatclient;

     

    import java.io.DataInputStream;

    import java.io.DataOutputStream;

    import java.io.IOException;

    import java.net.InetAddress;

    import java.net.Socket;

    import java.sql.Date;

    import java.text.SimpleDateFormat;

     

    import android.app.Activity;

    import android.os.Bundle;

    import android.os.Handler;

    import android.os.Message;

    import android.view.View;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.Toast;

     

    public class ChatClientActivity extends Activity implements Runnable{

        private EditText usernameEdit;

        private EditText ipEdit;

        private EditText historyEdit;

        private EditText messageEdit;

       

        private Button loginButton;

        private Button sendButton;

        private Button leaveButton;

      

        //声明字符串,name存储用户名

        //chat_txt存储发言信息

        //chat_in存储从服务器接收到的信息

        private String username,ip,chat_txt,chat_in;

        //创建Socket通信端口号常量

        public static final int PORT = 8521;

       

         //声明套接字对象

        Socket socket;

       

        //声明线程对象

        Thread thread; 

       

        //声明客户器端数据输入输出流

        DataInputStream in;

        DataOutputStream out;

        //是否登录的标记

        boolean flag=false;

       

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            //获取main.xml文件中定义的一系列组件

            usernameEdit = (EditText) findViewById(R.id.username);

            ipEdit = (EditText) findViewById(R.id.ip);

            historyEdit = (EditText) findViewById(R.id.history);

            messageEdit = (EditText) findViewById(R.id.message);

       

            loginButton = (Button) findViewById(R.id.LoginButton);

            sendButton = (Button) findViewById(R.id.SendButton);

            leaveButton = (Button) findViewById(R.id.LeaveButton);

           

            //为三个按钮注册监听器

            loginButton.setOnClickListener(listener);

            sendButton.setOnClickListener(listener);

            leaveButton.setOnClickListener(listener);

         }

       

        View.OnClickListener listener = new View.OnClickListener() {

           

            @Override

            public void onClick(View v) {

                switch (v.getId()) {

                //"进入聊天室"按钮的处理

                case R.id.LoginButton:

                    if(flag == true){

                        Toast.makeText(ChatClientActivity.this,"已经登陆过

    了!", Toast.LENGTH_SHORT).show();

                        return;

                    }

                 //获取用户名

                 username = usernameEdit.getText().toString();

                 //获取服务器ip

                 ip = ipEdit.getText().toString();

                 //判断用户名是否有效及ip是否为空

                 if(username != "" && username!=null

                         && username!="用户名输入" && ip!=null){

                     try

                     {

                         //创建Socket对象

                         socket = new Socket(ip, PORT);

                         //创建客户端数据输入/输出流,用于对服务器端发送或接收数据

                         in = new DataInputStream(socket.getInputStream());

                         out = new DataOutputStream(socket.getOutputStream());

                        

                         Date now = new Date(System.currentTimeMillis());

                          SimpleDateFormat format = new SimpleDateFormat("

    hh:mm:ss");

                          String nowStr = format.format(now);

                        

                          out.writeUTF("$$" + username +"  "+ nowStr + " 上

    线了!");

                     } catch (IOException e1) {System.out.println("can not

    connect");}

                     thread = new Thread(ChatClientActivity.this);

                     //开启线程,监听服务器段是否有消息

                     thread.start();

                     //说明已经登录成功

                     flag = true;

                 }

                    break;

                //"发送"按钮的处理

                case R.id.SendButton:

                    if(flag ==false){

                           Toast.makeText(ChatClientActivity.this, "没有登录,

    请登录!",Toast.LENGTH_SHORT).show();

                           return;

                    }

                    //获取客户端输入的发言内容

                    chat_txt = messageEdit.getText().toString();

                    if(chat_txt != null)

                    {

                      Date now = new Date(System.currentTimeMillis());

                      SimpleDateFormat format = new SimpleDateFormat("hh:mm:

    ss");

                      String nowStr = format.format(now);

                     

                      //发言,向服务器发送发言的信息

                        try{out.writeUTF("^_^" + username+ "  " + nowStr + "

    说\n" + chat_txt);}

                        catch(IOException e2){}

                    }

                    else

                    {

                        try{out.writeUTF("请说话");}

                        catch(IOException e3){}

                    }        

                    break;

                //"退出聊天室"按钮事件的处理

                case R.id.LeaveButton:

                     if(flag==true)

                        {

                         if(flag ==false){

                               Toast.makeText(ChatClientActivity.this, "没有

    登录,请登录!",Toast.LENGTH_SHORT).show();

                               return;

                        }

                         try {

                              out.writeUTF("=="+username+"下线了!");

                              //关闭socket

                              out.close();

                              in.close();

                              socket.close();

                            } catch (IOException e4) {}

                        }

                        flag=false;

                        Toast.makeText(ChatClientActivity.this, "已退出!",

    Toast.LENGTH_SHORT).show();

                    break;

                }

            }

        };

         //客户端线程启动后的动作

        @Override

        public void run() {

             //循环执行,作用是一直监听服务器端是否有消息

            while(true)  

            {

                try

                {

                  //读取服务器发送来的数据信息

                   chat_in = in.readUTF();

                   chat_in = chat_in + "\n";

                   //发送一个消息,要求刷新界面

                   mHandler.sendMessage(mHandler.obtainMessage());

                }

                catch(IOException e){}

            }

        }

        Handler mHandler = new Handler()

        {                                      

              public void handleMessage(Message msg)

              {    

                  //将消息并显示在客户端的对话窗口中

                  historyEdit.append(chat_in);

                  // 刷新   

                  super.handleMessage(msg);    

               

              }

         };

    }

    28  WebView的介绍及应用  

    28.2  WebView浏览网页简单示例

    编写strings.xml:

    <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="hello">请输入网址:</string>

        <string name="app_name">WebView简单示例</string>

        <string name="button">LoadUrl</string>

        <string name="button1">LoadData</string>

    </resources>

    编写main.xml文件:

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

        <TextView 

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="@string/hello"/>

           

            <EditText

                android:id="@+id/path"

                android:layout_width="fill_parent"

                android:layout_height="wrap_content"

                android:text="http://www.baidu.com"/>

         <Button

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@string/button"

            android:id="@+id/button"/> 

         <Button

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@string/button1"

            android:id="@+id/button1"/> 

        <WebView

            android:layout_height="fill_parent"

            android:layout_width="fill_parent"

            android:id="@+id/webview"/>

    </LinearLayout>

    编写WebViewActivity1.java:

    package com.sharpandroid.webviewdemo1;

     

    import android.app.Activity;

    import android.os.Bundle;

    import android.view.View;

    import android.webkit.WebView;

    import android.widget.Button;

    import android.widget.EditText;

     

    public class WebViewActivity1 extends Activity {

       

        private WebView webView;

        private EditText pathEdit;

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

           webView = (WebView) findViewById(R.id.webview);

          

           Button Button = (Button) findViewById(R.id.button);

           //为第一个button添加单击事件

           button.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                //获取文本框里的内容

                pathEdit = (EditText) findViewById(R.id.path);

                String path = pathEdit.getText().toString();

                //在WebView中加载指定的路径,路径以“http://”开头

                webView.loadUrl(path); 

            }

        });

          

           Button button1 = (Button) findViewById(R.id.button1);

           //为第二个Button添加单击事件

           button1.setOnClickListener(new View.OnClickListener() {

           @Override

           public void onClick(View v) {

               pathEdit = (EditText) findViewById(R.id.path);

               //定义一个字符串,内容包含一个超链接,指向百度

               String data = "<a href='http://www.baidu.com'>baidu</a>" ;

               //在WebView中加载该数据,数据类型是“text/html”,编码格式是“utf-8”

             webView.loadData(data,"text/html" ,"utf -8");

           }

           });

          

        }

    }

    为程序添加网络访问权限。编写功能清单文件,内容如下:

    <?xml version="1.0" encoding="utf-8"?>

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="com.sharpandroid.webviewdemo1"

          android:versionCode="1"

          android:versionName="1.0">

        <application android:icon="@drawable/icon" android:label="@string/

    app_name">

            <activity android:name=".WebViewActivity1"

                      android:label="@string/app_name">

                <intent-filter>

                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER"

    />

                </intent-filter>

            </activity>

        </application>

        <uses-sdk android:minSdkVersion="7" />

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

    </manifest>

    28.3  WebView浏览网页复杂示例

    准备一个名为index.html的HTML文件,放置到工程的“/assets”目录下。文件中包含三种不同的弹出对话框,供WebChromeClient测试使用,内容如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "

    http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <html xmlns="http://www.w3.org/1999/xhtml">

        <head>

            <meta http-equiv="Content-Type" content="text/html; charset=

    gb2312" />

            <title>测试JavaScript的三种不同对话框</title>

            <script language="JavaScript">

                function alertFun()

                {

                    alert("Alert警告对话框!-你好吗?");

                }

                function confirmFun()

                {

                    if(confirm("访问搜狐?"))

                    {

                        location.href="http://www.sohu.com";

                    }

                    else

                    {

                        alert("取消访问!");

                    }

                }

                function promptFun()

                {

                    var word =prompt("Prompt对话框","请输入你最想说的一句话:");

                    if(word)

                    {

                        alert("你说:"+ word)

                    }else{

                    alert("呵呵,你沉默了!");

                    }

                }

            </script>

        </head>

        <body>

            <p>三种对话框示例</p>

            <p>Alert对话框-你好啊!</p>

            <p>

              <input type="submit" name="Submit" value="按钮1" onclick="

    alertFun()" />

            </p>

            <p>Confirm对话框-是否访问搜狐!</p>

            <p>

              <input type="submit" name="Submit2" value="按钮2" onclick=

    "confirmFun()" />

            </p>

            <p>Prompt对话框-告诉我你想说的话!</p>

            <p>

              <input type="submit" name="Submit3" value="按钮3" onclick=

    "promptFun()" />

            </p>

        </body>

    </html>

    编写strings.xml文件:

    <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="app_name">WebView示例2</string>

        <string name="hello">请输入网址:</string>

        <string name="button">LoadUrl</string>

    </resources>

    编写main.xml文件:

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

        <TextView 

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="@string/hello"/>

           

        <EditText

            android:id="@+id/path"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="file:///android_asset/index.html"/>

       <Button

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="@string/button"

            android:id="@+id/button"/> 

        <WebView

            android:layout_height="fill_parent"

            android:layout_width="fill_parent"

            android:id="@+id/webview"/>

    </LinearLayout>

    编写prompt_view.xml文件:

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:gravity="center_horizontal"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        >

        <TextView

            android:id="@+id/text"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"/>

        <EditText

            android:id="@+id/edit"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:selectAllOnFocus="true"

            android:scrollHorizontally="true"/>

    </LinearLayout>

    编写WebViewActivity2.java:

    package com.sharpandroid.webviewdemo2;

     

    import android.app.Activity;

    import android.app.AlertDialog;

    import android.app.AlertDialog.Builder;

    import android.content.DialogInterface;

    import android.os.Bundle;

    import android.view.LayoutInflater;

    import android.view.View;

    import android.view.View.OnClickListener;

    import android.webkit.JsPromptResult;

    import android.webkit.JsResult;

    import android.webkit.WebChromeClient;

    import android.webkit.WebSettings;

    import android.webkit.WebView;

    import android.widget.Button;

    import android.widget.EditText;

    import android.widget.TextView;

     

    public class WebViewActivity2 extends Activity {

        private Button mButton;

        private EditText mEditText;

        private WebView mWebView;

     

        @Override

        public void onCreate(Bundle savedInstanceState)

        {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

            mButton = (Button) findViewById(R.id.button);

            mEditText = (EditText) findViewById(R.id.path);

            mWebView = (WebView) findViewById(R.id.webview);

           

            //获取WebSettings对象

            WebSettings webSettings = mWebView.getSettings(); 

            //设置支持JavaScript脚本

            webSettings.setJavaScriptEnabled(true);

            //设置可以访问文件

            webSettings.setAllowFileAccess(true);

            //设置支持缩放

            webSettings.setBuiltInZoomControls(true);

           

            //设置WebChromeClient,对网页中 JavaScript代码的各种事件进行处理

            mWebView.setWebChromeClient(new MyWebChromeClient());

           

            //按钮单击事件监听

            mButton.setOnClickListener(new OnClickListener()

            {

                public void onClick(View v)

                {

                    //取得编辑框中我们输入的内容

                String url = mEditText.getText().toString();

                mWebView.loadUrl(url);

                }

            });

        }

     

        class MyWebChromeClient extends WebChromeClient {

            @Override

            // 处理javascript中的alert

            public boolean onJsAlert(WebView view, String url, String message,

                    final JsResult result) {

                // 构建一个Builder来显示网页中的对话框

                new Builder(WebViewActivity2.this).setTitle("Alert对话框")

                .setMessage(message)

                // android.R.string.ok来自系统自带的文本,内容为“确定”

                .setPositiveButton(android.R.string.ok,

                    new AlertDialog.OnClickListener() {

                        public void onClick(DialogInterface dialog,int which) {

                            // 单击确定按钮之后,继续执行网页中的操作

                            result.confirm();

                        }

                    })

                .setCancelable(false).show();

                return true;

            };

     

            @Override

            // 处理javascript中的confirm

            public boolean onJsConfirm(WebView view, String url, String

    message,

                    final JsResult result) {

                new Builder(WebViewActivity2.this)

                .setTitle("Confirm对话框")

                .setMessage(message)

                .setPositiveButton(android.R.string.ok,

                    new AlertDialog.OnClickListener() {

                        public void onClick(DialogInterface dialog,int which) {

                            result.confirm();

                        }

                    })

                    // android.R.string.ok来自系统自带的文本,内容为“取消”

                    .setNegativeButton(android.R.string.cancel,

                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int

    which) {

                                result.cancel();

                            }

                        })

                .setCancelable(false)

                .show();

                return true;

            };

     

            @Override

            // 处理javascript中的prompt

            // message为网页中对话框的提示内容

            // defaultValue在没有输入时,默认显示的内容

            public boolean onJsPrompt(WebView view, String url, String message,

                    String defaultValue, final JsPromptResult result) {

                //获得一个LayoutInflater对象factory,该对象可以将指定的xml布局文

    件生成相应的对象

                final LayoutInflater factory = LayoutInflater.from

    (WebViewActivity2.this);

                // 获取自定义的带输入框的对话框由TextView和EditText构成

                final View dialogView = factory.inflate(R.layout.prompt_view,

    null);

                // 设置TextView对应网页中的提示信息

                ((TextView) dialogView.findViewById(R.id.text))

                        .setText(message);

                //为dialogView上的edit输入框 设置来自网页的默认文字

                ((EditText) dialogView.findViewById(R.id.edit))

                        .setText(defaultValue);

     

                new Builder(WebViewActivity2.this)

                .setTitle("Prompt对话框")

                //将前面获取的diaoView这个视图文件添加到对话框上面

                .setView(dialogView)

                .setPositiveButton(android.R.string.ok,

                    new AlertDialog.OnClickListener() {

                        public void onClick(DialogInterface dialog,int which){

                            // 单击确定之后,取得输入的值,传给网页处理

                            String value = ((EditText) dialogView.findViewById

    (R.id.edit)).getText().toString();

                            result.confirm(value);

                        }

                    })

                .setNegativeButton(android.R.string.cancel,

                    new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog,intwhich){

                            result.cancel();

                        }

                    })

                .show();

                return true;

            };

        }

    }

    由于在工程中需要访问Internet,因此,添加访问网络权限,编写功能清单文件:

    <?xml version="1.0" encoding="utf-8"?>

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="com.sharpandroid.webviewdemo2"

          android:versionCode="1"

          android:versionName="1.0">

        <application android:icon="@drawable/icon" android:label="@string/

    app_name">

            <activity android:name=".WebViewActivity2"

                      android:label="@string/app_name">

                <intent-filter>

                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER"

    />

                </intent-filter>

            </activity>

        </application>

        <uses-sdk android:minSdkVersion="7" />

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

    permission>

    </manifest>

     

    28.4  WebView使用HTML替代Layout做界面

    2.编写网页文件

    在assets目录下新建一个HTML文件phoneui.html,内容如下:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "

    http://www.w3.org/TR/html4/loose.dtd">

    <html>

    <head>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <title>Insert title here</title>

    <script type="text/javascript">

        //该部分用到了JavaScript的一些知识,不熟练的读者可以查阅相关书籍

        //或者可由美工做出来之后,进行必要的修改

       

        function show(jsondata){

        //将传递过来的json数据转换为对象

            var jsonobjs = eval(jsondata);

            //获取下面定义的的表格

            var table = document.getElementById("personTable");

            //遍历上面创建的json对象,将每个对象添加为表格中的一行,其每个属性为一列

            for(var i=0; i<jsonobjs.length; i++){

                //添加一行

                var tr = table.insertRow(table.rows.length);

                //添加三个单元格

                var td1 = tr.insertCell(0);

                var td2 = tr.insertCell(1);

                td2.align = "center";

                var td3 = tr.insertCell(2);

                //设置单元格的内容和属性,

                //其中innerHTML为设置或获取位于对象起始和结束标签内的 HTML

                //jsonobjs[i]为对象数组中的第i个对象

                td1.innerHTML = jsonobjs[i].id;

                td2.innerHTML = jsonobjs[i].name

                //为显示的内容添加超链接。

                //超链接会调用Java代码中的call()方法并且把内容作为参数传递过去

                td3.innerHTML = "<a href='javascript:sharp.call(\""+

    jsonobjs[i].phone +"\")'>"+jsonobjs[i].phone+ "</a>"; ;

            }

        }

    </script>

     

    </head>

    <!--onload指定了当该页面被加载时调用的方法,本例调用了Java代码中的contactlist方

    法--><body bgcolor="#000000" text="#FFFFFF" style="margin:0000"

    onload="javascript:sharp.contactlist()">

        <!-- 定义一个表格,显示数据-->

        <table border="0" width="100%" id="personTable" cellspacing="0"

            <tr>

                <td width="15%">编号</td><td align="center">姓名</td><td

    width="15%">电话</td>

            </tr>

        </table>

    </body>

    </html>

    3.编写main.xml

    <?xml version="1.0" encoding="utf-8"?>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

        android:orientation="vertical"

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        >

    <WebView

        android:layout_width="fill_parent"

        android:layout_height="fill_parent"

        android:id="@+id/webView"

        />

    </LinearLayout>

    4.编写Contact.java

    其代码如下:

    package com.sharpandroid.domain;

     

    public class Contact {

        private Integer id;

        private String name;

        private String phone;

        public Integer getId() {

            return id;

        }

        public void setId(Integer id) {

            this.id = id;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public String getPhone() {

            return phone;

        }

        public void setPhone(String phone) {

            this.phone = phone;

        }

        public Contact(Integer id, String name, String phone) {

            this.id = id;

            this.name = name;

            this.phone = phone;

        }

        public Contact(){}

    }

    5.编写HtmlActivity.Java

    HtmlActivity.java

    package com.sharpandroid.html;

     

    import java.util.ArrayList;

    import java.util.List;

     

    import org.json.JSONArray;

    import org.json.JSONObject;

     

    import android.app.Activity;

    import android.content.Intent;

    import android.net.Uri;

    import android.os.Bundle;

    import android.webkit.WebView;

     

    import com.sharpandroid.domain.Contact;

     

    public class HtmlActivity extends Activity {

         private WebView webView;

        /** Called when the activity is first created. */

        @Override

        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.main);

           

            webView = (WebView)this.findViewById(R.id.webView);//浏览器

            webView.getSettings().setJavaScriptEnabled(true);//支持js

            webView.getSettings().setSaveFormData(false);//不保存表单

            webView.getSettings().setSavePassword(false);//不保存密码

            webView.getSettings().setSupportZoom(false);//不支持放大功能

            webView.addJavascriptInterface(new SharpJavaScript(), "sharp");

    //addJavascriptInterface方法中要绑定的Java对象

     

            webView.loadUrl("file:///android_asset/index.html");

        }

        public class SharpJavaScript{

        public void contactlist(){

            try {

                    String json = buildJson(getContacts());

                    webView.loadUrl("javascript:show('"+ json + "')");//调

    用js的show()方法

                } catch (Exception e) {

                    e.printStackTrace();

                }

        }

       

        public void call(String phone){

        Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+

    phone));

            HtmlActivity.this.startActivity(intent);

        }

        }

       

        //模拟从数据库或者从网络获取数据

        public List<Contact> getContacts(){

        List<Contact> contacts = new ArrayList<Contact>();

        contacts.add(new Contact(1, "张三", "5554"));

        contacts.add(new Contact(2, "李四", "5556"));

        contacts.add(new Contact(3, "王五", "5557"));

        return contacts;

        }

        public String buildJson(List<Contact> contacts) throws Exception{

        JSONArray array = new JSONArray();

        for(Contact contact : contacts){

            JSONObject jsonObject = new JSONObject();

            jsonObject.put("id", contact.getId());

            jsonObject.put("name", contact.getName());

            jsonObject.put("phone", contact.getPhone());

            array.put(jsonObject);

        }

        return array.toString();

        }

    }

    6.添加拨号权限

    功能清单文件如下:

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"

          package="com.sharpandroid.phoneuibyhtml"

          android:versionCode="1"

          android:versionName="1.0">

        <application android:icon="@drawable/icon" android:label="@string/

    app_name">

            <activity android:name=".PhoneActivity"

                      android:label="@string/app_name">

                <intent-filter>

                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />

                </intent-filter>

            </activity>

     

        </application>

        <uses-sdk android:minSdkVersion="7" />

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

    </manifest>

  • 相关阅读:
    Android开发使用Glide获取图片背景色淡绿色解决办法
    Android 获取 View 宽高的常用正确方式,避免为零
    Android之自定义View来接收输入法输入的内容
    FileProvider使用详解(拍照、安装APP、共享文件)
    简明 homebrew
    更优雅地使用命令行
    一篇长文说 git 基础
    chrome 浏览器的使用技巧
    前端学命令行
    cocos 碰撞系统
  • 原文地址:https://www.cnblogs.com/fx2008/p/3132165.html
Copyright © 2011-2022 走看看