基于Android平台开发,仿头条新闻app

news2024/9/20 8:46:14

相关视频教程在某站上面(🔍浩宇软件开发)

1. 项目模块功能思维导图

在这里插入图片描述

2. 项目涉及到的技术点

  1. 数据来源:聚合数据API
  2. 使用okhttp网络请求框架获取api数据
  3. 使用gson库解析json数据
  4. 使用RecyclerView+adapter实现新闻列表
  5. 使用SQLite数据库实现用户登录,注册,浏览历史记录
  6. 使用SharedPreferences 实现记住密码登录
  7. 使用TabLayout+ViewPager2实现新闻分类滑动
  8. 使用DrawerLayout+NavigationView实现抽屉
  9. 使用WebView实现新闻详情数据加载
  10. 使用Glide实现新闻图片加载

3. 项目截图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3. 部分代码实现

  1. 欢迎页实现
public class WelcomeActivity extends AppCompatActivity {
    private TextView tvCountdown;

    private CountDownTimer countDownTimer;
    private long timeLeftInMillis = 3000; // 设置倒计时时长,单位为毫秒

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);
        //初始化控件
        tvCountdown =findViewById(R.id.tv_countdown);

        // 启动倒计时
        startCountdown();
    }

    private void startCountdown() {
        countDownTimer =new CountDownTimer(timeLeftInMillis,1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                timeLeftInMillis = millisUntilFinished;
                int secondsRemaining = (int) (millisUntilFinished / 1000);
                tvCountdown.setText(secondsRemaining +" s | 跳转");
            }

            @Override
            public void onFinish() {
                //跳转到登录页面(看自己逻辑想跳转哪个页面)
                startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                // 倒计时结束后的操作,例如跳转到主页面
                finish();

            }
        }.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
    }
}
  1. 首页实现
public class MainActivity extends AppCompatActivity {

    //    private String[] titles = {"娱乐", "军事", "教育", "文化", "将康", "财经", "体育", "汽车", "科技"};
    private List<TitleInfo> titles = new ArrayList<>();
    private TabLayout tab_layout;
    private ViewPager2 viewPager;

    private NavigationView nav_view;

    private TextView tv_username;
    private TextView tv_nickname;

    private ImageView btn_open_drawerLayout;
    private DrawerLayout drawer_layout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //初始化title数据
        titles.add(new TitleInfo("推荐", "top"));
        titles.add(new TitleInfo("国内", "guonei"));
        titles.add(new TitleInfo("国际", "guoji"));
        titles.add(new TitleInfo("娱乐", "yule"));
        titles.add(new TitleInfo("体育", "tiyu"));
        titles.add(new TitleInfo("军事", "junshi"));
        titles.add(new TitleInfo("科技", "keji"));
        titles.add(new TitleInfo("财经", "caijing"));
        titles.add(new TitleInfo("游戏", "youxi"));
        titles.add(new TitleInfo("汽车", "qiche"));
        titles.add(new TitleInfo("健康", "jiankang"));


        //初始化控件
        tab_layout = findViewById(R.id.tab_layout);
        viewPager = findViewById(R.id.viewPager);
        nav_view = findViewById(R.id.nav_view);
        btn_open_drawerLayout = findViewById(R.id.btn_open_drawerLayout);
        drawer_layout = findViewById(R.id.drawer_layout);
        //注意事项, 不能直接findViewById
        //        tv_username=findViewById(R.id.nav_view);
        //        tv_username = nav_view.getHeaderView(0).findViewById(R.id.tv_username);
        tv_username = nav_view.getHeaderView(0).findViewById(R.id.tv_username);
        tv_nickname = nav_view.getHeaderView(0).findViewById(R.id.tv_nickname);



