星空网 > 软件开发 > 操作系统

安卓第八天笔记

安卓第八天笔记--网络编程二

1.网络图片查看器

 安卓第八天笔记images/loading.gif' data-original="http://images2015.cnblogs.com/blog/710715/201602/710715-20160223224648427-319257914.png" />

  • /**
  •  * 网络图片查看器
  •  * 1.获取输入的URL地址,判断是否为空
  •  * 2.建立子线程,获取URl对象new URL(path)
  •  * 3.打开连接获取HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  •  * 4.设置连接超时时间conn.setConnectionTimeOut(5000)毫秒
  •  * 5.设置请求方式setRequestMethod
  •  * GET或者POST要大写
  •  *  6.获取响应码 conn.getResponseCode()
  •  *  7.判断是不是200,是200就一切正常
  •  * 8.获取conn.getInputStream() ,
  •  * 9.使用BitmapFactory.decode(in),将流转换为Bitmap对象
  •  * 10.使用Message msg = Message.obtain(),
  •  * 11.设置msg.what是int 类型用来表示标识
  •  * 符如SUCCESS,ERROR 与msg.obj为Object类型msg.obj=bitmap,用来传递数据
  •  * 12.handler.sendMessage(msg)发送给主线程的Handler对象
  •  * 13.主线程中Handler handler = newHandler(){
  •  *  重写handleMessage方法 判断msg.what,做主线程中的UI更新或者提示用户错误信息
  •  *  }
  •  *  14.添加网络权限Internet
  •  */

 

布局

<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"   android:orientation="vertical" ><!--输入URL图片地址 -->  <EditText    android:id="@+id/et_path"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:text="http://188.188.3.79:8080/itest/test.png" />  <Button    android:onClick="display"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="显示图片"/>    <ImageView    android:id="@+id/iv_show"    android:layout_width="match_parent"    android:layout_height="match_parent"/> </LinearLayout>

 


Activity

