简单的Android端新闻App的实现。

2023-10-29

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">

    <LinearLayout

        android:layout_width="match_parent"
        android:layout_height="wrap_content">
  <TextView
      android:id="@+id/finance"
      android:layout_weight="1"
      android:layout_width="0dp"
      android:text="财经"
      android:gravity="center_horizontal"
      android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/movie"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:text="电影"
            android:gravity="center"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/amusement"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:text="娱乐"
            android:gravity="center"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:text="电视"
            android:gravity="center"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/headline"
            android:layout_weight="1"
            android:layout_width="0dp"
            android:text="头条"
            android:gravity="center"
            android:layout_height="wrap_content" />
        <TextView
            android: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.PullToRefreshView
        android:id="@+id/pull_to_refresh"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <android.support.v4.view.ViewPager
        android: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;
    @Override
    protected 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;
    }
    @Override
    public Fragment getItem(int position) {
        Log.d("getItem","good");

        return fragmentList.get(position);
    }

    @Override
    public int getCount() {
        return fragmentList!= null ? fragmentList.size() : 0;
    }

    @Override
    public 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
    }



    @Override
    public 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() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.d("error11","获取错误!!!");
        }

        @Override
        public 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() {
                @Override
                public 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 欢迎浏览以及下载。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

简单的Android端新闻App的实现。 的相关文章

随机推荐

  • single-passParallel Prefix Scan with Decoupled Look-back

    背景 最近在写基数排序 nvidia的基数排序依赖这个实现 所以有必要搞懂 原理 代码 总结 参考
  • windows下如何搭建属于自己的git服务器

    前一阵子公司需要 领导让我给我们技术部搭建一个git服务器 以前看过教程 但自己没动手做过 开始按照网上的教程来 但搭建过程中发现还是不够详细 今天给大家一个比较详细的 希望对大家有帮助 高能预警 这不是一个问题 这是一个技术贴 咳咳 进入
  • 管理系统-------SPU

    目录 静态页面 api接口 二次封装ui button组件 代码 v attrs的用法详解与原理 listeners spuForm spuForm静态页面 spuForm逻辑分析 完整代码 spu完整代码 静态页面
  • 在vue export default 外部调用内部的属性或方法

  • C++超详细五子棋游戏(AI实现人机对弈+双人对弈+EasyX图形化界面+详细介绍)

    目录 一 准备工作 1 开发环境 2 EasyX的下载和安装 二 游戏规则 1 行棋顺序 2 判断胜负 3 四种重要棋型解释 重点 4 禁手规则 三 双人对弈详细剖析 1 落子 2 判胜 四 人机对弈超详细剖析 1 整体代码分析 2 玩家落
  • 分类算法简述

    分类算法简述 一 什么是分类算法 数据挖掘任务通常分为两大类 预测任务 根据其他属性的值 预测特定属性的值 描述任务 概括数据中潜在联系的模式 相关性 趋势 聚类 轨迹和异常 分类属于预测任务 就是通过已有数据集 训练集 的学习 得到一个目
  • CH2-开发工具DevEco Studio

    文章目录 本章节目标 一 DevEco基本特性 主要功能 基本特性 应用开发流程 二 安装过程 搭建开发环境流程 下载和安装Node js 下载和安装DevEco Studio 配置开发环境 网络设置 设置npm仓库 三 Gradle的作用
  • 软件测试大厂面试真题,分享一波经验!!

    你好 我是小牛 在这家公司待了两年了 基本上功能 自动化 性能都有做 而且公司系统相对比较复杂 链路比较长 相对来说 还是能学习到不少东西 而且比较难得的一点是 公司加班相对来说比较少 一般七点左右就能走了 偶尔加班到九点 可以说是十分安逸
  • XSSGAME小游戏(XSS学习)level1-15

    XSS源码下载 xssgame 本地搭建 level1 查看源码
  • 【SQL注入-04】报错注入案例

    目录 1 报错注入概述 2 常用的报错注入命令 2 2 group by重复键冲突 count floor rand group by组合 2 2 1 group by重复键冲突的原理及bug演示 2 2 2 补充 sql语句解析过程 2
  • SpringBoot 如何使用 CORS 进行跨域资源共享

    SpringBoot 如何使用 CORS 进行跨域资源共享 在 Web 开发中 跨域资源共享 CORS 是常见的问题之一 CORS 是一种安全机制 用于限制跨域请求对目标服务器的访问 在本文中 我们将介绍如何在 Spring Boot 中使
  • 解决NestedScrollView嵌套RecyclerView滑动冲突导致无法正常调用加载更多功能

    解决NestedScrollView嵌套RecyclerView滑动冲突导致无法正常调用加载更多功能 在使用NestedScrollView嵌套RecyclerView中 首先会出现的问题就是RecyclerView滑动会出现卡顿 没有惯性
  • DB2 常见错误号 解释

    操作数据库过程中 遇到许多问题 很多都与SQL CODE和SQL State相关 现在把一个完整的SQLCODE和SQLState错误信息和相关解释作以下说明 一来可以自己参考 对DB2错误自行找出原因 声明 这是搜集网上的资料得来的 详细
  • Java获取JSONObject内指定字段key的value值

    项目场景一 获取 id code success data user id 6286f2c0 6399 11ec 800b f7f07b836bd8 exp 1667880458 解决方案 通过JSONObject解决 String id
  • Android studio 卸载

    Android studio 卸载 彻底卸载 Android studio 卸载 彻底卸载 1 卸载Android Studio前 要关闭 或重启电脑 2 控制面板 开始 控制面板 程序和功能 选择Android Studio 3 删除sd
  • JS中localStorage的使用

    localStorage的介绍使用 localStorage理论上来说是永久有效的 即不主动清空的话就不会消失 即使保存的数据超出了浏览器所规定的大小 也不会把旧数据清空而只会报错 localstorage为标准的键值对 Key Value
  • 使用Qgis按属性批量裁剪

    参考 QGIS按属性表批量裁剪 知乎 1 加载栅格图以及矢量 2 根据属性字段将矢量分割成单独的矢量文件 Vetor Data Management Tools Splt vector layer 3 根据单独矢量文件批量裁剪栅格图像 Ra
  • 为什么越多的通用寄存器,可以减少对栈的访问,提高性能

    为什么越多的通用寄存器 可以减少对栈的访问 提高性能 增加通用寄存器的数量可以减少对栈的访问 从而提高性能的原因如下 1 寄存器是位于CPU内部的存储器 访问速度非常快 远快于访问外部内存 相比之下 访问栈上的数据需要通过内存总线与内存进行
  • 微信登录接口对接

    微信开发文档 https open weixin qq com cgi bin showdocument action dir list t resource res list verify 1 id open1419316505 toke
  • 简单的Android端新闻App的实现。

    1 更新记录 2021 11 14 1 更新了数据来源的 api 使用了聚合数据的 新闻 api 2 使用了 TabLayout 代替原来的 textview 组 2021 11 13 1 解决下拉刷新出现崩溃的现象 1 更新了数据来源的