        //btn_open_drawerLayout打开抽屉
        btn_open_drawerLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawer_layout.open();
            }
        });


        //nav_view点击事件
        nav_view.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {

                if (item.getItemId() == R.id.nav_history) {
                    //跳转到历史记录
                    Intent intent = new Intent(MainActivity.this, HistoryListActivity.class);
                    startActivity(intent);
                } else if (item.getItemId() == R.id.nav_update_pwd) {

                    //判断是否登录
                    UserInfo userInfo = UserInfo.getUserInfo();
                    if (null != userInfo) {
                        startActivity(new Intent(MainActivity.this, UpdatePwdActivity.class));
                    } else {
                        Toast.makeText(MainActivity.this, "请先登录~~", Toast.LENGTH_SHORT).show();
                    }

                } else if (item.getItemId() == R.id.nav_about) {
                    startActivity(new Intent(MainActivity.this, AboutActivity.class));


                } else if (item.getItemId() == R.id.nav_exit) {
                    UserInfo userInfo = UserInfo.getUserInfo();
                    if (null!=userInfo){
                        new AlertDialog.Builder(MainActivity.this).setTitle("温馨提示").setMessage("确认要退出登录吗?").setPositiveButton("确认", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {

                                        startActivity(new Intent(MainActivity.this, LoginActivity.class));
                                        UserInfo.setUserInfo(null);
                                    }
                                }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {

                                    }
                                })
                                .show();
                    }else {
                        Toast.makeText(MainActivity.this, "请先登录~~", Toast.LENGTH_SHORT).show();
                    }

                }

                return true;
            }
        });


        //viewPager 需要设置一个adapter
        viewPager.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                String title = titles.get(position).getPy_title();
                TabNewsFragment tabNewsFragment = TabNewsFragment.newInstance(title);
                return tabNewsFragment;
            }

            @Override
            public int getItemCount() {
                return titles.size();
            }
        });

        //tab_layout点击事件
        tab_layout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //设置viewPager选中当前页
                viewPager.setCurrentItem(tab.getPosition(), false);

            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });


        //tab_layout和viewPager关联在一起
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(tab_layout, viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
            @Override
            public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                tab.setText(titles.get(position).getTitle());
            }
        });


        //这句话一定不能少
        tabLayoutMediator.attach();

    }

    @Override
    protected void onResume() {
        super.onResume();

        UserInfo userInfo = UserInfo.getUserInfo();
        if (null != userInfo) {
            tv_username.setText(userInfo.getUsername());
            tv_nickname.setText(userInfo.getNickname());
        } else {
            tv_username.setText("请登录");
            tv_nickname.setText("");
            //登录点击事件
            tv_username.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(MainActivity.this, LoginActivity.class);
                    startActivity(intent);
                }
            });
        }


    }
}
  1. 新闻详情页
public class NewsDetailsActivity extends AppCompatActivity {
    private NewsInfo.ResultDTO.DataDTO dataDTO;
    private Toolbar toolbar;
    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news_details);

        //初始化控件
        toolbar = findViewById(R.id.toolbar);
        mWebView = findViewById(R.id.webView);

        //获取传递的数据
        dataDTO = (NewsInfo.ResultDTO.DataDTO) getIntent().getSerializableExtra("dataDTO");

        //设置数据
        if (null != dataDTO) {
            toolbar.setTitle(dataDTO.getTitle());
            mWebView.loadUrl(dataDTO.getUrl());

            //添加历史记录
            String dataDTOJson = new Gson().toJson(dataDTO);
            UserInfo userInfo = UserInfo.getUserInfo();
            if (userInfo!=null){
                HistoryDbHelper.getInstance(NewsDetailsActivity.this).addHistory(userInfo.getUsername(),dataDTO.getUniquekey(),dataDTOJson);
            }else {
                HistoryDbHelper.getInstance(NewsDetailsActivity.this).addHistory(null,dataDTO.getUniquekey(),dataDTOJson);
            }

        }


        //返回
        toolbar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });






    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1919432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学建模·Topsis优劣解距离法

Topsis优劣解 一种新的评价方法&#xff0c;特点就是利用原有数据&#xff0c;客观性强。相较于模糊评价和层次评价 更加客观&#xff0c;充分利用原有数据&#xff0c;精确反映方案差距基本原理 离最优解最近&#xff0c;离最劣解越远具体步骤 正向化 代码与原理与熵权法…

防火墙第一次综合实验

DMZ区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 办公区设备10.8.2.1不允许访问DMZ区的FTP服务器和HTTP服务器&#xff0c;仅能ping通10.0.3.10 1.先建立拒绝BG到DMZ区的安全策略 2.建立BG到DMZ区的icmp允许 3…

探索 Electron:窗口菜单以及生命周期和对话框讲解

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

Linux文件编程(标准C库)

目录 一、标准C库打开/创建文件&#xff0c;读写文件&#xff0c;光标移动 二、标准C库写入结构体到文件 三、其他函数补充 1.fputc函数 2.feof函数和fgetc函数 前面讲到的open函数都是基于linux内核的&#xff0c;也就是说在Windows系统上无法运行&#xff0c;移植性比较…

shein测试开发会问些啥?

&#x1f3c6;本文收录于《CSDN问答解惑-》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

【thingsbord源码编译】 显示node内存不足

编译thingsbord显示报错 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory问题原因分析 重新安装java版本 编译通过

论文阅读【时空+大模型】ST-LLM(MDM2024)

论文阅读【时空大模型】ST-LLM&#xff08;MDM2024&#xff09; 论文链接&#xff1a;Spatial-Temporal Large Language Model for Traffic Prediction 代码仓库&#xff1a;https://github.com/ChenxiLiu-HNU/ST-LLM 发表于MDM2024&#xff08;Mobile Data Management&#xf…

无人机之遥控器保养

一、使用存放 1、避免让遥控器受到强烈的震动或从高处跌落&#xff0c;以免影响内部结构的精度&#xff1b; 2、遥控器在使用完后&#xff0c;需要将天线收拢&#xff0c;避免折断&#xff0c;养成定期检查天线的习惯&#xff1b; 3、定期检查遥控器按键有无裂纹、畸变、松旷…