安卓第八天笔记安卓第八天笔记
 /** * 网络图片查看器 * 1.获取输入的URL地址,判断是否为空 * 2.建立子线程,获取URl对象new URL(path) * 3.打开连接获取HttpURLConnection conn = (HttpURLConnection) url.openConnection(); * 4.设置连接超时时间conn.setConnectionTimeOut(5000)毫秒 * 5.设置请求方式setRequestMethod * GET或者POST要大写 * 6.获取响应码 conn.getResponseCode() * 7.判断是不是200,是200就一切正常 * 8.获取conn.getInputStream() , * 9.使用BitmapFactory.decode(in),将流转换为Bitmap对象 * 10.使用Message msg = Message.obtain(), * 11.设置msg.what是int 类型用来表示标识 * 符如SUCCESS,ERROR 与msg.obj为Object类型msg.obj=bitmap,用来传递数据 * 12.handler.sendMessage(msg)发送给主线程的Handler对象 * 13.主线程中Handler handler = newHandler(){ * 重写handleMessage方法 判断msg.what,做主线程中的UI更新或者提示用户错误信息 * } * 14.添加网络权限Internet * * @author 刘楠 * *     2016-2-23下午12:30:41 */public class MainActivity extends Activity {     /*   * 标识 常量   */   protected static final int ERROR = 0;   protected static final int SUCCESS = 1;   /*   * 用户输入的url地址   */   private EditText et_path;   /*   * 显示图片   */   private ImageView iv_show;     /*   * Handler 处理   */   private Handler handler;   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     /*     * 用户输入的url地址     */     et_path = (EditText) findViewById(R.id.et_path);     /*     * 显示图片     */     iv_show = (ImageView) findViewById(R.id.iv_show);     /**     * 13.主线程中Handler handler = newHandler(){ * 重写handleMessage方法 判断msg.what,做主线程中的UI更新或者提示用户错误信息 * }     */     handler = new Handler(){              @Override       public void handleMessage(Message msg) {          switch (msg.what) {          case SUCCESS:                       iv_show.setImageBitmap((Bitmap)msg.obj);            break;          case ERROR:            Toast.makeText(MainActivity.this, "网络连接超里", Toast.LENGTH_SHORT).show();            break;          }       }     };       }   /**   * 显示图片的按键 获取用户输入的URL, 并显示在下方   *   * @param v   *      按键display   */   public void display(View v) {     // *1.获取输入的URL地址,判断是否为空     final String path = et_path.getText().toString().trim();         if(TextUtils.isEmpty(path)){       Toast.makeText(this, "输入的url路径不能为空", Toast.LENGTH_SHORT).show();       return ;     }     // * 2.建立子线程,获取URl对象new URL(path)     new Thread(new Runnable() {              @Override       public void run() {                   try {            // * 3.打开连接获取HttpURLConnection conn = (HttpURLConnection)            URL url = new URL(path);            // url.openConnection();            HttpURLConnection conn= (HttpURLConnection) url.openConnection();                       // * 4.设置连接超时时间conn.setConnectionTimeOut(5000)毫秒            conn.setConnectTimeout(5000);                       // * 5.设置请求方式setRequestMethod GET或者POST要大写            conn.setRequestMethod("GET");                       // * 6.获取响应码 conn.getResponseCode()            int code = conn.getResponseCode();                       // * 7.判断是不是200,是200就一切正常            if(code==200){            // * 8.获取conn.getInputStream() ,              InputStream in = conn.getInputStream();            // * 9.使用BitmapFactory.decodeStream(in),将流转换为Bitmap对象              Bitmap bitmap = BitmapFactory.decodeStream(in);                         // * 10.使用Message msg = Message.obtain(),              Message msg = Message.obtain();                         // * 11.设置msg.what是int 类型用来表示标识 符如SUCCESS,ERROR              msg.what=SUCCESS;                         // 与msg.obj为Object类型msg.obj=bitmap,用来传递数据              msg.obj=bitmap;                         // * 12.handler.sendMessage(msg)发送给主线程的Handler对象              handler.sendMessage(msg);                         }else{              sendError();            }          } catch (MalformedURLException e) {            e.printStackTrace();            sendError();                   } catch (ProtocolException e) {            e.printStackTrace();            sendError();                     } catch (IOException e) {            e.printStackTrace();            sendError();                     }       }        private void sendError() {          Message msg = Message.obtain();                   // * 11.设置msg.what是int 类型用来表示标识 符如SUCCESS,ERROR            msg.what=ERROR;          // * 12.handler.sendMessage(msg)发送给主线程的Handler对象            handler.sendMessage(msg);       }         }).start();   }}

View Code

 

 

添加网络权限

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

 


 

2.HTMLView查看

 安卓第八天笔记

布局<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"><!--用户输入的URL -->  <EditText    android:id="@+id/et_path"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="http://188.188.3.79:8080/"/>  <Button    android:id="@+id/btn_show"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="显示"/>    <ScrollView     android:layout_width="match_parent"    android:layout_height="match_parent">    <!-- 显示结果 -->    <TextView      android:id="@+id/tv_result"      android:layout_width="match_parent"      android:layout_height="match_parent"/>      </ScrollView> </LinearLayout>

 

流转换工具类

 

安卓第八天笔记安卓第八天笔记
/** * 将流转换为字符的工具类   * @author 刘楠 * * 2016-2-23下午1:12:45 */public class StreamUtils {   public static String decode(InputStream in) throws IOException {       ByteArrayOutputStream baos = new ByteArrayOutputStream();         int len =0;         byte [] buf = new byte[1024];         while((len=in.read(buf))!=-1){       baos.write(buf, 0, len);     }     in.close();     baos.close();         return baos.toString();   } }

View Code

 


Activitty

 

 

安卓第八天笔记安卓第八天笔记
/** * HTML查看器 * 步骤: * 1.获取用户输入的url * 2.判断是否为空 * 3.建立子线程 * 4.建立url对象 * 5. 建立HttpURLConnection连接 * 6.设置请求方式,与连接超时 * 7.获取响应码 * 8.判断是否为200 * 9.获取输入流 * 10.解析为字符串 * 11.handler发送message * 12.主线程中的Handler做更新UI的操作 * @author 刘楠 * * 2016-2-23下午1:50:31 */public class MainActivity extends Activity implements OnClickListener {     protected static final int ERROR = 0;   protected static final int SUCCESS = 1;   /*   * 用户输入的URL   */   private EditText et_path;     /*   * 输入完成后点击的按键   */   private Button btn_show;     /*   * 结果显示   */   private TextView tv_result;   /*   * 消息处理   */   private Handler handler;   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     /*     * 用户输入的URL     */     et_path = (EditText) findViewById(R.id.et_path);         /*     * 输入完成后点击的按键     */     btn_show = (Button) findViewById(R.id.btn_show);          btn_show.setOnClickListener(this);         /*     * 结果显示     */     tv_result = (TextView) findViewById(R.id.tv_result);     /*     * 消息处理     */     handler = new Handler(){        @Override       public void handleMessage(Message msg) {          //判断msg.what          switch (msg.what) {          case SUCCESS:            //成功就处理数据            tv_result.setText(msg.obj.toString());            break;          case ERROR:            //失败就提示用户失败            Toast.makeText(MainActivity.this, "网络连接超时", Toast.LENGTH_SHORT).show();            break;          }                 }     };   }   /**   * 单击事件**   */   @Override   public void onClick(View v) {   switch (v.getId()) {   case R.id.btn_show:     display();     break;   }       }   /**   * 显示图片的方法单击事件   */   private void display() {     //1.获取用户输入的url     final String path = et_path.getText().toString().trim();         //2.判断是否为空         if(TextUtils.isEmpty(path)){       Toast.makeText(this, "url不能为空", Toast.LENGTH_SHORT).show();       return;     }     //3.建立子线程     new Thread(new Runnable() {              @Override       public void run() {                   try {            //4.建立url对象            URL url = new URL(path);                       //5. 建立HttpURLConnection连接            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            //6.设置请求方式,与连接超时            conn.setRequestMethod("GET");            conn.setConnectTimeout(5000);                       //7.获取响应码            int code = conn.getResponseCode();                       //8.判断是否为200            if(code==200){              //9.获取输入流              InputStream in = conn.getInputStream();              //10.解析为字符串              String data = StreamUtils.decode(in);                            //是200表示成功 设置成功消息              Message msg = Message.obtain();              //设置成功标识              msg.what=SUCCESS;              //传递数据              msg.obj=data;              //发送消息              handler.sendMessage(msg);            }else{              //发送错误消息              sendError();            }                     } catch (MalformedURLException e) {            e.printStackTrace();            //发送错误消息            sendError();          } catch (IOException e) {            e.printStackTrace();            //发送错误消息            sendError();          }                         }        private void sendError() {          //错误发送错误消息          Message msg = Message.obtain();          //设置错误标识          msg.what=ERROR;                   //发送消息          handler.sendMessage(msg);       }     }  ).start();           }}

View Code

添加网络权限

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

 


 

 

3.ANR现象:

Anr( application not responding) ---- 应用程序无响应

 

如果 点击了 某个按钮 ,按钮背后干了比较耗时的事儿 , 长时间的没有相应, 并且这个长时间的事儿是运行在主线程的

那么就 会出现ANR现象.

 

主线程中不能干 耗时的事儿, 主线程不能够被阻塞.

 

 

4. 手机号码吉凶测试(

 安卓第八天笔记

实体类

 

/** * 解析<phones><phone type="huawei">   <phoneNum>13410110407</phoneNum>   <address>广东深圳移动</address>   <phoneJx>大凶之兆,多多拜神</phoneJx></phone></phones>

 

    

安卓第八天笔记安卓第八天笔记
 * @author 刘楠 * * 2016-2-23下午6:37:28 */public class Phone {   /*   * 手机类型   */   private String type;   /*   * 手机 号码   */   private String phoneNum;   /*   * 归属地   */   private String address;   /*   * 手机号吉凶   */   private String phoneJx;         /*   * Getter与Setter方法   */   public String getType() {     return type;   }   public void setType(String type) {     this.type = type;   }   public String getPhoneNum() {     return phoneNum;   }   public void setPhoneNum(String phoneNum) {     this.phoneNum = phoneNum;   }   public String getAddress() {     return address;   }   public void setAddress(String address) {     this.address = address;   }   public String getPhoneJx() {     return phoneJx;   }   public void setPhoneJx(String phoneJx) {     this.phoneJx = phoneJx;   }     public String show(){     return "手机号码:"+this.phoneNum+",手机类型:"+this.type+",归属地:"+this.address+",手机号吉凶";   } }

View Code

 


 

工具类

 /** * @author 刘楠 * * 2016-2-23下午6:40:31 */public class StreamUtils {     /**   * 获取URLConnection的InputStream   * @param in 输入流   * @return 返回一个phone对象   */   public static Phone decode(InputStream in){         Phone p = new Phone();     try {       = "UTF-8");       int eventType = pullParser.getEventType();              while(eventType!=if(eventType==if("phone".equals(pullParser.getName())){              String type = pullParser.getAttributeValue(null, "type");              p.setType(type);            }else if("phoneNum".equals(pullParser.getName())){              String phoneNum = pullParser.nextText();              p.setPhoneNum(phoneNum);            }else if("address".equals(pullParser.getName())){              String address = pullParser.nextText();              p.setAddress(address);                         }else if("phoneJx".equals(pullParser.getName())){              String phoneJx = pullParser.nextText();              p.setPhoneJx(phoneJx);            }                     }             eventType=pullParser.next();       }              in.close();                  } catch (catch (IOException e) {       e.printStackTrace();     }         return p;       } } 

 


布局

<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"><!--用户输入的URL -->  <EditText    android:id="@+id/et_path"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:hint="请输入URL"    android:text="http://188.188.3.79:8080/itest/phone./>   <!-- 发送-->  <Button    android:onClick="send"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="请求"/>    <TextView    android:id="@+id/tv_result"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  </LinearLayout>

 


 

Activity

安卓第八天笔记安卓第八天笔记
 /** * 网络请求@author 刘楠 * *     2016-2-23下午6:31:27 */public class MainActivity extends Activity {   /*   * 标识符常量   */   protected static final int SUCCESS = 0;   protected static final int ERROR = 1;   /*   * 用户输入的URL   */   private EditText et_path;   /*   * 显示结果   */   private TextView tv_result;   private Handler handler;   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);     et_path = (EditText) findViewById(R.id.et_path);     tv_result = (TextView) findViewById(R.id.tv_result);     handler = new Handler() {       @Override       public void handleMessage(Message msg) {          // 11.主线程handler重写handlMessage方法,判断msg.what 执行更新UI信息或者提示用户错误信息          switch (msg.what) {          case SUCCESS:            Phone phone = (Phone) msg.obj;            tv_result.setText(phone.show());            break;          case ERROR:            Toast.makeText(MainActivity.this, "网络异常",                 Toast.LENGTH_SHORT).show();            break;          }        }     };   }   /**   * 发送用户输入的URL,获取@param v   */   public void send(View v) {     // 1.获取用户输入的URL地址     final String path = et_path.getText().toString().trim();     // 2.判断用户输入是否为空,为空就提示用户     if (TextUtils.isEmpty(path)) {       Toast.makeText(this, "url地址不能为空", Toast.LENGTH_SHORT).show();       return;     }     // 3.不为空就创建子线程     new Thread(new Runnable() {        @Override       public void run() {          try {            // 4.创建URL对象new URL(path)            URL url = new URL(path);            // 5.url.openConnection();            HttpURLConnection conn = (HttpURLConnection) url.openConnection();                       // 6.设置请求方法setRequestMethod("GET"),设置连接超时时间setConnectTimeOut(5000)                 conn.setRequestMethod("GET");            conn.setConnectTimeout(5000);            // 7.获取响应码,判断是否为200,不为200就使用handler发送Error的message            int code = conn.getResponseCode();            if(code==200){              // 8.是200,就获取输入流conn.getInputStream()              InputStream in = conn.getInputStream();                            // 9.使用              Phone phone = StreamUtils.decode(in);              // 10.使用handler发送message,messag.what=SUCCESS,message.obj=封装的对象              Message msg = Message.obtain();              msg.what=SUCCESS;              msg.obj = phone;              handler.sendMessage(msg);            }else{              //发送错误消息              sendErrorMessage();            }                   } catch (MalformedURLException e) {            e.printStackTrace();          } catch (ProtocolException e) {            e.printStackTrace();         } catch (IOException e) {            e.printStackTrace();          }        }       /*        * 发送的消息        */       private void sendErrorMessage() {          Message msg = Message.obtain();          msg.what=ERROR;          handler.sendMessage(msg);       }     }).start();   }}

View Code

 

5.解析JSON

安卓第八天笔记

安卓第八天笔记安卓第八天笔记
 布局<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:gravity="center_horizontal"  android:orientation="vertical" >      <EditText    android:id="@+id/et_city"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:hint="请输入要查寻的城名称"/>     <Button    android:onClick="search"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="查询天气"/>    <TextView    android:id="@+id/tv_result"    android:gravity="center_horizontal"    android:layout_width="match_parent"    android:layout_height="wrap_content" />    <ListView    android:id="@+id/lv"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:divider="#ff0000"    android:dividerHeight="2dp">      </ListView> </LinearLayout>weather_ithem<??><LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >    <TextView    android:id="@+id/fengxiang"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  <TextView    android:id="@+id/fengli"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  <TextView    android:id="@+id/high"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  <TextView    android:id="@+id/type"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  <TextView    android:id="@+id/low"    android:layout_width="match_parent"    android:layout_height="wrap_content"/>  <TextView    android:id="@+id/date"    android:layout_width="match_parent"    android:layout_height="wrap_content"/> </LinearLayout>

View Code

 

工具类

 

/** * 解析流的工具类, * 把流解析为字符串   * @author 刘楠 * * 2016-2-23下午8:18:52 */public class StreamUtils {   public static String decode(InputStream in) throws IOException {     ByteArrayOutputStream baos = new ByteArrayOutputStream();         int len =0;     byte [] buff = new byte[1024];     while((len=in.read(buff))!=-1){       baos.write(buff, 0, len);     }     in.close();     baos.close();     return baos.toString();   } }

 


 

Activity

安卓第八天笔记安卓第八天笔记
 /** * 查询天气预报 * 1.获取输入的城市 * 2.判断是否为空 * 3.获取string中的资源与用户输入的拼接为访问的url * 4.建立HttpURLConnection * 5.设置请求方式与连接超时时间 * 6.获取响应码 * 7.判断是否为200 * 8.是200就,使用自定义的流工具类,将流转换为字符串 * 9.获取DESC判断是否为OK,分别处理 * 10,是OK,继续使用JSON解析 * 11.将数组发给主线程中的handler做处理 * 12.handler做更新UI或者 提示用户错误信息等   * @author 刘楠 * * 2016-2-23下午8:06:08 */public class MainActivity extends Activity {   protected static final int SUCCESS = 0;   protected static final int INVALID_CITY = 1;   protected static final int ERROR = 2;   private static final String TAG = "R.string.weather";   /*   * 用户输入的城市   */   private EditText et_city;   /*   * 容器用于显示结果   */   private ListView lv;   private TextView tv_result;     private BaseAdapter adapter;     /*   * handler   */   private Handler handler;   private ProgressDialog dialog;   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.activity_main);         et_city = (EditText) findViewById(R.id.et_city);         lv = (ListView) findViewById(R.id.lv);         tv_result = (TextView) findViewById(R.id.tv_result);         handler = new Handler(){              @Override       public void handleMessage(Message msg) {          switch (msg.what) {          case SUCCESS:          final JSONArray array =(JSONArray) msg.obj;          //tv_result.setText(array.toString());                   adapter = new BaseAdapter() {                       @Override            public View getView(int position, View convertView, ViewGroup parent) {              View view ;              if(convertView==null){                 view = View.inflate(MainActivity.this, R.layout.weather_item, null);              }else{                 view = convertView;              }              try {                 JSONObject obj = array.getJSONObject(position);                 TextView fengxiang =(TextView) view.findViewById(R.id.fengxiang);                 fengxiang.setText("风向:"+obj.getString("fengxiang"));                 TextView fengli =(TextView) view.findViewById(R.id.fengli);                 fengli.setText("风力:"+obj.getString("fengli"));                 TextView high =(TextView) view.findViewById(R.id.high);                 high.setText("高温:"+obj.getString("high"));                 TextView type =(TextView) view.findViewById(R.id.type);                 type.setText("天气:"+obj.getString("type"));                 TextView low =(TextView) view.findViewById(R.id.low);                 low.setText("低温:"+obj.getString("low"));                 TextView data =(TextView) view.findViewById(R.id.date);                 data.setText("日期:"+obj.getString("data"));                              } catch (JSONException e) {                 e.printStackTrace();              }                            return view;            }                       @Override            public long getItemId(int position) {              // TODO Auto-generated method stub              return position;            }                       @Override            public Object getItem(int position) {              // TODO Auto-generated method stub              return position;            }                       @Override            public int getCount() {              // TODO Auto-generated method stub              return array.length();            }          };          dialog.dismiss();          lv.setAdapter(adapter);            break;          case ERROR:            Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();            break;          case INVALID_CITY:            Toast.makeText(MainActivity.this, "输入的城市 不存在", Toast.LENGTH_SHORT).show();            break;          }       }           };       }     /**   * 查询天气   * @param v 查询按键   */   public void search(View v){     //获取用户化输入的城市     final String city = et_city.getText().toString().trim();         if(TextUtils.isEmpty(city)){       Toast.makeText(this, "城市不能为空", Toast.LENGTH_SHORT).show();       return;     }     System.out.println(city);     dialog = ProgressDialog.show(MainActivity.this, "努力加载", "请稍后..........");     new Thread(new Runnable() {                    @Override       public void run() {          try {            //请求路径            String path=getResources().getString(R.string.weather);                     Log.i(TAG, path);            //建立URL            URL url = new URL(path+URLEncoder.encode(city, "UTF-8"));            //打开连接            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            //设置主求方式与连接超时时间            conn.setRequestMethod("GET");            conn.setConnectTimeout(5000);                       //获取响应码            int code = conn.getResponseCode();            //判断是否为成功            if(code==200){              //获取输入流              InputStream in = conn.getInputStream();                            String data = StreamUtils.decode(in);              JSONObject dataObj = new JSONObject(data);              String desc = dataObj.getString("desc");              Log.i(TAG, desc);              if("ok".equalsIgnoreCase(desc)){                                                 /**                 * {"desc":"OK",                 * "status":1000,                 * "data":{"wendu":"13","ganmao":"天气较凉,较易发生感冒,请适当增加衣服。体质较弱的朋友尤其应该注意防护。",                 * "forecast":                 * [{"fengxiang":"无持续风向","fengli":"微风级","high":"高温 15℃","type":"小雨","low":"低温 11℃","date":"23日星期二"},                 * {"fengxiang":"无持续风向","fengli":"微风级","high":"高温 15℃","type":"阴","low":"低温 12℃","date":"24日星期三"},                 * {"fengxiang":"无持续风向","fengli":"微风级","high":"高温 16℃","type":"小雨","low":"低温 12℃","date":"25日星期四"},                 * {"fengxiang":"无持续风向","fengli":"微风级","high":"高温 17℃","type":"阴","low":"低温 13℃","date":"26日星期五"},                 * {"fengxiang":"无持续风向","fengli":"微风级","high":"高温 18℃","type":"阴","low":"低温 13℃","date":"27日星期六"}],                 * "yesterday":{"fl":"微风","fx":"无持续风向","high":"高温 21℃","type":"多云","low":"低温 16℃","date":"22日星期一"},"aqi":"28","city":"深圳"}}                 */                 //获取data:每一天的信息                 JSONObject dataJsonObject = dataObj.getJSONObject("data");                 //获取一周的数据                 JSONArray array = dataJsonObject.getJSONArray("forecast");                                 Message msg =Message.obtain();                 msg.what =SUCCESS;                 msg.obj = array;                 handler.sendMessage(msg);              }else {                 Message msg = Message.obtain();                 msg.what= INVALID_CITY;                 handler.sendMessage(msg);              }                         }else{              //网络异常              sendErrorMessage();                         }                                } catch (MalformedURLException e) {            e.printStackTrace();            sendErrorMessage();            //网络异常          } catch (IOException e) {            e.printStackTrace();            //网络异常            sendErrorMessage();          } catch (JSONException e) {            e.printStackTrace();          }                       }       //发送错误信息       private void sendErrorMessage() {          Message msg = Message.obtain();          msg.what= ERROR;          handler.sendMessage(msg);       }     }).start();       } } 

View Code

 

6.模拟新闻客户端

安卓第八天笔记

本地tomcat服务器提供一个

<??> <channel><item> <title>军报评徐才厚</title>  <description>人死账不消 反腐步不停,支持,威武,顶,有希望了。 </description> <image>http://192.168.1.104:8080/img/a.jpg</image> <type>1</type> <comment>163</comment> </item>   <item> <title>女司机翻车后直奔麻将室</title>  <description>女司机翻车后直奔麻将室,称大难不死手气必红 </description> <image>http://192.168.1.104:8080/img/b.jpg</image> <type>2</type> </item>   <item> <title>小伙当“**”以为陪美女</title>  <description>来源:中国青年网,小伙当“**”以为陪美女,上工后被大妈吓怕 </description> <image>http://192.168.1.104:8080/img/c.jpg</image> <type>3</type> </item>   <item> <title>男子看上女孩背影欲**</title>  <description> 来源:新京报, 看到正脸后放弃仍被捕 </description> <image>http://192.168.1.104:8080/img/d.jpg</image> <type>1</type> <comment>763</comment> </item></channel>

 

添加权限 

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

 

<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:orientation="vertical"  android:layout_height="match_parent"><ListView  android:id="@+id/lv"   android:layout_width="match_parent"  android:layout_height="match_parent">  </ListView>    </LinearLayout>//listView使用的<??><RelativeLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent" ><!--自定义的控件 -->  <com.itheima.newsclient.smartview.MySmartView    android:id="@+id/iv_icon"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="10dp"    android:src='/images/loading.gif' data-original="@drawable/ic_launcher" />  <TextView    android:id="@+id/tv_title"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="10dp"    android:layout_toRightOf="@id/iv_icon"    android:text="标题" />     <TextView    android:id="@+id/tv_desc"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="10dp"    android:layout_below="@id/tv_title"    android:layout_toRightOf="@id/iv_icon"    android:text="内容描述" />     <TextView    android:id="@+id/tv_comm"    android:layout_alignParentRight="true"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:layout_marginLeft="10dp"    android:layout_marginTop="10dp"    android:layout_below="@id/tv_desc"    android:text="评论数" /></RelativeLayout>

实体JAVABEAN

/** * 新闻封装类   * @author 刘楠 * * 2016-2-24下午7:06:45 * <item><title>军报评徐才厚</title><description>人死账不消 反腐步不停,支持,威武,顶,有希望了。</description><image>http://188.188.3.100:8080/img/a.jpg</image><type>1</type><comment>163</comment></item> */public class NewsItems {    private String title;    private String description;      private String imageUrl;    private String type;    private String comment;  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public String getDescription() {    return description;  }  public void setDescription(String description) {    this.description = description;  }  public String getImageUrl() {    return imageUrl;  }  public void setImageUrl(String imageUrl) {    this.imageUrl = imageUrl;  }  public String getType() {    return type;  }  public void setType(String type) {    this.type = type;  }  public String getComment() {    return comment;  }  public void setComment(String comment) {    this.comment = comment;  }}

 

 

工具类

/** * 解析@author 刘楠 * * 2016-2-24下午7:22:52 */public class NewsClientService {  public static List<NewsItems> getNewsInfo(InputStream in) throws <NewsItems> list = new ArrayList<NewsItems>();    //     //设置输入编码    pullParser.setInput(in,"UTF-8");        //获取事件    int eventType = pullParser.getEventType();        //开始解析    NewsItems newsItem=null;    while(eventType!=if(eventType==if("item".equals(pullParser.getName())){            //如果是开始就新对象            newsItem = new NewsItems();          }else if("title".equals(pullParser.getName())){            //设置标题            newsItem.setTitle(pullParser.nextText());          }else if("description".equals(pullParser.getName())){            //设置描述内容            newsItem.setDescription(pullParser.nextText());          }else if("image".equals(pullParser.getName())){            //设置image            newsItem.setImageUrl(pullParser.nextText());                      }else if("type".equals(pullParser.getName())){            //设置类型            newsItem.setType(pullParser.nextText());          }else if("comment".equals(pullParser.getName())){            //设置评论数            newsItem.setComment(pullParser.nextText());          }                            }else if(eventType==if("item".equals(pullParser.getName())){            //添加对象到集合            list.add(newsItem);          }        }                  //移动指针      eventType=pullParser.next();    }            return list;  }}

 

自定义的

/** * 自定义显示地址为path的图片   * @author 刘楠 * * 2016-2-24下午7:58:58 */public class MySmartView extends ImageView {  public MySmartView(Context context) {    super(context);  }  public MySmartView(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);  }  public MySmartView(Context context, AttributeSet attrs) {    super(context, attrs);  }    /*   * 设置图像   */  public void setImage(String url){    ViewAsyncTask viewAsyncTask = new ViewAsyncTask(getContext());        try {      viewAsyncTask.execute(new URL(url));    } catch (MalformedURLException e) {      e.printStackTrace();    }  }      private class ViewAsyncTask extends AsyncTask<URL, Integer, Bitmap>{        private Context mContext;        public ViewAsyncTask(Context mContext){      this.mContext=mContext;          }    @Override    protected Bitmap doInBackground(URL... params) {            try {        HttpURLConnection conn = (HttpURLConnection) params[0].openConnection();        //设置请求方法        conn.setRequestMethod("GET");                conn.setConnectTimeout(5000);                int code = conn.getResponseCode();                if(code==200){          InputStream in = conn.getInputStream();                    Bitmap bitmap = BitmapFactory.decodeStream(in);          return bitmap;        }              } catch (IOException e) {        e.printStackTrace();      }            return null;    }          @Override    protected void onPostExecute(Bitmap result) {      setImageBitmap(result);    }              }    }

 

Activity

/** * 模拟新闻客户端 1. * * @author 刘楠 * *     2016-2-24下午6:54:19 */public class MainActivity extends Activity {  private ListView lv;  private List<NewsItems> list;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    lv = (ListView) findViewById(R.id.lv);        NewsAsyncTask newsAsyncTask = new NewsAsyncTask(this);    try {      newsAsyncTask.execute(new URL(getResources().getString(R.string.path)));    } catch (MalformedURLException e) {      e.printStackTrace();    } catch (NotFoundException e) {      e.printStackTrace();    }  }  private class NewsAsyncTask extends AsyncTask<URL, Integer, List<NewsItems>>{    private List<NewsItems> list = null ;    //对话框    private ProgressDialog pDialog;    //上下文    private Context mContext;    //构造函数    public NewsAsyncTask(Context mContext){      this.mContext = mContext;    }        @Override    protected List<NewsItems> doInBackground(URL... params) {          try {            //获取连接          HttpURLConnection conn = (HttpURLConnection) params[0].openConnection();                    //设置连接连接方法          conn.setRequestMethod("GET");          conn.setConnectTimeout(5000);          //获取响应码          int code = conn.getResponseCode();          if(code == 200){            //获取输入流            InputStream in = conn.getInputStream();            //解析            list=NewsClientService.getNewsInfo(in);          }          return list;        } catch (IOException e) {          e.printStackTrace();        } catch (return null;    }    @Override    protected void onPostExecute(List<NewsItems> result) {      lv.setAdapter(new MyBaseAdapter(result));      //设置对话框消失      pDialog.dismiss();          }    @Override    protected void onPreExecute() {      //初始化对象话进度条      pDialog = new ProgressDialog(MainActivity.this);      //设置标题      pDialog.setTitle("新闻加载中");      //设置内容      pDialog.setMessage("正在加载中........惊喜稍后呈现");      //设置是否可以取消 true可以取消      pDialog.setIndeterminate(true);      //设置风格      pDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);      //设置最大进度      pDialog.setMax(100);      //显示      pDialog.show();    }    @Override    protected void onProgressUpdate(Integer... values) {      //设置时度      pDialog.setProgress(values[0]);          }              }        /**   * ListView 适配器       * @author 刘楠   *   * 2016-2-24下午7:04:25   */  private class MyBaseAdapter extends BaseAdapter {        private static final String TAG = "MyBaseAdapter";    private List<NewsItems> list ;        public MyBaseAdapter(List<NewsItems> list){      this.list=list;    }    @Override    public int getCount() {      return list.size();    }    @Override    public Object getItem(int position) {      return position;    }    @Override    public long getItemId(int position) {      return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {            NewsItems newsItems = list.get(position);      Log.i(TAG, newsItems.getTitle());      View view;      if(convertView==null){        view = View.inflate(MainActivity.this, R.layout.news_items, null);      }else{        view = convertView;      }      //图片      com.itheima.newsclient.smartview.MySmartView iv_icon =(com.itheima.newsclient.smartview.MySmartView) view.findViewById(R.id.iv_icon);            iv_icon.setImage(newsItems.getImageUrl());            //标题      TextView tv_title = (TextView) view.findViewById(R.id.tv_title);      tv_title.setText(newsItems.getTitle());      //描述      TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc);      tv_desc.setText(newsItems.getDescription());      //评论      TextView tv_comm = (TextView) view.findViewById(R.id.tv_comm);            String type = newsItems.getType();            if(type.equals("1")){        tv_comm.setBackgroundColor(Color.RED);        tv_comm.setText("军报"+newsItems.getComment());      }else if(type.equals("2")){        tv_comm.setBackgroundColor(Color.BLUE);        tv_comm.setText("实时"+newsItems.getComment());      }else if(type.equals("3")){        tv_comm.setBackgroundColor(Color.GREEN);        tv_comm.setText("娱乐"+newsItems.getComment());      }else if(type.equals("4")){        tv_comm.setBackgroundColor(Color.GRAY);        tv_comm.setText("生活"+newsItems.getComment());      }                return view;    }  }}

 

7.源生GET与POST请求

本地TOMCAT运行服务端写了一个Servlet

/** * LoginServlet* @Decription 处理登录请求的Servlet * @author 刘楠 * * @time2016-2-22下午9:40:48 */@WebServlet(urlPatterns={"/login"})public class LoginServlet extends HttpServlet {  @SuppressWarnings("deprecation")  public void doGet(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    /*     * 获取用户名与密码并转换为UTF-8     */    String user = request.getParameter("username");    /*String encode = URLEncoder.encode(user,"iso8859-1");    String decode = URLDecoder.decode(encode, "UTF-8");*/    System.out.println("================get===============");    String username =new String(user.getBytes("iso8859-1"),"utf-8");    System.out.println("get用户名:"+username);        String pwd=request.getParameter("password");        String password = new String(pwd.getBytes("iso8859-1"), "UTF-8");    System.out.println("get密码:"+password);        /*     * 这里写死用户名与密码,     * 正常是去数据库查询     */    PrintWriter writer = response.getWriter();        if("admin".equals(username)&& "admin".equals(password)){      writer.write("SUCCESS");          }else{      writer.write("FAILURE");    }                            }  public void doPost(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    System.out.println("================post===============");    request.setCharacterEncoding("UTF-8");    String username = request.getParameter("username");        String password = request.getParameter("password");    System.out.println("post username:"+username+",password: "+password);        if("admin".equals(username) && "admin".equals(password)){      response.getWriter().print("SUCCESS");    }else{      response.getWriter().print("failure");    }  }}

 

安卓第八天笔记安卓第八天笔记

工具类

public class StreamUtils {  public static String decode(InputStream in) throws IOException {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        int len=0;    byte [] buf = new byte[1024];        while((len=in.read(buf))!=-1){      baos.write(buf, 0, len);    }    in.close();    baos.close();    return baos.toString();  }}

布局

<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"   android:orientation="vertical">  <ImageView     android:layout_width="match_parent"    android:layout_height="wrap_content"    android:src='/images/loading.gif' data-original="@drawable/qq"/>    <EditText    android:id="@+id/et_name"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:hint="请输入登录用户名"/>  <EditText    android:id="@+id/et_pwd"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:inputType="textPassword"    android:hint="请输入密码"/>    <Button    android:onClick="login"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="登录"/> <TextView    android:id="@+id/tv_result"    android:layout_width="match_parent"    android:layout_height="wrap_content"/></LinearLayout>

 

Activity

public class MainActivity extends Activity {  protected static final int ERROR = 0;  protected static final int SUCCESS = 1;  /*   * 用户名   */  private EditText et_name;  /*   * 密码   */  private EditText et_pwd;    /*   * 结果   */  private TextView tv_result;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    et_name = (EditText) findViewById(R.id.et_name);    et_pwd = (EditText) findViewById(R.id.et_pwd);        tv_result = (TextView) findViewById(R.id.tv_result);  }    private Handler handler = new Handler(){    public void handleMessage(Message msg) {      switch (msg.what) {      case SUCCESS:        tv_result.setText(msg.obj.toString());        break;      case ERROR:        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();        break;      }    };  };  /**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    new Thread() {      public void run() {        String path = getResources().getString(R.string.path);        try {          path = path + "?username="              + URLEncoder.encode(username, "UTF-8")              + "&password="              + URLEncoder.encode(password, "UTF-8");          //建立连接          URL url = new URL(path);                    //打开连接          HttpURLConnection conn = (HttpURLConnection) url.openConnection();          //设置请求方式与连接超时时间          conn.setRequestMethod("GET");          conn.setConnectTimeout(5000);                    //获取响应码          int code = conn.getResponseCode();          //判断响应异常          if(code==200){            //获取输入            InputStream in = conn.getInputStream();            //解析            String result=StreamUtils.decode(in);            //设置消息            Message msg= Message.obtain();            msg.what=SUCCESS;            msg.obj=result;            //发送消息            handler.sendMessage(msg);                      }else{            sendErrorMessage();          }                            } catch (UnsupportedEncodingException e) {          e.printStackTrace();          sendErrorMessage();        } catch (IOException e) {          e.printStackTrace();          sendErrorMessage();        }      }      private void sendErrorMessage() {        //设置消息        Message msg= Message.obtain();        msg.what=ERROR;        //发送消息        handler.sendMessage(msg);      };    }.start();  }}

 

Post

public class MainActivity extends Activity {  protected static final int ERROR = 0;  protected static final int SUCCESS = 1;  /*   * 用户名   */  private EditText et_name;  /*   * 密码   */  private EditText et_pwd;  /*   * 结果   */  private TextView tv_result;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    et_name = (EditText) findViewById(R.id.et_name);    et_pwd = (EditText) findViewById(R.id.et_pwd);    tv_result = (TextView) findViewById(R.id.tv_result);  }  private Handler handler = new Handler() {    public void handleMessage(Message msg) {      switch (msg.what) {      case SUCCESS:        tv_result.setText(msg.obj.toString());        break;      case ERROR:        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT)            .show();        break;      }    };  };  /**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    new Thread() {      public void run() {        String path = getResources().getString(R.string.path);        try {          String params = "username="              + URLEncoder.encode(username, "UTF-8")              + "&password="              + URLEncoder.encode(password, "UTF-8");          /*           * String params = "username=" + username + "&password=" +           * password;           */          // 建立连接          URL url = new URL(path);          // 打开连接           HttpURLConnection conn = (HttpURLConnection) url              .openConnection();          // 设置请求方式与连接超时时间          conn.setRequestMethod("POST");          conn.setConnectTimeout(5000);          // 设置请求头          // Content-Type: application/x-www-form-urlencoded          // Content-Length: 25          conn.setRequestProperty("Content-Type",              "application/x-www-form-urlencoded");          conn.setRequestProperty("Content-Length", params.length()              + "");          // 设置输出          conn.setDoOutput(true);          // 把参数输出到服务器          OutputStream out = conn.getOutputStream();          out.write(params.getBytes());          // 获取响应码          int code = conn.getResponseCode();          // 判断响应异常          if (code == 200) {            // 获取输入            InputStream in = conn.getInputStream();            // 解析            String result = StreamUtils.decode(in);            // 设置消息            Message msg = Message.obtain();            msg.what = SUCCESS;            msg.obj = result;            // 发送消息            handler.sendMessage(msg);          } else {            sendErrorMessage();          }        } catch (UnsupportedEncodingException e) {          e.printStackTrace();          sendErrorMessage();        } catch (IOException e) {          e.printStackTrace();          sendErrorMessage();        }      }      private void sendErrorMessage() {        // 设置消息        Message msg = Message.obtain();        msg.what = ERROR;        // 发送消息        handler.sendMessage(msg);      };    }.start();  }}

 

8.使用Apache的HttpClient完成

8.1get

public class MainActivity extends Activity {  protected static final int ERROR = 0;  protected static final int SUCCESS = 1;  /*   * 用户名   */  private EditText et_name;  /*   * 密码   */  private EditText et_pwd;    /*   * 结果   */  private TextView tv_result;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    et_name = (EditText) findViewById(R.id.et_name);    et_pwd = (EditText) findViewById(R.id.et_pwd);        tv_result = (TextView) findViewById(R.id.tv_result);  }    private Handler handler = new Handler(){    public void handleMessage(Message msg) {      switch (msg.what) {      case SUCCESS:        tv_result.setText(msg.obj.toString());        break;      case ERROR:        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();        break;      }    };  };  /**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    new Thread() {      public void run() {                          String path = getResources().getString(R.string.path);        try {          path = path + "?username="              + URLEncoder.encode(username, "UTF-8")              + "&password="              + URLEncoder.encode(password, "UTF-8");          HttpClient client = new DefaultHttpClient();           HttpGet httpGet = new HttpGet(path);          //建立获取响应          HttpResponse response = client.execute(httpGet);                    //获取响应码          int code = response.getStatusLine().getStatusCode();          //判断响应异常          if(code==200){            //获取输入            InputStream in = response.getEntity().getContent();            //解析            String result=StreamUtils.decode(in);            //设置消息            Message msg= Message.obtain();            msg.what=SUCCESS;            msg.obj=result;            //发送消息            handler.sendMessage(msg);                      }else{            sendErrorMessage();          }                            } catch (UnsupportedEncodingException e) {          e.printStackTrace();          sendErrorMessage();        } catch (IOException e) {          e.printStackTrace();          sendErrorMessage();        }      }      private void sendErrorMessage() {        //设置消息        Message msg= Message.obtain();        msg.what=ERROR;        //发送消息        handler.sendMessage(msg);      };    }.start();  }}

 

8.2 post

public class MainActivity extends Activity {  protected static final int ERROR = 0;  protected static final int SUCCESS = 1;  /*   * 用户名   */  private EditText et_name;  /*   * 密码   */  private EditText et_pwd;    /*   * 结果   */  private TextView tv_result;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    et_name = (EditText) findViewById(R.id.et_name);    et_pwd = (EditText) findViewById(R.id.et_pwd);        tv_result = (TextView) findViewById(R.id.tv_result);  }    private Handler handler = new Handler(){    public void handleMessage(Message msg) {      switch (msg.what) {      case SUCCESS:        tv_result.setText(msg.obj.toString());        break;      case ERROR:        Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();        break;      }    };  };  /**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    new Thread() {      public void run() {                          String path = getResources().getString(R.string.path);        try {        /*  String params = "username="              + URLEncoder.encode(username, "UTF-8")              + "&password="              + URLEncoder.encode(password, "UTF-8");*/          HttpClient client = new DefaultHttpClient();          HttpPost httpPost = new HttpPost(path);                              List<NameValuePair> list = new ArrayList<NameValuePair>();                    list.add(new BasicNameValuePair("username",username));          list.add(new BasicNameValuePair("password",password));                     httpPost.setEntity(new UrlEncodedFormEntity(list, "UTF-8"));                              //建立获取响应          HttpResponse response = client.execute(httpPost);                    //获取响应码          int code = response.getStatusLine().getStatusCode();          //判断响应异常          if(code==200){            //获取输入            InputStream in = response.getEntity().getContent();            //解析            String result=StreamUtils.decode(in);            //设置消息            Message msg= Message.obtain();            msg.what=SUCCESS;            msg.obj=result;            //发送消息            handler.sendMessage(msg);                      }else{            sendErrorMessage();          }                            } catch (UnsupportedEncodingException e) {          e.printStackTrace();          sendErrorMessage();        } catch (IOException e) {          e.printStackTrace();          sendErrorMessage();        }      }      private void sendErrorMessage() {        //设置消息        Message msg= Message.obtain();        msg.what=ERROR;        //发送消息        handler.sendMessage(msg);      };    }.start();  }}

 

9.使用开源的框架完成

https://github.com/loopj/android-async-http

9.1 get

/**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    String path = getResources().getString(R.string.path);/*    try {      path = path + "?username="          + URLEncoder.encode(username, "UTF-8")          + "&password="          + URLEncoder.encode(password, "UTF-8");    } catch (UnsupportedEncodingException e) {      e.printStackTrace();    }*/    //使用开源框架 https://github.com/loopj/android-async-http        AsyncHttpClient httpClient = new AsyncHttpClient();      /*  httpClient.get(path, new AsyncHttpResponseHandler() {            @Override      public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }            @Override      public void onFailure(int statusCode, Header[] headers,          byte[] responseBody, Throwable error) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));      }    });*/      RequestParams params = new RequestParams();    params.put("username", username);    params.put("password", password);    httpClient.get(path, params, new AsyncHttpResponseHandler() {            @Override      public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }            @Override      public void onFailure(int statusCode, Header[] headers,          byte[] responseBody, Throwable error) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }    });  }

9.2post

  /**   * 登录点击事件   *   * @param v   *      按键   */  public void login(View v) {    final String username = et_name.getText().toString().trim();    final String password = et_pwd.getText().toString().trim();    if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {      Toast.makeText(this, "用户名或者密码不能为空", Toast.LENGTH_SHORT).show();      return;    }    String path = getResources().getString(R.string.path);/*    try {      path = path + "?username="          + URLEncoder.encode(username, "UTF-8")          + "&password="          + URLEncoder.encode(password, "UTF-8");    } catch (UnsupportedEncodingException e) {      e.printStackTrace();    }*/        AsyncHttpClient httpClient = new AsyncHttpClient();      /*  httpClient.get(path, new AsyncHttpResponseHandler() {            @Override      public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }            @Override      public void onFailure(int statusCode, Header[] headers,          byte[] responseBody, Throwable error) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));      }    });*/      RequestParams params = new RequestParams();    params.put("username", username);    params.put("password", password);    httpClient.post(path, params, new AsyncHttpResponseHandler() {            @Override      public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }            @Override      public void onFailure(int statusCode, Header[] headers,          byte[] responseBody, Throwable error) {        tv_result.setText("code"+statusCode+"响应体"+new String(responseBody));              }    });  }

 

10.使用开源框架上传文件

安卓第八天笔记安卓第八天笔记

https://github.com/wyouflf/xUtils

服务器,使用Servlet完成使用Apache的commons-fileupload,commons-io写的文件上传

安卓第八天笔记安卓第八天笔记
public class UploadServlet extends HttpServlet {  public void doGet(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    doPost(request, response);  }  public void doPost(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    try {      //ArrayList<String> list=initList();                  // 获取磁盘文件工厂      DiskFileItemFactory factory = new DiskFileItemFactory();      // 设置初始值      setFactory(factory);      /*       * // 配置初始化值缓冲区 factory.setSizeThreshold(1024 * 1024); // 设置缓冲 区文件       * String bufPath = getServletContext().getRealPath("/temp");       *       * factory.setRepository(new File(bufPath));       */      // 获取上传对象解析器      ServletFileUpload upload = new ServletFileUpload(factory);      // 判断 是不是多部分组成      if (!upload.isMultipartContent(request)) {        request.setAttribute("msg", "表单不是多部分组成,查看enctype");        request.getRequestDispatcher("/upload.jsp").forward(request,            response);        return;      }      // 初始化      setFileUpload(upload);      // 设置 字符编码      /*       * upload.setHeaderEncoding("utf-8"); // 设置单个文件大小       * upload.setFileSizeMax(1024 * 1024 * 5); // 设置总文件大小       * upload.setSizeMax(1024 * 1024 * 20);       *       * // 设置上传** upload.setProgressListener(new ProgressListener() {       *       * public void update(long pBytesRead, long pContentLength, int       * pItems) { System.out.println("已经读:" + pBytesRead + "总共大小 :" +       * pContentLength + "第" + pItems + "个");       *       * } });       */      // 获取请求的列表      List<FileItem> parseRequest = upload.parseRequest(request);      // 遍历      for (FileItem item : parseRequest) {        // 判断 是不是普通表单数据        if (item.isFormField()) {          String fieldname = item.getFieldName();          String fieldValue = item.getString("UTF-8");          System.out.println("表单:" + fieldname + "," + fieldValue);        } else {          // 上传路径          String uploadPath = getServletContext().getRealPath(              "/WEB-INF/upload");          // 获取文件名          String filename = item.getName();          int index=filename.lastIndexOf(".");          String extname=filename.substring(index);          //判断上传的文件是否在上传列表 中          /*if(!list.contains(extname)){            request.setAttribute("msg", "文件类型"+extname+"不在上传的类型中");            request.getRequestDispatcher("/upload.jsp").forward(request,                response);            return;          }*/                    // 获取输入流          InputStream in = item.getInputStream();          filename = UUID.randomUUID().toString().replace("-", "")              + "_" + filename;          System.out.println(filename);          String savePath = genera(uploadPath, filename);          System.out.println(savePath);          //上传文件          uploadFile(in,savePath,filename);          //删除缓存          item.delete();        }        //上传失败的缓冲也清除        item.delete();      }    } catch (FileUploadBase.FileSizeLimitExceededException e) {      request.setAttribute("msg", "单个文件大小超过限制");      request.getRequestDispatcher("/upload.jsp").forward(request,          response);      return;    } catch (FileUploadBase.SizeLimitExceededException e) {      request.setAttribute("msg", "文件总大小超过限制");      request.getRequestDispatcher("/upload.jsp").forward(request,response);      return;    } catch (MyException e) {      request.setAttribute("msg", "文件类型不正确");      request.getRequestDispatcher("/upload.jsp").forward(request,          response);      return;    }catch (Exception e) {      e.printStackTrace();      request.setAttribute("msg", "出错了");      request.getRequestDispatcher("/upload.jsp").forward(request,          response);      return;    }    request.setAttribute("msg", "上传成功");    request.getRequestDispatcher("/upload.jsp").forward(request, response);  }  /**   * 初始化可以上传的文件列表   * @return   */  private ArrayList<String> initList() {   ArrayList<String>  list=new ArrayList<String>();    list.add(".jpg");    list.add(".rar");    list.add(".txt");    list.add(".png");           return list;      }  /**   * 上传文件   * @param in 输入流   * @param savePath 保存路径   * @param filename 文件名称   * @throws Exception   */  private void uploadFile(InputStream in, String savePath, String filename) throws Exception {    File file = new File(savePath, filename);    // 设置输出流    OutputStream out = new FileOutputStream(file);    int len = 0;    byte[] buf = new byte[1024];    while ((len = in.read(buf)) != -1) {      out.write(buf, 0, len);    }    in.close();    out.close();  }  /**   * 使用哈希值,做散列的文件目录   *   * @param uploadPath   * @param filename   * @return   */  private String genera(String uploadPath, String filename) {    System.out.println(uploadPath);    int hashCode = filename.hashCode();    StringBuilder sb = new StringBuilder();    while (hashCode > 0) {      int tmp = hashCode & 0xf;      sb.append("/");      sb.append(tmp + "");      hashCode = hashCode >> 4;    }    System.out.println(sb.toString());    String path = uploadPath + sb.toString();    File file = new File(path);    if (!file.exists()) {      file.mkdirs();    }    return path;  }  /**   * 对象解析器进行初始化   *   * @param upload   */  private void setFileUpload(ServletFileUpload upload) {    // 设置 字符编码    upload.setHeaderEncoding("utf-8");    // 设置单个文件大小    upload.setFileSizeMax(1024 * 1024 * 20);    // 设置总文件大小    upload.setSizeMax(1024 * 1024 * 100);    // 设置上传**    upload.setProgressListener(new ProgressListener() {      public void update(long pBytesRead, long pContentLength, int pItems) {        System.out.println("已经读:" + pBytesRead + "总共大小 :"            + pContentLength + "第" + pItems + "个");      }    });  }  /**   * 为工厂设置初始值   */  private void setFactory(DiskFileItemFactory factory) {    // 配置初始化值缓冲区    factory.setSizeThreshold(1024 * 1024);    // 设置缓冲 区文件    String bufPath = getServletContext().getRealPath("/temp");    factory.setRepository(new File(bufPath));  }}

View Code

 

客户端 

权限

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

 

布局

<LinearLayout ="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <!-- 这里把文件写死了 -->  <EditText    android:id="@+id/et_file"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:hint="请输入要上传的文件路径"    android:text="/mnt/sdcard/gm.mp3" />  <Button    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:onClick="upload"    android:text="上传" />  <ProgressBar    android:id="@+id/pb"    style="?android:attr/progressBarStyleHorizontal"    android:layout_width="match_parent"    android:layout_height="wrap_content" />  <TextView    android:id="@+id/tv_display"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:gravity="center_horizontal" /></LinearLayout>

 

Activity

public class MainActivity extends Activity {  protected static final String TAG = "MainActivity";  /*   * 输入的文件地址   */  private EditText et_file;    /*   * 进度条   */  private ProgressBar pb;  /*   * 显示时度值   */  private TextView tv_display;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    et_file = (EditText) findViewById(R.id.et_file);        pb = (ProgressBar) findViewById(R.id.pb);        tv_display = (TextView) findViewById(R.id.tv_display);  }  /**   * 上传文件   *   * @param v   *      上传按键   */  public void upload(View v) {    //获取输入的文件地址    String str = et_file.getText().toString().trim();    File file = new File(str);    // 使用开源框架 地址https://github.com/wyouflf/xUtils    HttpUtils httpUtils = new HttpUtils();    RequestParams params = new RequestParams();    params.addBodyParameter("file", file);    // 获取上传路径,写在values--strings中    String url = "http://192.168.1.104:8080/MyDay11upload/upload";    Log.i(TAG, url);    // 发送文件    httpUtils.send(HttpMethod.POST, url, params,        new RequestCallBack<String>() {          @Override          public void onFailure(HttpException error, String msg) {            Toast.makeText(MainActivity.this, "上传失败:=====" + msg,                Toast.LENGTH_SHORT).show();          }          @Override          public void onSuccess(ResponseInfo<String> responseInfo) {            Toast.makeText(MainActivity.this, "上传成功:=====",                Toast.LENGTH_SHORT).show();            Header[] headers = responseInfo.getAllHeaders();            for (Header header : headers) {              Log.i(TAG, "key:---->" + header.getName()                  + "values---->" + header.getValue());            }          }          @Override          public void onLoading(long total, long current,              boolean isUploading) {            pb.setMax((int) total);            pb.setProgress((int) current);            tv_display.setText("当前进度:"+current+"  总进度:"+total);          }                            });  }}

 

11.AsyncTask

/** * 使用异步下载 * 1.创建AsyncTaskr子类,并为三个泛型参数指定类型,如果某个泛型参数不需要指定类型则可以指定为Void * 2.根据需要实现AsyncTAsk的方法 * * doInBackground 重写这个方法,后台线程将要完成的任务,该方法可以调用publishProgress(Progresss....values)方法更新任务的进度 * onProExecute():该方法将在后台耗时操作前被调用,通常该方法,用于完成一些初始化准备工作,比如在界面显示初始化进度等 * onPostExcute(Result result) 当doInBackground完成以后,系统会自动调用onPostExecute()方法,并将doInBackground方法的返回值传给该方法 * * 3.调用AsyncTask子类的实例execute(Params..params)开始执行耗时任务 * 注意: * 必须在UI线程中创建AsyncTasck的实例 * 必须在UI线程中调用AsyncTask的execute()方法 * doInBackground,onProExecute,onPostExcute,opProgressUpdate()方法,不应该用程序员代码调用,而是用Android系统负责调用 * 每个AsyncTask只能执行一次,多次调用将会引发异常 * */

 

/** * 使用异步下载 * 1.创建AsyncTaskr子类,并为三个泛型参数指定类型,如果某个泛型参数不需要指定类型则可以指定为Void * 2.根据需要实现AsyncTAsk的方法 * * doInBackground 重写这个方法,后台线程将要完成的任务,该方法可以调用publishProgress(Progresss....values)方法更新任务的进度 * onProExecute():该方法将在后台耗时操作前被调用,通常该方法,用于完成一些初始化准备工作,比如在界面显示初始化进度等 * onPostExcute(Result result) 当doInBackground完成以后,系统会自动调用onPostExecute()方法,并将doInBackground方法的返回值传给该方法 * * 3.调用AsyncTask子类的实例execute(Params..params)开始执行耗时任务 * 注意: * 必须在UI线程中创建AsyncTasck的实例 * 必须在UI线程中调用AsyncTask的execute()方法 * doInBackground,onProExecute,onPostExcute,opProgressUpdate()方法,不应该用程序员代码调用,而是用Android系统负责调用 * 每个AsyncTask只能执行一次,多次调用将会引发异常 * */public class MainActivity extends AppCompatActivity {  /*  用户输入的url   */  private EditText tv_path;  /*   *显示结果   */  private TextView tv_show;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    tv_path = (EditText) findViewById(R.id.tv_path);    tv_show = (TextView) findViewById(R.id.tv_show);  }  /**   * 响应按键点击下载事件   * @param v 当前按键   */  public void download(View v){    String path = tv_path.getText().toString().trim();    if(TextUtils.isEmpty(path)){      Toast.makeText(this,"下载路径不能为空",Toast.LENGTH_SHORT).show();      return;    }    DownloadTask task = new DownloadTask(this);    try {      //开始执行      task.execute(new URL(path));    } catch (MalformedURLException e) {      e.printStackTrace();    }  }  /**   * 可变参数   * 第一个:param 表示传入的参数   * 第二个:progress后台任务成的进度值的类型   * 第三个:Result,返回的类型   *   *   */  private class DownloadTask extends AsyncTask<URL,Integer,String>{    /*    上下文     */    private Context mContext;    /*    进度条     */    private ProgressDialog progressDialog;    /*    定义记录读取的行数     */    private int hasRead = 0;    public DownloadTask(Context context) {      this.mContext = context;    }    @Override    protected String doInBackground(URL... params) {      StringBuilder sb = new StringBuilder();      try {        //打开连接        URLConnection conn = params[0].openConnection();        //开始读读        BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));        String line=null;        //开始读        while((line=br.readLine())!=null){          sb.append(line+"\n");        }        //返回将因被OnPostexecute方法调用接收返回值        return sb.toString();      } catch (IOException e) {        e.printStackTrace();      }      return null;    }    /**     * 初始化操作     */    @Override    protected void onPreExecute() {      progressDialog = new ProgressDialog(mContext);      //设置对话框标题      progressDialog.setTitle("任务正在执行中");      //设置对话显示的内容      progressDialog.setMessage("任务在拼命加载中...请稍后......");      //设置对话框不能用 取消 按键关闭      progressDialog.setCancelable(false);      //设置该进度条最在时度值      progressDialog.setMax(100);      //设置时度条的风格      progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);      //设置是否显示时度条 不确定的是否显示true为不显示,      progressDialog.setIndeterminate(false);      progressDialog.show();    }    @Override    protected void onProgressUpdate(Integer... values) {      tv_show.setText("已经读取====" + values[0] + "=====行");      progressDialog.setProgress(values[0]);    }    /**     * 调用 doInBackground,并接收其返回值     * @param s     */    @Override    protected void onPostExecute(String s) {      //设置显示      tv_show.setText(s);      //进度对话框消失不可见           progressDialog.dismiss();    }  }}

 

 12.多线程断点下载

JAVA实现

安卓第八天笔记安卓第八天笔记
package com.it.download;import java.io.BufferedReader;import java.io.File;import java.io.FileReader;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;/** * 多线程断点下载,续传 * * @Decription TODO * @author 刘楠 * * @time2016-2-25上午12:34:47 */public class DownTask {  // 下载地址  public static String path = "http://192.168.1.104:8080/itest/gm.mp3";  /*   * 线程数   */  public static int threadCount = 5;  /*   * 当前运行的线程数   */  public static int runninThreadCount =threadCount;  public static void main(String[] args) {    // 开始连接网络    try {      URL url = new URL(path);      // 打开网络连接      HttpURLConnection conn = (HttpURLConnection) url.openConnection();      // 设置请求方式与连接超时时间      conn.setRequestMethod("GET");      conn.setConnectTimeout(5000);      // 获取获取码      int code = conn.getResponseCode();      if (code == 200) {        int length = conn.getContentLength();        System.out.println("长度:" + length);        // 在本地创建一个与服务一样大小的文件        String fileName = getFileName(path);        RandomAccessFile raf = new RandomAccessFile(fileName, "rw");        // 设置文件的大小        raf.setLength(length);        raf.close();        // 计算每个线程下载的大小        int blockSize = length % threadCount == 0 ? length            / threadCount : length / threadCount + 1;        //        for (int threadId = 0; threadId < threadCount; threadId++) {          // 计算开始下载的位置与结束下载的文置          int startIndex = threadId * blockSize;          int endIndex = startIndex + blockSize;          if (endIndex >= length) {            endIndex = length;          }          new DownThread(threadId, startIndex, endIndex).start();        }      }    } catch (Exception e) {      e.printStackTrace();    }  }  /**   * 获取文件名称   *   * @param path   *      路径   * @return 返回文件名称   */  public static String getFileName(String path) {    int index = path.lastIndexOf("/");    return path.substring(index + 1);  }  /**   * 下载的线程   *   * @Decription TODO   * @author 刘楠   *   * @time2016-2-25上午12:23:49   */  private static class DownThread extends Thread {    // 线程IP    private int threadId;    // 开始位置    private int startIndex;    // 结束位置    private int endIndex;    private int currentPosition;    public DownThread(int threadId, int startIndex, int endIndex) {      super();      this.threadId = threadId;      this.startIndex = startIndex;      this.endIndex = endIndex;      this.currentPosition = startIndex;    }    @Override    public void run() {      System.out.println("线程:" + threadId + ",==开始下载位置:" + startIndex          + "=========>结束位置:" + endIndex);      // 开始连接网络      try {        URL url = new URL(path);        // 打开连接        HttpURLConnection conn = (HttpURLConnection) url            .openConnection();        // 设置请求方式与连接超时时间        conn.setRequestMethod("GET");        conn.setConnectTimeout(5000);        // 设置请求头,多线程下载,只获取一部分数据        String fileName = getFileName(path);        RandomAccessFile rf = new RandomAccessFile(fileName, "rw");        // 首先确认有没有下载过拿到文件        File fFile = new File(threadId + ".position");        // 判断文件是不是存在,存在就说明下载过        if (fFile.exists()) {          //读取出下载的进度          BufferedReader br = new BufferedReader(new FileReader(fFile));          String readLine = br.readLine();                    currentPosition = Integer.parseInt(readLine);          conn.setRequestProperty("range", "bytes=" + currentPosition              + "-" + endIndex);          rf.seek(currentPosition);          br.close();        } else {          // 说明没有下载过          conn.setRequestProperty("range", "bytes=" + startIndex              + "-" + endIndex);          rf.seek(currentPosition);        }        // 获取获取码部分数据为206        int code = conn.getResponseCode();        if (code == 206) {          InputStream in = conn.getInputStream();          // 设置开始位置          // 开始写放          int len = 0;          byte[] buf = new byte[1024];          while ((len = in.read(buf)) != -1) {            rf.write(buf, 0, len);            // 用来记录当前的下载位置            currentPosition += len;            RandomAccessFile positionFile = new RandomAccessFile(                threadId + ".position", "rwd");            // 写入文件 建立缓存            positionFile.write((currentPosition + "").getBytes());            positionFile.close();          }          rf.close();          in.close();          System.out.println("线程:" + threadId + "下载完成了");          //把下载完成的文件标记为完成          File file = new File(threadId+".position");          file.renameTo(new File(threadId+".position.finished"));          synchronized (DownTask.class) {            //线程数-1            runninThreadCount--;            if(runninThreadCount<=0){              for(int i=0;i<threadCount;i++){                File delFile = new File(i+".position.finished");                //删除                delFile.delete();              }                          }          }        }      } catch (Exception e) {        e.printStackTrace();      }    }  }}

View Code

13.使用开源框架实现多线程下载

https://github.com/wyouflf/xUtils

 

 

 

 

 

 

 

 

 

 

 

 




原标题:安卓第八天笔记

关键词:

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

账号申诉:https://www.goluckyvip.com/tag/3662.html
跨境电商怎么做流程:https://www.goluckyvip.com/tag/36620.html
跨境电商怎么做铺货:https://www.goluckyvip.com/tag/36621.html
跨境电商怎么做推广:https://www.goluckyvip.com/tag/36622.html
跨境电商怎么做账:https://www.goluckyvip.com/tag/36623.html
跨境电商怎样:https://www.goluckyvip.com/tag/36625.html
​TikTok发生了什么?美区增长首次停滞,准入管理力度加大:https://www.kjdsnews.com/a/1836407.html
2024年如何找到在TikTok上发帖的最佳时间:https://www.kjdsnews.com/a/1836408.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流