Android学习系列笔记(四)

##Android基础网络第一天html

01 网络html源码查看器

访问网络须要加Internet权限:
android.permission.INTERNET 

	
使用UrlConnection请求一个url地址获取内容:

		//1.建立一个Url对象
			URL url = new URL(url_str);
		//2.获取一个UrlConnection对象
			HttpURLConnection connection = (HttpURLConnection)url.openConnection();
		//3.为UrlConnection对象设置一些请求的参数,请求方式,链接的超时时间 
			connection.setRequestMethod("GET");//设置请求方式
			connection.setConnectTimeout(1000*10);//设置超时时间
		//4.在获取url请求的数据前须要判断响应码,200 :成功,206:访问部分数据成功   300:跳转或重定向  400:错误 500:服务器异常
			int code = connection.getResponseCode();
			if(code == 200){
		//5.获取有效数据,并将获取的流数据解析成String
				InputStream inputStream = connection.getInputStream();
				String result = StreamUtils.streamToString(inputStream);



注意事项:
	
	1. ANR:application not response 应用无响应; androoid中耗时的操做(请求网络,大文件的拷贝,数据库的操做)须要在子线程中作。
	09-02 01:52:40.711: E/ActivityManager(857): ANR in com.itheima.sourcelook (com.itheima.sourcelook/.MainActivity)

	2. 4.0后网络操做强制在子线程中进行。由于网络访问是耗时的操做,可能会致使ANR
	09-02 01:57:32.879: W/System.err(1789):  android.os.NetworkOnMainThreadException

	3.错误线程调用异常,子线程不可以更新UI(控件的内容)
		09-02 02:02:08.873: W/System.err(1858): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.


	主线程不可以作耗时的操做,网络请求就是耗时的操做须要放到子线程作。子线程不能更新控件的内容(更新Ui)。因此产生了矛盾,解决办法就是使用Handler.

02 消息机制的写法(重要) Handler

使用Handler的步骤:

	1.主线程中建立一个Handler
	private Handler handler = new Handler(){
			public void handleMessage(android.os.Message msg) {
	
	
			};
	};

	2.重写handler的handlermessage方法

	3.子线程中建立一个Message对象,将获取的数据绑定给msg
			Message msg = new Message();
			//另外一种方式:Message msg = Messge.obtain;
			msg.obj = result;
	4.主线程中的handler对象在子线程中将message发送给主线程
			handler.sendMessage(msg);
	
	5.主线程中handlermessage方法接受子线程发来的数据,就能够作更新UI的操做。
			
		
***********主线程
	
//☆☆☆1.在主线程中建立一个Handler对象
private Handler handler = new Handler(){
	//☆☆☆2.重写handler的handlermessage方法,用来接收子线程中发来的消息
	public void handleMessage(android.os.Message msg) {
		//☆☆☆5.接收子线程发送的数据,处理数据。
		Bitmap bitmap  = (Bitmap) msg.obj;
		//☆☆☆6.当前方法属于主线程能够作UI的更新
		//五.获取服务器返回的内容,显示到textview上
		img_pic.setImageBitmap(bitmap);//设置ImageView的图片内容
	};
};

************子线程

		if(code == 200){
			//5.获取有效数据,并将获取的流数据解析成String
					InputStream inputStream = connection.getInputStream();
					
					//将一个读取流转换成一个图片 Drawable , Btimap:位图  ?????
					Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
					
					
					//☆☆☆3.子线中建立一个Message对象,为了携带子线程中获取的数据给主线程。
					Message msg = Message.obtain();//获取一个Message对象,内部实现是:若是以前的Message存在直接返回,不存在建立新的Message返回
					msg.obj = bitmap;//将获取的数据封装到msg中。
					//☆☆☆4.使用handler对象将message发送到主线程。
					handler.sendMessage(msg);
		
					
				}

03 消息机制原理(重要)

有几个主要元素:

1.Message:用来携带子线程中的数据。
2.MessageQueue:用来存放全部子线程发来的Message.
3.Handler:用来在子线程中发送Message,在主线程中接受Message,处理结果
4.Looper:是一个消息循环器,一直循环遍历MessageQueue,从MessageQueue中取一个Message,派发给Handler处理。

原理看资料中的图。

04 网络图片查看器

adb shell+  input text 内容;能够经过将内容输入到手机上的输入框。

	将一个读取流转换成bitmap对象:

	BitmapFactory:能够将文件,读取流,字节数组转换成一个Bitmap对象。
	Bitmap bitmap = BitmapFactory.decodeStream(InputStream in);
	
	imageView.setImageBitmap(bitmap);//设置图片内容

05 常见消息处理api(重要)

面试:子线程必定不能更新UI? SurfaceView :多媒体视频播放 ,能够在子线程中更新UI; Progress(进度)相关的控件:也是能够在子线程中更新Ui;审计机制:activity彻底显示的时候审计机制才会去检测子线程有没有更新Ui.
	

	1.使用activity的runOnUiThread方法更新ui,不管当前线程是不是主线程,都将在主线程执行.
			runOnUiThread(new Runnable() {
				
				[@Override](https://my.oschina.net/u/1162528)
				public void run() {
					tv_simple.setText("我被更新了");
				}
			});

	2.使用handler直接post到主线程,handler须要在主线程建立
				//延迟多少毫米执行runnable。
				mHandler.postDelayed(new Runnable() {
				
				[@Override](https://my.oschina.net/u/1162528)
				public void run() {

					tv_simple.setText("我被更新了");
				}
			}, 1000*5);

		应用场景:广告展现后,作页面跳转。

06 新闻客户端案例(重要) 项目 和 产品

第一次进入新闻客户端须要请求服务器获取新闻数据,作listview的展现,为了第二次再次打开新闻客户端时能快速显示新闻,须要将数据缓存到数据库中,下次打开能够直接去数据库中获取新闻直接作展现。


	1.写布局listview  ok

	2.找到listview,设置条目的点击事件。  ok

	3.获取数据提供给listview作展现。

		3.1:获取本地数据库缓存的新闻数据,让listview显示。若是没有网络不至于显示空界面。
		3.2:请求服务器获取新闻数据,是一个json字符串,须要解析json,封装到list集合中。提供给listview展现。

		public static String newsPath_url = "http://192.168.13.83:8080/itheima74/servlet/GetNewsServlet";
//封装新闻的假数据到list中返回
public static ArrayList<NewsBean> getAllNewsForNetWork(Context context) {
	ArrayList<NewsBean> arrayList = new ArrayList<NewsBean>();
	try{
		//1.请求服务器获取新闻数据
		//获取一个url对象,经过url对象获得一个urlconnnection对象
		URL url = new URL(newsPath_url);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		//设置链接的方式和超时时间
		connection.setRequestMethod("GET");
		connection.setConnectTimeout(10*1000);
		//获取请求响应码
		int code = connection.getResponseCode();
		if(code == 200){
			//获取请求到的流信息
			InputStream inputStream = connection.getInputStream();
			String result = StreamUtils.streamToString(inputStream);
			
			//2.解析获取的新闻数据到List集合中。
			
				JSONObject root_json = new JSONObject(result);//将一个字符串封装成一个json对象。
				JSONArray jsonArray = root_json.getJSONArray("newss");//获取root_json中的newss做为jsonArray对象
				
				for (int i = 0 ;i < jsonArray.length();i++){//循环遍历jsonArray
					JSONObject news_json = jsonArray.getJSONObject(i);//获取一条新闻的json
					
					NewsBean newsBean = new NewsBean();
					
					newsBean. id = news_json.getInt("id");
					newsBean. comment = news_json.getInt("comment");//评论数
					newsBean. type = news_json.getInt("type");//新闻的类型,0 :头条 1 :娱乐 2.体育
					newsBean. time = news_json.getString("time");
					newsBean. des = news_json.getString("des");
					newsBean. title = news_json.getString("title");
					newsBean. news_url = news_json.getString("news_url");
					newsBean. icon_url = news_json.getString("icon_url");
					
					arrayList.add(newsBean);
		
				}

			//3.清楚数据库中旧的数据,将新的数据缓存到数据库中
				new NewsDaoUtils(context).delete();
				new NewsDaoUtils(context).saveNews(arrayList);
		}
		
	}catch (Exception e) {
		e.printStackTrace();
	}
	return arrayList;
}

		3.3: 获取服务端数据成功后,须要缓存到本地数据库,缓存前须要清空本地数据库。

	4.建立一个Adapter继承BaseAdapter,封装4个方法,须要接收获取的新闻数据   ok


	5.将adapter设置给listview。   ok

07 采用smartimageview 显示(开源的小项目)

github : 12306 出名

自定义的控件在布局文件中的引用都须要指定类的完整路径

08 smartimageview 的原理

1.自定义了一个MyImageview类继承了Imageview,添加三个构造方法

2.添加一个setImageUrl方法接受一个图片url
	
3.新建一个子线程去请求url获取图片资源

4.将获取的图片Bitmap经过handler发送给主线程,主线程设置给当前view.

5.在布局中引用MyImageview,须要指定完成的包名路径。

09 get方式提交数据到服务器

10 post方式提交数据到服务器

get方式和post方式的区别:

	1.请求的URL地址不一样:
		post:"http://192.168.13.83:8080/itheima74/servlet/LoginServlet"
		get:http://192.168.13.83:8080/itheima74/servlet/LoginServlet?username=root&pwd=123

	2.请求头不一样:
		****post方式多了几个请求头:Content-Length   Cache-Control  Origin

		openConnection.setRequestProperty("Content-Length", body.length()+"");
		openConnection.setRequestProperty("Cache-Control", "max-age=0");
		openConnection.setRequestProperty("Origin", "http://192.168.13.83:8080");

		****post方式还多了请求的内容:username=root&pwd=123

			//设置UrlConnection能够写请求的内容
		openConnection.setDoOutput(true);
		//获取一个outputstream,并将内容写入该流
		openConnection.getOutputStream().write(body.getBytes());

	3.请求时携带的内容大小不一样
		get:1k 
		post:理论无限制