1. 更新记录:

2021/11/14:

1.更新了数据来源的 api 使用了聚合数据的 新闻 api

2.使用了 TabLayout 代替原来的 textview 组。

2021/11/13:

1.解决下拉刷新出现崩溃的现象。1.更新了数据来源的 api
2.新增设定:下拉若 5s 内没有获取到数据,就停止显示加载栏。

------------------------------------------------------------------------------------------------------

2.先上效果图:

     

图 1                                            图 2

在此先感谢我本次app开发所用的api分享者贴上文章链接 ,各位读者如有需求请移步此链接:

资源 | 分享一个网易新闻的 API - 简书

目前已经更换为聚合数据 api:新闻头条-新闻头条API _API数据接口_API接口调用_API接口平台-聚合数据

3. 总体思路概述:

如图1 和 图 2 app 界面简单,图 1 的最顶端是安卓原生的标题栏,图 2 的最顶端是我自己定义的标题栏,具体代码后面再说。图一标题栏下面是五个 TextView 表示五个板块,再下面是Fragment+ViewPage 的滑动页面,Fragment 里面是 Recyclerview 控件,当滑动页面滑到相应版块时上面的相应的 TextView 会变成浅蓝色。当点击 RecyclerView 里的 item 时可以进入到图二:因为所用的 api 没有返回相应的内容信息,我只好把原网址用 WebView 加载出来了,其实我也尝试过用 Jsoup 爬虫框架爬取图片和相应的信息,但效果不太好,也可能是我不太会用 Jsoup 的原因吧。

已经描述完整个 app 所有模块了,下面进行各个模块的详细说明。

4. APP所用开源库:

  compile 'org.jsoup:jsoup:1.9.2'compile 'com.squareup.okhttp3:okhttp:3.4.1'compile 'com.android.support:recyclerview-v7:24.2.1'compile 'com.android.support:appcompat-v7:24.2.1'compile 'com.android.support.constraint:constraint-layout:1.0.2'compile 'com.github.bumptech.glide:glide:3.7.0'compile 'com.android.support:cardview-v7:24.2.1'compile 'com.yalantis:phoenix:1.2.3'compile 'com.android.support:support-v4:24.2.1'

phonix 这一条是我用的一款下拉刷新开源控件。

glide 高效加载图片用的。

cardview 卡片式布局。

okhttp 网络通信框架。

recyclerview 就不必说了。

主活动界面的 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.example.thinkpad.wenews.MainActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/finance"android:layout_weight="1"android:layout_width="0dp"android:text="财经"android:gravity="center_horizontal"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/movie"android:layout_weight="1"android:layout_width="0dp"android:text="电影"android:gravity="center"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/amusement"android:layout_weight="1"android:layout_width="0dp"android:text="娱乐"android:gravity="center"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/tv"android:layout_weight="1"android:layout_width="0dp"android:text="电视"android:gravity="center"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/headline"android:layout_weight="1"android:layout_width="0dp"android:text="头条"android:gravity="center"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/newsLive"android:layout_weight="1"android:layout_width="0dp"android:text="News"android:gravity="center"android:layout_height="wrap_content" /></LinearLayout><com.yalantis.phoenix.PullToRefreshViewandroid:id="@+id/pull_to_refresh"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.v4.view.ViewPagerandroid:id="@+id/viewpager"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center" />
</com.yalantis.phoenix.PullToRefreshView>
</LinearLayout>

5. 本项目的关键点(ViewPager+fragment) 实现详解

关于 ViewPager+fragment 的模式是本项目的一个关键点:

所以如下将说明我如何利用 ViewPager+Fragment 实现本项目如上所述说的功能:

ViewPager

ViewPager 实际上和我们所熟悉的RecyclerView差不多,需要适配器,一个存储对象的List。

附上ViewPager基础知识学习链接:ViewPager 详解(一)---基本入门_android开发笔记-CSDN博客_安卓viewpager

代码:

package com.example.thinkpad.wenews;import android.app.ProgressDialog;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;import com.yalantis.phoenix.PullToRefreshView;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {ViewPager viewPager;static   List<TextView> tag;List<Fragment> viewList;static   int tagPointer=0;static  ProgressDialog  progressDialog ;PullToRefreshView pullToRefreshView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);progressDialog=new ProgressDialog(MainActivity.this);progressDialog.setMessage("正在加载内容...");viewPager = (ViewPager) findViewById(R.id.viewpager);pullToRefreshView=(PullToRefreshView) findViewById(R.id.pull_to_refresh);viewList = new ArrayList<Fragment>();// 将要分页显示的View装入数组中final  amusementFragment fragment1=new amusementFragment();final financeFragment  fragment2=new financeFragment();final armyFragment fragment3=new armyFragment();final  headlineFragment fragment4=new headlineFragment();final   tvFragment fragment5=new tvFragment();final  newsFragment fragment6=new newsFragment();viewList.add(fragment2);viewList.add(fragment3);viewList.add(fragment1);viewList.add(fragment5);viewList.add(fragment4);viewList.add(fragment6);FragmentManager fragmentManager=getSupportFragmentManager();channelPager pagerAdapter=new channelPager(fragmentManager,viewList,this);viewPager.setAdapter(pagerAdapter);tag=new ArrayList<>();tag.add((TextView)findViewById(R.id.finance));tag.add((TextView)findViewById(R.id.movie));tag.add((TextView)findViewById(R.id.amusement));tag.add((TextView)findViewById(R.id.tv));tag.add((TextView)findViewById(R.id.headline));tag.add((TextView) findViewById(R.id.newsLive));pullToRefreshView.setOnRefreshListener(new PullToRefreshView.OnRefreshListener() {public void onRefresh() {switch (tagPointer){case 0:fragment1.GetNews();break;case 1:fragment2.GetNews();break;case 2:fragment3.GetNews();break;case 3:fragment4.GetNews();break;case 4:fragment5.GetNews();break;case 5:break;}pullToRefreshView.setRefreshing(false);}});}}

在如上代码里:

channelPager pagerAdapter=new channelPager(fragmentManager,viewList,this);是创建了我的ViewPager适配器

在此之前我用 viewList.add(fragment2);在viewList添加几个fragment对象。

5.1 先讲一讲适配器类channelPager

