zoukankan      html  css  js  c++  java
  • 守望先锋app(1)

    这个app就是从守望先锋的官网下载相关的图片、文字、视频然后展示出来。

    第一个功能是英雄介绍,所以先分析一波官网的数据.守望先锋的英雄数据的官方网站是http://ow.blizzard.cn/heroes/,

    这个页面有英雄的头像和名字,如果想要看英雄的详细介绍点击英雄框就行,点击第一个英雄跳转的网址是http://ow.blizzard.cn/heroes/doomfist,点击第二个英雄跳转的网址是http://ow.blizzard.cn/heroes/genji,所以如果以后想要得到英雄的具体介绍在这里还需要得到英雄的id,比如这里的doomfist、genji

    然后右键查看网页源代码

    这里可以看到英雄的名字和头像图片的地址,还有id,所以这样就分析结束了。

    然后是这个活动的布局xml:

       <LinearLayout
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:orientation="vertical">
    
          <android.support.v7.widget.RecyclerView
              android:id="@+id/recycler_view"
              android:layout_width="match_parent"
              android:layout_height="wrap_content" />
    
       </LinearLayout>

    这里使用RecyclerView来作为展示的列表

    然后是RecyclerView的子项的布局

    <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        app:cardCornerRadius="4dp">
    
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
            <ImageView
                android:id="@+id/hero_image_card"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:scaleType="center"
                android:layout_gravity="center_horizontal"/>
    
            <TextView
                android:id="@+id/hero_name_card"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_margin="5dp"
                android:textSize="16sp"/>
        </LinearLayout>
    </android.support.v7.widget.CardView>

    最外层是卡片式的布局然后是一个垂直分布的图片和文字,对应着英雄头像和名字,完成后的效果是这样

    然后最重要的就是下载数据的逻辑了,这里使用的是jsoup对html的解析,筛选出想要的文本和图片视频的地址。

    这里需要添加的库有:

        compile 'org.jsoup:jsoup:1.10.3'
        compile 'com.squareup.okhttp3:okhttp:3.9.0'

    使用okhttp来获取网站的html代码。

    首先建立一个类,存放英雄信息

    public class Hero {
    
        private String imageUrl;//英雄头像图片地址
    
        private String name;//英雄名字
    
        private String heroId;//英雄id
    
    
    
        public Hero(String imageUrl, String name, String heroId) {
            this.imageUrl = imageUrl;
            this.name = name;
            this.heroId = heroId;
        }
    
        public String getUrl() {
            return imageUrl;
        }
    
        public void setUrl(String url) {
            this.imageUrl = url;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getHeroId() {
            return heroId;
        }
    
        public void setHeroId(String heroId) {
            this.heroId = heroId;
        }
    }

    然后在活动中建立一个List用于存放所有英雄的信息

    private List<Hero> heroList = new ArrayList<>();

    然后新建一个类用于发起一条HTTP请求,传入地址,并注册一个回调来处理服务器响应,

    public class HttpUtil {
    
        public static void sendOkHttpRequest(String address, okhttp3.Callback callback){
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder().url(address).build();
            client.newCall(request).enqueue(callback);
        }
    }

    在主活动中这样使用这个类:

     1     private void initHeroes(){
     2         String Url = "http://ow.blizzard.cn/heroes/";
     3         HttpUtil.sendOkHttpRequest(Url, new Callback() {
     4             @Override
     5             public void onResponse(Call call, Response response) throws IOException {
     6                 final String responseText = response.body().string();
     7                 new Thread(new Runnable() {
     8                     @Override
     9                     public void run() {
    10                         //这里用于解析html代码
    11                     }
    12                 }).start();
    13             }
    14 
    15             @Override
    16             public void onFailure(Call call, IOException e) {
    17                 e.printStackTrace();
    18                 runOnUiThread(new Runnable() {
    19                     @Override
    20                     public void run() {
    21                         Toast.makeText(MainActivity.this, "数据获取失败", Toast.LENGTH_SHORT).show();
    22                     }
    23                 });
    24             }
    25         });
    26     }

    第二行建立一个字符串用于存放网站的地址,然后调用刚刚创建的HttpUtil的sendOkHttpRequest方法,传入地址,然后通过实现okhttp3.Callback这个接口获取到html代码并进行解析工作

     final String responseText = response.body().string();

    这是第六行,这个response对象就是服务器返回的数据,这样的写法就是将得到的数据转换成字符串类型,存放在responseText中。

    具体获得的数据就是用浏览器打开该网站,右键查看网页源代码,这样的数据转换成了字符串存放在responseText中,下图就是字符创的具体累人了,然后Jsoup的作用就是采用CSS或类似jquery 选择器(selector)语法来处理HTML文档中的数据。

    然后是具体的解析代码:

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Document doc = Jsoup.parse(responseText);//将String类型的html转换为Document
                            Elements elements1 = doc.select(".portrait"); //读取图片url
                            Elements elements2 = doc.select(".portrait-title");//读取英雄名字
                            Elements elements3 = doc.select(".hero-portrait-detailed");//读取英雄id
                            for (int j = 0; j < elements1.size(); j++) {
                                Hero hero = new Hero(elements1.get(j).attr("src"), elements2.get(j).text(),elements3.get(j).attr("data-hero-id"));
                                heroList.add(hero);
                            }
    ...
                        }
                    }).start();

    首先是使用Jsoup的parse方法将字符串类型的html代码转换成Document类型,然后就是Document的select方法来解析数据。

    这是其中一个英雄的html代码,

    图中的这一段data-hero-id="doomfist"是英雄的id,因为class是hero-portrait-detailed,所以通过这个Elements elements3 = doc.select(".hero-portrait-detailed"),以及elements3.get(j).attr("data-hero-id"),就可以获取到一个英雄的id,这里的elements3获取到的是所有英雄的数据,所以这里使用一个循环以及get()方法得到某一个英雄的信息

    这一段是英雄头像的地址,和上面一样

    这里的英雄名字稍微不一样些,elements2.get(j).text()这样就行。

     整个活动的代码是:

    public class MainActivity extends AppCompatActivity {
    
        private List<Hero> heroList = new ArrayList<>();
        private Handler handler;
        private HeroSelectAdapter heroSelectAdapter;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    
            initHeroes();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    if(msg.what == 1){
                        GridLayoutManager layoutManager = new GridLayoutManager(MainActivity.this,2);
                        recyclerView.setLayoutManager(layoutManager);
                        heroSelectAdapter = new HeroSelectAdapter(heroList);
                        recyclerView.setAdapter(heroSelectAdapter);
                    }
                }
            };
        }
    
        //读取数据
        private void initHeroes(){
            String Url = "http://ow.blizzard.cn/heroes/";
            HttpUtil.sendOkHttpRequest(Url, new Callback() {
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    final String responseText = response.body().string();
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            Document doc = Jsoup.parse(responseText);//将String类型的html转换为Document
                            Elements elements1 = doc.select(".portrait"); //读取图片url
                            Elements elements2 = doc.select(".portrait-title");//读取英雄名字
                            Elements elements3 = doc.select(".hero-portrait-detailed");//读取英雄id
                            for (int j = 0; j < elements1.size(); j++) {
                                Hero hero = new Hero(elements1.get(j).attr("src"), elements2.get(j).text(),elements3.get(j).attr("data-hero-id"));
                                heroList.add(hero);
                            }
                            Message msg = new Message();
                            msg.what = 1;
                            handler.sendMessage(msg);
                        }
                    }).start();
                }
    
                @Override
                public void onFailure(Call call, IOException e) {
                    e.printStackTrace();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(MainActivity.this, "数据获取失败", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            });
        }
    }

    因为解析过程的代码不能放在主线程中,所以这里使用的Handle异步消息处理机制,解析数据结束后发送消息给主线程然后在更新RecyclerView

    最后有一个RecyclerView的适配器的代码

    public class HeroSelectAdapter  extends RecyclerView.Adapter<HeroSelectAdapter.ViewHolder> {
    
        private Context mContext;
    
        private List<Hero> mHero;
    
        static class ViewHolder extends RecyclerView.ViewHolder{
    
            CardView cardView;
            ImageView heroImage;
            TextView heroName;
    
            public ViewHolder(View view){
                super(view);
                cardView = (CardView) view;
                heroImage = (ImageView) view.findViewById(R.id.hero_image_card);
                heroName = (TextView) view.findViewById(R.id.hero_name_card);
            }
        }
    
        public HeroSelectAdapter(List<Hero> HeroList){
            mHero = HeroList;
        }
    
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if(mContext == null){
                mContext = parent.getContext();
            }
            View view = LayoutInflater.from(mContext).inflate(R.layout.hero_select,parent,false);
            final ViewHolder holder = new ViewHolder(view);
            holder.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    int position = holder.getAdapterPosition();
                    Hero hero = mHero.get(position);
                    Intent intent = new Intent(mContext,HeroDetails.class);
                    intent.putExtra(HeroDetails.Hero_NAME, hero.getName());
                    intent.putExtra(HeroDetails.Hero_ID, hero.getHeroId());
                    mContext.startActivity(intent);
                }
            });
            return   holder;
        }
        public void onBindViewHolder(ViewHolder viewHolder, int position) {
            Hero hero = mHero.get(position);
            viewHolder.heroName.setText(hero.getName());
            Glide.with(mContext).load(hero.getUrl()).into(viewHolder.heroImage);
        }
    
        public int getItemCount() {
            return mHero.size();
        }
    }

    onCreateViewHolder这个方法中的代码是处理RecyclerView的点击事件,启动下一个活动,传递的数据是英雄的名字和id.

  • 相关阅读:
    Struts2异常处理配置
    struts2支持的结果类型
    Project facet Java 1.8 is not supported by target runtime Apache Tomcat v7.0.
    net.paoding.analysis.exception.PaodingAnalysisException: dic home should not be a file, but a directory!
    struts.xml路径修改后的web配置
    struts.xml中的配置常量的含义
    Spring实战笔记
    2018第2周日
    新人替代旧人
    Web安全总结摘录
  • 原文地址:https://www.cnblogs.com/xxbbtt/p/7617682.html
Copyright © 2011-2022 走看看