这个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);
}
}

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

     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() {
//这里用于解析html代码
}
}).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();
}
});
}
});
}

第二行建立一个字符串用于存放网站的地址,然后调用刚刚创建的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.

守望先锋app(1)的更多相关文章

  1. 守望先锋app(2)

    上次的功能完成了英雄名字.id.头像的下载并使用RecyclerView展示, 所以接下来就是点击每个英雄的caraview就能打开下一个活动进行英雄的介绍.先打开暴雪的官网查看有那些技能.故事.图片 ...

  2. 浅谈《守望先锋》中的 ECS 构架

    https://blog.codingnow.com/2017/06/overwatch_ecs.html 今天读了一篇 <守望先锋>架构设计与网络同步 .这是根据 GDC 2017 上的 ...

  3. Android仿“守望先锋”加载动画

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 效果图 实现思路 画一个小六边形 按效果图位置画七个小六边形 实现一个小六边形的显示与隐藏 ...

  4. 暴雪游戏-守望先锋-FPS

    http://us.battle.net/overwatch/en/    

  5. 守望先锋overwatch美服外服设置方法

    打开:C:\Users\你的用户名\AppData\Roaming\Battle.net\Battle.net.config 替换为下方内容: { "Client": { &quo ...

  6. Python爬取CSDN博客文章

    0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.win ...

  7. VR应用向导,全球Top10 VR应用排行榜

    2016年国际知名产商索尼.三星.HTC.Oculus.YouTube等等都推出了自己的VR设备,与此同时还有自有的VR应用平台,供各位玩家下载应用体验沉浸式VR,当然每个平台的VR应用下载量各不相同 ...

  8. Android开源项目库汇总

    最近做了一个Android开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库,方便移动开发人员便捷的找到自己需要的项目工具等,感兴趣的可以到GitHub上给个star. 抽 ...

  9. 开源分享 Unity3d客户端与C#分布式服务端游戏框架

    很久之前,在博客园写了一篇文章,<分布式网游server的一些想法语言和平台的选择>,当时就有了用C#做网游服务端的想法.写了个Unity3d客户端分布式服务端框架,最近发布了1.0版本, ...

随机推荐

  1. FluentValidation:一个非常受欢迎的,用于构建强类型验证规则的.NET 库

    1. FluentValidation:一个非常受欢迎的,用于构建强类型验证规则的.NET 库 请求参数实体定义: FluentValidation 验证类定义: 过滤器:ActionFilter中O ...

  2. git中常用的操作命令有哪些?常用操作命令归纳

    git中常用的操作命令有哪些?本篇文章就给到大家归纳了一些git中常用操作命令.有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. git开始 全局配置:配置用户名和e-mail地址 1 ...

  3. ABP开发框架前后端开发系列---(15)ABP框架的服务端和客户端缓存的使用

    缓存在一个大型一点的系统里面是必然会涉及到的,合理的使用缓存能够给我们的系统带来更高的响应速度.由于数据提供服务涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发 ...

  4. I/O:FileLock

    FileLock: /* 文件锁定要么是独占的,要么是共享的.共享锁定可阻止其他并发运行的程序获取重叠的 独占锁定,但是允许该程序获取重叠的共享锁定.独占锁定则阻止其他程序获取任一类型的重叠锁 定.一 ...

  5. 【题解】埃及分数-C++

    Description 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数. 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的. 对于一个分数a/ ...

  6. 分布式Streaming Data Processing - Samza

    ​ 现在的主流的互联网应用越来越依赖streaming data来提供用户一些interesting statistics insights.以linkedin为例,最近90天有多少人看过你的link ...

  7. Python常用的标准库以及第三方库

    Python常用的标准库以及第三方库有哪些?   20个必不可少的Python库也是基本的第三方库 读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们 ...

  8. python元组-字典-集合及其内置方法(下)

    列表补充 补充方法 清空列表 clear # clear 清空列表 l = [1, 2, 3, 4, 4] print(l.clear()) # clear没有返回值(None) print(l) # ...

  9. java高并发系列 - 第17天:JUC中的循环栅栏CyclicBarrier常见的6种使用场景及代码示例

    这是java高并发系列第17篇. 本文主要内容: 介绍CyclicBarrier 6个示例介绍CyclicBarrier的使用 对比CyclicBarrier和CountDownLatch Cycli ...

  10. cesium 学习(六) 坐标转换

    cesium 学习(六) 坐标转换 一.前言 在场景中,不管是二维还好还是三维也罢,只要涉及到空间概念都会提到坐标,坐标是让我们理解位置的一个非常有效的东西.有了坐标,我们能很快的确定位置相关关系,但 ...