布局
<LinearLayout xmlns:android="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(); } }
添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
布局 <LinearLayout xmlns:android="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(); } }
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(); } }
添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
Anr( application not responding) ---- 应用程序无响应
如果 点击了 某个按钮 ,按钮背后干了比较耗时的事儿 , 长时间的没有相应, 并且这个长时间的事儿是运行在主线程的
那么就 会出现ANR现象.
主线程中不能干 耗时的事儿, 主线程不能够被阻塞.
实体类
/** * 解析XML封装的JAVABEAN * <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+",手机号吉凶"; } }
工具类
/** * XML流解析工具类 * @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 { XmlPullParser pullParser = Xml.newPullParser(); pullParser.setInput(in,"UTF-8"); int eventType = pullParser.getEventType(); while(eventType!=XmlPullParser.END_DOCUMENT){ if(eventType==XmlPullParser.START_TAG){ 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 (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return p; } }
布局
<LinearLayout xmlns:android="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.xml"/> <!-- 发送--> <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
/** * 网络请求XML 1.获取用户输入的URL地址 2.判断用户输入是否为空,为空就提示用户 3.不为空就创建子线程 4.创建URL对象new * URL(paht) 5.url.openConnection(); * 6.设置请求方法setRequestMethod("GET"),设置连接超时时间setConnectTimeOut(5000) * 7.获取响应码,判断是否为200,不为200就使用handler发送Error的message * 8.是200,就获取输入流conn.getInputStream() 9.使用Xml.PullParse解析xml,并封装为对象,返回一个对象 * 10.使用handler发送message,messag.what=SUCCESS,message.obj=封装的对象 * 11.主线程handler重写handlMessage方法,判断msg.what 执行更新UI信息或者提示用户错误信息 * * @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,获取XML数据 * * @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.使用Xml.PullParse解析xml,并封装为对象,返回一个对象 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(); } }
布局 <LinearLayout xmlns:android="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 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android: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>
工具类
/** * 解析流的工具类, * 把流解析为字符串 * @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(); } }
本地tomcat服务器提供一个XML文件与图片
<?xml version="1.0" encoding="UTF-8" ?> <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 xmlns:android="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使用的 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="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="@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; } }
工具类
/** * 解析XML * @author 刘楠 * * 2016-2-24下午7:22:52 */ public class NewsClientService { public static List<NewsItems> getNewsInfo(InputStream in) throws XmlPullParserException, IOException { List<NewsItems> list = new ArrayList<NewsItems>(); //XML解析器 XmlPullParser pullParser = Xml.newPullParser(); //设置输入编码 pullParser.setInput(in,"UTF-8"); //获取事件 int eventType = pullParser.getEventType(); //开始解析 NewsItems newsItem=null; while(eventType!=XmlPullParser.END_DOCUMENT){ if(eventType==XmlPullParser.START_TAG){ 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==XmlPullParser.END_TAG){ 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(); //解析XML list=NewsClientService.getNewsInfo(in); } return list; } catch (IOException e) { e.printStackTrace(); } catch (XmlPullParserException e) { e.printStackTrace(); } 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; } } }
本地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 xmlns:android="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="@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(); } }
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.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(); } }
https://github.com/loopj/android-async-http
/** * 登录点击事件 * * @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)); } }); }
/** * 登录点击事件 * * @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)); } }); }
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)); } }
客户端
权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
布局
<LinearLayout xmlns:android="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); } }); } }
/** * 使用异步下载 * 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(); } } }
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(); } } } }
https://github.com/wyouflf/xUtils