package com.example.thinkpad.wenews;import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.TextView;import java.util.ArrayList;
import java.util.List;/*** Created by thinkpad on 2019/3/3.*/public class channelPager extends FragmentPagerAdapter {List<Fragment> fragmentList=new ArrayList<>();MainActivity mContext;public  channelPager(FragmentManager fm , List<Fragment> list,MainActivity mContext){super(fm);fragmentList=list;this.mContext=mContext;}@Overridepublic Fragment getItem(int position) {Log.d("getItem","good");return fragmentList.get(position);}@Overridepublic int getCount() {return fragmentList!= null ? fragmentList.size() : 0;}@Overridepublic void setPrimaryItem(ViewGroup container, int position, Object object) {super.setPrimaryItem(container, position, object);MainActivity.tagPointer=position;switch (position) {case 0: {MainActivity.tag.get(0).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(0);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;case 1: {MainActivity.tag.get(1).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(1);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;case 2: {MainActivity.tag.get(2).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(2);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;case 3: {MainActivity.tag.get(3).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(3);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;case 4: {MainActivity.tag.get(4).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(4);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;case 5: {MainActivity.tag.get(5).setBackgroundColor(mContext.getResources().getColor(R.color.colorDark));List<TextView> others = new ArrayList<TextView>();others.addAll(MainActivity.tag);others.remove(5);for (TextView textView : others) {textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorWhite));}}break;}}
}

这个类的构造方法有三个参数,FragmentManager,List<Fragment>,Mainacitivity

其中前两个是必须的因为你也可以看到super()调用父类的构造方法里传了参数fm,而List<Fragment>不消说是必须的只有MainActivity因为我需要在这个类里操作UI才特意传的。构造方法后面是两个重载函数,第一个返回固定位置的fragment对象,第二个返回数量。

setPrimaryItem是一个确定当前fragment位置的方法,在这个方法里我完成了让相应版块的TextView变成浅蓝色的功能。具体请看代码。

5.2 下面是Fragement

package com.example.thinkpad.wenews;import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;import org.json.JSONArray;
import org.json.JSONObject;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;public class amusementFragment extends Fragment {private List<NewItem> newItems=new ArrayList<NewItem>();private  RecyclerView recyclerView_amusement;private  NewsAdapter adapter;public amusementFragment() {// Required empty public constructor}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view =inflater.inflate(R.layout.layout_amusement, container, false);recyclerView_amusement=(RecyclerView) view.findViewById(R.id.recyclerview_amusement) ;LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());recyclerView_amusement.setLayoutManager(layoutManager);adapter=new NewsAdapter(newItems);recyclerView_amusement.setAdapter(adapter);
GetNews();return view;}public void GetNews(){if(!MainActivity.progressDialog.isShowing()){MainActivity.progressDialog.show();}HttpUtil.sendOkhttpRequest("https://3g.163.com/touch/reconstruct/article/list/BA10TA81wangning/0-20.html", new Callback() {@Overridepublic void onFailure(Call call, IOException e) {Log.d("error11","获取错误!!!");}@Overridepublic void onResponse(Call call, Response response) throws IOException {Log.d("成功!","12121212");String text=response.body().string();Log.d("response",text);char test[]=text.toCharArray();for(int i=0;i<9;i++)test[i]=' ';test[test.length-1]=' ';Log.d("text",String.valueOf(test));text=String.valueOf(test);parseJSONWithJSONObject(text);}});
}private  void  parseJSONWithJSONObject(String jsonData){try{Log.d("hello","hello");JSONObject jsonObject=new JSONObject(jsonData);Log.d("testtest",jsonObject.toString());final JSONArray array=jsonObject.getJSONArray("BA10TA81wangning");for(int i=1;i<array.length();i++){NewItem one=new NewItem();JSONObject object=array.getJSONObject(i);one.setPictureAddress(object.getString("imgsrc"));one.setTitle(object.getString("title"));one.setContentAddress(object.getString("url"));Log.d("contentadress",one.getContentAddress());if(one.getContentAddress().toCharArray()[0]=='0')//对无用的内容地址object进筛选{Log.d("goodnull","truetrue!+");continue;}Log.d("title12",one.getTitle());Log.d("pic12",one.getPictureAddress());boolean check=false;for(NewItem c:newItems){if(c.getTitle().equals(one.getTitle())){check=true;break;}}if(!check)newItems.add(one);}Log.d("listsize","1234"+" "+newItems.size());getActivity().runOnUiThread(new Runnable() {@Overridepublic void run() {if(MainActivity.progressDialog.isShowing())MainActivity.progressDialog.dismiss();adapter.notifyDataSetChanged();}});}catch (Exception e){e.printStackTrace();}}
}

都是一些Fragement的基本用法,我只挑了一个进行说明,其他的都差不多,感觉这样复用不够高,也许可以只写一个fragment类吧,或者先写一个接口,后面的或许更好对fragment的List进行操作,这些觉得我以后可以好好思考思考。GetNews()是我更新内容的方法。我的加载内容的模块是放在onCreatView()里的,这样其实每次划到该fragment之前就会更新数据了,但这样感觉也不是很好,各位如果有更好的方法请不吝赐教。 parseJSONWithJSONObject()是解析Json对象的,关于Json的解析我代码在上面建议配合json源码看看。

httpsendrequest就不说了,是一个发起请求的方法如下:


public class HttpUtil {private String channel="";private final static  String apikey="LzQUsyWYuvT5kNqAAuUuY1pBmhhS37V7";public static void sendOkhttpRequest(String address,okhttp3.Callback callback){//建立RequestBody对象存放待提交的参数,参数有 apikey,text,userid./*RequestBody requestBody=new FormBody.Builder().add("key",apikey).add("info",text).add("userid","128").build();*/OkHttpClient client =new OkHttpClient();Request request=new Request.Builder().url(address).build();client.newCall(request).enqueue(callback);//enqueue方法在内部开好了子线程并最终将结果回调到okhttp3.Callback当中。}
}

5.3 RecyclerView的item类代码:

public class NewItem {private String title;private String pictureAddress;private String contentAddress;public String getContentAddress() {return contentAddress;}public void setContentAddress(String contentAddress) {this.contentAddress = contentAddress;}public String getPictureAddress() {return pictureAddress;}public void setPictureAddress(String pictureAddress) {this.pictureAddress = pictureAddress;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}
}

6 总结以及源码下载链接

基本就到此结束了。下载源码的同时,希望能点个赞或者GitHub点个星,感激不尽!

github的项目地址:https://github.com/DhyanaCoder/WeNews/tree/master 欢迎浏览以及下载。

简单的Android端新闻App的实现。相关推荐

  1. 简单的Android端新闻App的实现

    先上效果图: 图一  :     图二:    总体思路概述:        如图本app界面简单,图一的最顶端是安卓原生的标题栏,图二的最顶端是我自己定义的标题栏,具体代码后面再说.图一标题栏下面是 ...

  2. 搭建直播平台过程中Android端直播APP源码是如何实现连麦功能的?

    直播平台强大的变现能力是大家有目共睹的,很多开发商在搭建直播平台时为了增加用户黏性,纷纷将直播中加入连麦功能. 目前市场上通用的有两种连麦方案:本地混流和云端混流.本地混流即主播和连麦观众分别推一路流 ...

  3. react native Android端保持APP后台运行--封装 Headless JS

    react native Android端保持APP后台运行--封装 Headless JS 前些日子在做后台下载时踩了后台运行这个大坑,RN官网文档上面在安卓上提供了Headless JS方法,iO ...

  4. android实现mysql数据库存储_一个简单的Android端对象代理数据库系统的实现(二、执行+存储)...

    这是我之前在武汉大学彭智勇老师那边做过的一个对象代理数据库系统.文中给出了一整个系统的几乎所有代码,经测试可正常运行.文章比较长,超出了知乎的最长文章范围,因此分为两篇文章.这是第二篇. 执行 执行部 ...

  5. 一个简单的android便签app

    一个简单的android便签app 源码下载 MainActivity.java package com.zp.myfirstapp;import java.io.File; import java. ...

  6. Android Compose 新闻App(四)下拉刷新、复杂数据、网格布局、文字样式

    Compose 新闻App(四)下拉刷新.复杂数据.网格布局.文字样式 前言 正文 一.下拉刷新 ① 添加依赖 ② 使用 ③ 样式更改 二.刷新数据 三.复杂数据 四.复杂列表 ① 更改返回数据 ② ...

  7. android模拟机新闻APP,DavidTGNewsProject

    DavidTGNewsProject ##[Android]最新主流新闻app功能实现.仿网易,搜狐等新闻客户端 (原创作品,转载请说明出处)先给大家看一下效果图: 这个项目总体来说虽然不是特别难,但 ...

  8. Android Compose 新闻App(二)ViewModel、Hlit、数据流

    Compose 新闻App(二)ViewModel.Hlit.数据流 前言 正文 一.添加依赖 ① 添加Hilt依赖 ②添加ViewModel依赖 二.Hilt使用 三.ViewModel使用 四.数 ...

  9. 凤凰新闻 android,凤凰新闻app正式版

    凤凰新闻app是一款由凤凰网推出的新闻资讯手机客户端,用户可以在凤凰新闻app中获得第一手新闻资讯,资讯涵盖面甚广,用户可以寻找到自己感兴趣的资讯,精美的界面,简单易上手的操作,感兴趣的朋友不要错过! ...

最新文章

  1. codeforces A. Jeff and Digits 解题报告
  2. 为ASP.NET控件添加常用的JavaScript操作
  3. 扎哈的绝唱:“六芒星”大兴机场的几何赏析
  4. Windows Server 2012 R2/2016/2019无法安装.NET Framework 3.5.1或语言包的解决方法
  5. 使用V8和node轻松profile分析nodejs应用程序
  6. Spring boot项目集成Sharding Jdbc
  7. 华为Mate 30 Pro保护壳生产线谍照曝光:长方形摄像头模组实锤?
  8. 《spring-boot学习》-01-初体验
  9. JPA学习笔记---JPA理解---第一个JPA程序
  10. 互联网产品经理的核心竞争力是什么呢?
  11. java动态编译无法导包_java动态编译整个项目,解决jar包找不到问题.doc
  12. 《编写可维护的 JavaScript》读书笔记第7章:事件处理
  13. 如何直接打开AutoCAD格式的DXF文件
  14. 量化金融经典理论、重要模型、发展简史大全
  15. 阿里云部署RSSHub踩坑笔记
  16. 神经计算棒python_神经计算棒-Movidius™ Neural Compute SDK Python API
  17. linux c++ 线程支持 多核应用,linux C++多线程服务端开发
  18. centos 7使用gcc编译c语言,CentOS 7编译安装gcc 4.9.4
  19. ubuntu删除旧的linux内核
  20. Android studio 安装步骤

热门文章

  1. python 编辑距离_最小编辑距离(Levenshtein)的 Python 实现
  2. 最新精仿小刀娱乐资源网模板源码,带前台会员投稿审核功能
  3. (Note)夜光藻赤潮
  4. visio跨职能流程图带区背景及大小及改变格式 (转)
  5. JavaScript学习笔记--【黑马程序员】
  6. 数学公式识别神器Mathpix,零错误高效率
  7. 外媒称今年iPhone XR将新增两种颜色:绿色和薰衣草色
  8. 数智企业 财税云领——用友全线产品支持专票电子化
  9. dedecms 对不起,你输入的参数有误修改
  10. day79_babasport第五天