守望先锋app

【守望先锋app】曾无好事来相访,赖尔高文一起予。这篇文章主要讲述守望先锋app相关的知识,希望能为你提供帮助。
这个app就是从守望先锋的官网下载相关的图片、文字、视频然后展示出来。
第一个功能是英雄介绍,所以先分析一波官网的数据.守望先锋的英雄数据的官方网站是http://ow.blizzard.cn/heroes/,

守望先锋app

文章图片

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

文章图片

这里可以看到英雄的名字和头像图片的地址,还有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>

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

文章图片

 
然后最重要的就是下载数据的逻辑了,这里使用的是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; //英雄idpublic 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); } }

在主活动中这样使用这个类:
1private void initHeroes(){ 2String Url = "http://ow.blizzard.cn/heroes/"; 3HttpUtil.sendOkHttpRequest(Url, new Callback() { 4@Override 5public void onResponse(Call call, Response response) throws IOException { 6final String responseText = response.body().string(); 7new Thread(new Runnable() { 8@Override 9public void run() { 10//这里用于解析html代码 11} 12}).start(); 13} 14 15@Override 16public void onFailure(Call call, IOException e) { 17e.printStackTrace(); 18runOnUiThread(new Runnable() { 19@Override 20public void run() { 21Toast.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文档中的数据。
守望先锋app

文章图片

然后是具体的解析代码:
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方法来解析数据。
守望先锋app

文章图片

这是其中一个英雄的html代码,
守望先锋app

文章图片

图中的这一段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()方法得到某一个英雄的信息
守望先锋app

文章图片

这一段是英雄头像的地址,和上面一样
守望先锋app

文章图片

这里的英雄名字稍微不一样些,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 HeroSelectAdapterextends 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); } }); returnholder; } 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.

    推荐阅读