Android_handler_网络请求_img框架

1,Android网络请求

1.1显示互联网的图片

①获取输入的路径

②使用API URL(统一资源定位符)

URL url = new URL(path);

③通过路径打开一个http的连接,打开通道

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

④得到服务器的返回信息

String type = conn.getContentType();//得到服务器返回的数据类型

Int code = comm.getResponseCode()//返回状态码200ok,404找不到,500服务器内部错误

If(code == 200){

//获得服务器输入流

Is = conn.getInputStream();

Bitmap bm = BitmapFactory.decodeStream(is)//通过输入流转换成位图资源

//bitmap就是 Android下的图片对象,默认都是32位图

//decode可以转换图片文件对象,也可以转换资源文件下的图片对象

//设置到对应控件上

iv.setImageBitMap(bitmap);

Is.close();

//但是上面这种写法会报错UnknowHostException,不知道的主机异常

//是因为没有设置权限android.permission.INTERNET

}

//细节问题:

conn.setRequestMethod(“POST”);//设置请求方式,默认为GET

conn.setConnectionTimeout(50000);//设置请求服务器的超时时间,超过就不再等待

conn.getContentLength();//返回服务器资源的长度

流的释放要放到finally里面.

 

1.2在有的模拟器上,上面的代码会运行不了(NetworkOnMainThreadException,网络在主线程的异常)(2.3的版本可以,4.1的版本不可以,因为谷歌不允许可能要花费一段时间的代码在主线程中运行,比如在主线程中休眠10秒钟,也不会允许执行)

简单的说,就是主线程允许阻塞(大多数图形化界面都是一个死循环),

ANR错误:Application not response 应用程序无响应

谷歌设计的用户保护模式,如果主线程等待太长时间,就报 ANR错误,

所以在4.0以后,访问网络的操作,必须写在子线程里

 

1.3,改进版网络图片查看器

通过子线程(匿名内部类,自定义继承Thread,自定义实现runable接口)的方式,请求图片,获取数据.

但是这样会出ViewRootImp$CalledFromWrongThreadException 从错误的线程调用的代码.后面的信息是子线程不能更新ui;

查看LogCat的时候,找自己创建的类中报出的异常.

原因:ui线程(主线程)ui线程的修改,android中为非法的.

只有ui才能修改ui线程中的内容

2,主线程模型:

2.1更新ui,单一主线程,审查机制(在界面可见时,才会审查,如果是界面第一次打开,在加载的时候,是可以让子线程修改ui,相当于此时审查机制还没有启动,子线程可以悄悄的修改,但是如果在界面开启之后想要更新ui就会报错)

2.2子线程想要更新ui:Handler消息处理器,类似主线程的代理人.

在主线程中,google设置了一个message queue消息队列,通过Handler把请求放在消息队列里(MessageQueue),在消息队列里有一个监听器(底层会自动启动):looper,looper获取消息之后,会找到Handler,Handler里有一个handleMessage()方法处理器(要注意的是,Handler是主线程的一个内部类,就是把请求间接的放在主线程中使用)

2.3,执行步骤

①定义一个Handler消息处理器

②通过消息处理器发送消息handler.sendMessage(msg)

Message msg = new Message();//创建一个Message对象

一般开发中用Message.obtain();这个方法底层优化了Message对象,可以重复利用Message对象,减少内存消耗

把需要发送的消息放在msg.obj(Obejct类型的成员变量可以接受一切请求,相当于一个通用型的容器,起到转发信息的作用)

msg.obj = ...........;

looper接收到消息,找到Handler(这一步在代码中没有体现,但是google框架有这一步)

④在创建的Hadler引用指向匿名子类对象

Handler handler = new Hadler(){

//重写handleMessage方法

String text = msg.obj;

//设置ui即可

//不要把super.handleMess(message)删掉了

}

 

Hanlder底层发送消息的流程:

用到的类:Looper,Hanlder,Message,MessageQueue(消息队列,按时间排序)

Looper初始化过程

Activiy中初始化Looper,调用了ThreadLocal 中的get()方法,

>>Looper.prepare(),初始化了Lopper对象,同时初始化了MessageQueue对象,一个Looper对象只会有一个消息队列.

>>Looper.loop();开始轮寻,不断查看消息队列里面的内容,取到msg对象

然后拿msg.target(Handler对象).dispatchMessage()方法进行转发

>>dispatchMessage()里面调用了handlerhandlerMessage(msg)方法,这样就把msg发送到了主线程中,这时候可以重写hanlderMessage(msg)方法,在主线程获取到信息再进行操作

 

Hanlder:发送消息的流程

sendMessage(msg)

>>sendMessageDelayed(msg,0)(第二个参数可以发送延迟信息)

>>sendMessageAtTime(msg,SystemClock.uptimeMillis + delayMissis);

>>enqueueMessage(queue,msg,uptimeMillis):MessageQueue对象方法

在这个方法里,把当前的handler对象中赋值到了我们发送的消息msg里面,同时把meg对象放入到了MessageQueue,通过que

>>

 

图片查看器改进版:

如果网络异常,会抛出SocketXXXXtimeoutException Socket连接失败

//不能在子线程打印Toast,因为它的底层也是用的消息实现的,如果要在子线程中使用Toast打印,后面会讲到

Msg.what = xxx

正确的代码

Msg.what=yyy

错误的代码

通过指定msg.what类型可以在handlerMessage()中区分不同的类型

 

3.练习:网络源码查看器(电脑上可以右击浏览器查看源代码,这里主要是为了练习Android的网络相关API)

配置权限

①定义按钮,图片地址输入框(查看的网址),文本显示框(显示源码)

②找到控件,并且定义单击事件

③单击事件中:获取网址

④创建子线程,重写run方法,调用start()方法

创建URL对象,转换路径

这列可以开启等待框

Try{

URL url = new URL(path)

HttpURLConnection conn = url.openConnection()//打开连接

//设置请求方式,超时时间

Conn.setRequestMethod(“GET”);

Conn.setConnectionTimeOut(5000);

//获得状态吗

Int code = Conn,getResponseCode();

If(code == 200){

//获取服务器连接输入流

InputStream is = conn.getInputStream();

调用转换类,把流信息转换成字符串

//调用Handler方法

Message msg = Message.obtain();

Msg.what=xxx; //让它代表一个数字

Msg.obj=xxxx;

handler.sendMessage(msg);

}

}catch(xxx){

Msg.what=xxx

Msg = Message.obtain();

Msg.obj=xxxx;

}

⑤在handle中重写HandleMessage方法,设置对应的控件文本,并关闭等待框

 

额外:①定义一个能把流中内容转换成字符串的类(用的挺多,提取出来做工具)

定义方法

定义内存输出流

ByteArrayOutPutStream baos  =  new XXX;

Byte()buffer = new byte[1024];

Int len = -1;

While(XXX){

Baos.write(x,x,x);

}

Is.close();

②定义一个Scroll控件来显示文本

③定义一个等待框,定义在子线程中开启,handlerMessage()中关闭,代表已经把msg发送过来了,这时候就可以关闭等待框了

 

4.User-Agent:

conn.setRequestProperty(“User-Agent”,xxxxx)

通过设置User-Agent头信息,可以让服务器识别这是什么浏览器

 

5.中文乱码问题

在模拟器中访问TomCat服务器不能写LocalHost或者127.0.0.1

通过cmd指令中的ifconfig可以查看本机ip,写这个ip地址.

5.1 常见乱码>>>>黑色菱形带问号,utf-8的数据以gb2313gbk读取就会出现这样问题.

解决方法,判断服务器中反馈信息中包含的编码信息,从而设置解码方式

 

6,手机号码归属地案例 解析服务器返回的xml信息

需求:用户输入手机号,点击测试,反馈手机号,归属地,吉凶

EdtiText  Button TextView TextView TextView

TextView中有一个属性,drawableLeft可以通过资源文件在文本框左边显示一个小图标,美化界面

通过手机号,访问网站,观察反馈的信息来解析,获取需要的信息

案例中反馈的是xml文件,可以用xml解析

 

7,天气预报,解析服务器返回的JSON信息

7.1浏览器路径中不支持中文问题,通过URLEncoder编码可以把中文进行转译

URLEncoder.encode(需要转码的数据,被转码数据的编码)

7.2 JSON对象的解析

   通过Android提供的 JSONObject  API  进行解析

JSONObject jsonobject = new JSONObject(json);

//获取到服务器返回的状态信息(如果有的话)

String result = jsonobject.getString(“desc”);

jsonobject.optString(“desc”);

这两个都是获取值的,但是opt不会报异常,返回空字符串

//解析jsonobject的子json

 

JSONObject dataJSON = jsonobject.JSONObject(“data”);

//如果Json中有数组格式的json可以获取数组形式的json

JSONArray jsonarray = dataJSON.JSONArray(“”)

小技巧,带大括号的就是JSON对象,带中括号的就是JSON数组

 

8,新闻客户端

8.1RSS技术:是一种订阅互联网上信息的方式.是一种特殊的xml文件

把新闻xml文件和img放到tomcat服务器

8.2 新闻项目开发流程

MVC模式分包

M:service包新闻信息的业务代码

V:布局文件显示layout

C: MainActivity显示在主页面,就这一个界面

domain,代表业务实体,封装的对象

② 业务bean封装 新闻的item对象

       业务方法 获得所有item对象

一般路径之类的字符串都是在values文件夹下创建config.xml文件,在里面创建对应的键值对,键对应字符串的名称,值对应具体的数值

③其它跟前面差不多,重点是子线程的获取

8.3加载界面的优化显示

ProgressBar 等待旋转标志

标签的visibility属性可以用来设置标签状态,显示,不显示,无效果

TextView SingleLine属性可以控制行数

使用打气筒把xml布局文件转换成view对象

创建ListView适配器显示效果

RelativeLayout中四个边界距离属性(可以参考盒子模型)

 

9,利用开源框架显示效果

www.github.com开源网站