跨境电商API的全球视野:打破地域限制,连接全球消费者与商家

在全球化日益加深的今天&#xff0c;跨境电商已成为推动全球经济一体化的重要力量。它不仅为消费者提供了前所未有的购物体验&#xff0c;让世界各地的商品触手可及&#xff0c;更为商家开辟了全新的市场蓝海&#xff0c;实现了业务的全球化拓展。在这一进程中&#xff0c;跨境…

PyTorch | 加速模型训练的妙招

引言 提升机器学习模型的训练速度是每位机器学习工程师的共同追求。训练速度的提升意味着实验周期的缩短&#xff0c;进而加速产品的迭代过程。同时&#xff0c;这也表示在进行单一模型训练时&#xff0c;所需的资源将会减少。简而言之&#xff0c;我们追求的是效率。 熟悉 PyT…

Rust代码优化的九大技巧

一.使用 Cargo 内置的性能分析工具 描述&#xff1a;Cargo 是 Rust 的包管理器&#xff0c;带有内置工具来分析代码性能&#xff0c;以识别性能瓶颈。 解释&#xff1a; 发布模式&#xff1a;在发布模式下编译启用优化&#xff0c;可以显著提高性能。 cargo build --release基…

解决vue多层弹框时存在遮挡问题

本文给大家介绍vue多层弹框时存在遮挡问题&#xff0c;解决思路首先想到的是找到对应的遮挡层的css标签&#xff0c;然后修改z-index值&#xff0c;但是本思路只能解决首次问题&#xff0c;再次打开还会存在相同的问题&#xff0c;故该思路错误&#xff0c;下面给大家带来一种正…

【鸿蒙学习笔记】文件管理

官方文档&#xff1a;Core File Kit简介 目录标题 文件分类什么是应用沙箱&#xff1f; 文件分类 应用文件&#xff0c;比如应用的安装包&#xff0c;自己的资源文件等。用户文件&#xff0c;比如用户自己的照片&#xff0c;录制的音视频等。 什么是应用沙箱&#xff1f; 应…

完美解决:MySQL8报错:Public Key Retrieval is not allowed

在配置数据源的时候直接将属性allowPublicKeyRetrieval设置为true即可 &AutoReconnecttrue

论文发表作图必备:训练结果对比,多结果绘在一个图片【Precision】【Recall】【mAP0.5】【mAP0.5-0.95】【loss】

前言:Hello大家好,我是小哥谈。YOLO(You Only Look Once)算法是一种目标检测算法,它可以在图像中实时地检测和定位目标物体。YOLO算法通过将图像划分为多个网格,并在每个网格中检测目标物体,从而实现快速的目标检测。本文所介绍的作图教程适用于所有YOLO系列版本算法,接…

Linux Ubuntu MySQL环境安装

1. 更新软件源 首先&#xff0c;确保你的Ubuntu系统已经更新了软件源列表&#xff0c;以便能够下载到最新的软件包。打开终端并输入以下命令&#xff1a; sudo apt update 2. 安装MySQL服务器 打开终端并输入以下命令来安装MySQL服务器 sudo apt install mysql-server 在…

代码随想录算法训练营第五十天| 739. 每日温度、496.下一个更大元素 I、503.下一个更大元素II

739. 每日温度 题目链接&#xff1a; 739. 每日温度 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 思路&#xff1a; 这道题需要找到下一个更大元素。 使用栈来存储未找到更高温度的下标&#xff0c;那么栈中的下标对应的温度从栈底到栈顶是递减的。这意味着&#xff…

鸿蒙语言基础类库:【@ohos.application.testRunner (TestRunner)】 测试

TestRunner TestRunner模块提供了框架测试的能力。包括准备单元测试环境、运行测试用例。 如果您想实现自己的单元测试框架&#xff0c;您必须继承这个类并覆盖它的所有方法。 说明&#xff1a; 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-…

5款常用的漏洞扫描工具,网安人员不能错过!

漏洞扫描是指基于漏洞数据库&#xff0c;通过扫描等手段对指定的远程或者本地计算机系统的安全脆弱性进行检测&#xff0c;发现可利用漏洞的一种安全检测的行为。 在漏洞扫描过程中&#xff0c;我们经常会借助一些漏扫工具&#xff0c;市面上漏扫工具众多&#xff0c;其中有一…

windows环境下基于3DSlicer 源代码编译搭建工程开发环境详细操作过程和中间关键错误解决方法说明

说明: 该文档适用于  首次/重新 搭建3D-Slicer工程环境  Clean up(非增量) 编译生成 1. 3D-slicer 软件介绍 (1)3D Slicer为处理MRI\CT等图像数据软件,可以实行基于MRI图像数据的目标分割、标记测量、坐标变换及三维重建等功能,其源于3D slicer 4.13.0-2022-01-19开…