使用自定义的控件,标签名要写全包名

 

附上一个简易的新闻客户端

package com.zzx.news;

import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.zzx.news.domain.MyItem;
import com.zzx.news.other.SmartImageView;
import com.zzx.news.service.NewsService;

public class MainActivity extends Activity {
    
    private List<MyItem> myitem = getNewsMessage();
    private ListView lv_show;
    private View showView;
    private MyAdapter ma;
    private ProgressBar pb_init;
    private Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            pb_init.setVisibility(0x00000004);
            lv_show.setVisibility(0x00000000);
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化需要的组件
        init();
        //设置载入画面
        new Thread(){
            public void run() {
                try {
                    Thread.sleep(3000);
                    Message mes = Message.obtain();
                    handler.sendMessage(mes);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            
        }.start();
     
        lv_show.setAdapter(ma);
    }
    /**
     * 这里做服务器网络信息的获取集合
     */
    public List<MyItem> getNewsMessage() {
        //要通过子线程访问网络
        new Thread(){
            public void run() {
                myitem = NewsService.getNews();
            };
        }.start();
        return myitem;
    }
    /**
     * 初始化控件
     */
    public void init() {
        pb_init = (ProgressBar) findViewById(R.id.pb);
        lv_show = (ListView) findViewById(R.id.showNews);
            ma = new MyAdapter();
    }
    /**
     * 自定义适配器
     * @author msi
     *
     */
    class MyAdapter extends BaseAdapter{
        
        private TextView tv_nt;
        private TextView tv_ns;
        private TextView tv_ne;
        private SmartImageView iv_in;

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView==null){
                convertView = View.inflate(MainActivity.this, R.layout.shonews, null);
            }
            //给对应组件进行赋值
            iv_in = (SmartImageView) convertView.findViewById(R.id.imgnew);
            tv_nt = (TextView) convertView.findViewById(R.id.newsTitle);
            tv_ns = (TextView) convertView.findViewById(R.id.newsMsg);
            tv_ne = (TextView) convertView.findViewById(R.id.newstype);
            //获取集合中的元素
            MyItem mi = myitem.get(position);
            String imgurl = mi.getNewsimg();
            System.out.println(imgurl);
            iv_in.setImageUrl(imgurl);
            tv_nt.setText(mi.getNewstitle());
            tv_ns.setText(mi.getNewsmsg());
            switch (Integer.parseInt(mi.getNewstype())) {
            case 2:
                tv_ne.setText("主题新闻");
                break;

            case 1:
                tv_ne.setText("评论新闻" + mi.getNewscomment());
                break;
                
            case 3:
                tv_ne.setText("视频新闻");
                break;
            }
        
            //用框架进行封装图片
            return convertView;
        }
        @Override
        public int getCount() {
             myitem = getNewsMessage();
            return myitem.size();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        
        
    }
}

业务处理类

package com.zzx.news.service;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;


import android.util.Log;
import android.util.Xml;

import com.zzx.news.domain.MyItem;
/**
 * 新闻信息服务类
 * @author msi
 *
 */
public class NewsService {

    private static int type;
/**
 * 获取新闻信息
 * @return    保存item的集合,返回为null就是没有读取到
 */
    public static List<MyItem> getNews(){
        //定义List集合保存信息
         List<MyItem> myitem = null;
        try {
            //访问网络获取数据
            URL url = new URL("http://192.168.16.80:8080/Android/news.xml");
            //打开网络服务
            HttpURLConnection huc = (HttpURLConnection) url.openConnection();
            //通过输入流解析xml文件
            XmlPullParser xpp = Xml.newPullParser();
            //设置信息
            xpp.setInput(huc.getInputStream(),"utf-8");
            type = 0;
            //創建條目信息
            MyItem my = null;
            //循环遍历获取结果
            while((type = xpp.getEventType())!=XmlPullParser.END_DOCUMENT){
                String name = xpp.getName();
                switch (type) {
                //当解析到开始标签的时候创建集合
                case XmlPullParser.START_DOCUMENT:
                    myitem= new LinkedList<MyItem>();
                    break;
                case XmlPullParser.START_TAG:
                    //根據不同的节点设置不同的信息
                    if("item".equals(name)){
                        my = new MyItem();
                    }else if("title".equals(name)){
                        my.setNewstitle(xpp.nextText());
                    }else if("description".equals(name)){
                        my.setNewsmsg(xpp.nextText());
                    }else if("image".equals(name)){
                        my.setNewsimg(xpp.nextText());
                    }else if("type".equals(name)){
                        my.setNewstype(xpp.nextText());
                    }else if("comment".equals(name)){
                        my.setNewscomment(xpp.nextText());
                    }
                    break;
                case XmlPullParser.END_TAG:
                    //如果标签解析完了,就存放在集合中
                    if("item".equals(name)){
                        myitem.add(my);
                    }
                    break;
                }
                //解析下一个
                xpp.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(myitem);
        //返回集合
        return myitem;
    }

}

 

posted on 2016-05-25 22:40 抓根宝 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/adventurer/p/5528842.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值