基于Android开发疫情时报APP

基于Android开发疫情时报APP

在这里插入图片描述

要求:

对其软件要求较高,要考虑兼容性。首先,在APP开发工具方面,有更多开发者选择的是Eclipese
进行开发,但是最近google好像停止对Eclipese的sdk更新了,所以我推荐大家使用android studio
,它是Google官方指定的Android开发工具, 目前我用的是4.1.2稳定版,及JDK1-8.0,Gradle 6.3。
Gradle也极为重要,它的作用就是管理项目中的依赖、打包、编译……它就是一个构建工具,也就是一些复杂的操作不需要开发者自己去弄,而是通过构建工具去完成的。还有所调用的权限,本论文引用网址的及访问本地数据库权限至关重要,APP必须访问受限数据或执行受限操作才能实现某个用例,要先声明相应的权限,才能实现相对于的功能。

理论意义:

新冠肺炎疫情之下,为提倡关注疫情情况,各大网络平台推出了实时疫情时报网站,在当前大数据技术飞速发展的时代背景下,但独立的软件少之又少,本项目是基于Android开发的疫情时报APP,可以更加方便的了解疫情进展,更能够密切的查看疫情新闻,及了解为疫情做出贡献的英雄学者。

实际意义:

以我为例子,刚开始我花大量时间在微博上,看微博热搜和主页。但微博的信息量极大,我不得不每天花费一定量的时间来获取信息。接着我开始通过微信“看一看”和“朋友圈”来获取相关信息,这个渠道的好处在于通过我的朋友筛选出了质量不错的信息,我可以看到大家都在关注的热点。
以上两个途径是我最开始获取疫情信息的主要途径。但这两个途径并没有满足我另外的需求,比如获取个别城市相关的最新疫情消息和相关新闻。准确来说,我需要设计出一款实时监控疫情动态的APP,打开APP就能够直观的查看疫情相关的疫情,繁琐操作减少,更能切合我对疫情的了解状况。

一、绪论

本文是基于Android Studio的一款疫情时报APP,阐述了Android程序设计语言在软件开发中的应用方式,并以iOS手机软件为例对Android程序设计语言在软件开发中的实践运用进行了详细分析,Android程序的应用最主要的便是在编程效率的提升方面,以往在编程方面存在着来自诸多方面的限制。

通常情况下来说,Java语言会应用在对于Android手机软件的开发上,而iOS则大多会采用c++或者是Objective-C语言进行开发。所以当在对一款移动端应用进行制作的时候需要同两个平台相适应,便要对两个不同的开发语言进行应用,在各自平台上分别将相同的逻辑开发一次。但此举往往涉及到对于大量人力和财力的浪费,特别是在时间方面的花费,对于移动互联网市场来说,时间是至关重要的影响因素,所以亟待采用适当的方法来解决这一问题。其本身存在着较高的专业程度,但从目前来看,编程不再像从前一样面临较高的难度,其在准入门槛方面也有所降低,强化对于Android程序设计语言的应用能够在极大程度上实现编程效率的提升,这样一来便能够有效发挥出其对于软件开发技术提高的推动作用。

二、项目完整展现

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

![在这里插入图片描述](https://img-blog.csdnimg.cn/ee7eb2779e1f4061afd9a44943f5fd4b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5pyo5aS044m_,size_16,color_FFFFFF,t_70,g_se,x_16
在这里插入图片描述

三、关于前端布局的框架
1 新闻界面

新闻界面由顶部搜索栏(带图片装饰)与新闻展示栏两部分组成。其中新闻展示栏集RecyclerViewSmartRefreshLayout两个类为一体,添加了装饰线和加载动画,加载流畅。新闻的点击进入详情页利用CardView类的click事件实现,加载内容为新闻的正文内容。

从Android 5.0开始,谷歌公司推出了一个用于大量数据展示的新控件RecylerView,可以用来代替传统的ListView,更加强大和灵活。RecyclerView并不会完全替代ListView(这点从ListView没有被标记为@Deprecated可以看出),两者的使用场景不一样。但是RecyclerView的出现会让很多开源项目被废弃,例如横向滚动的ListView, 横向滚动的GridView, 瀑布流控件,因为RecyclerView能够实现所有这些功能。

SmartRefreshLayout的目标是打造一个强大,稳定,成熟的下拉刷新框架,正如名字所说,SmartRefreshLayout是一个“聪明”或者“智能”的下拉刷新布局,由于它的“智能”,它不只是支持所有的View,还支持多层嵌套的视图结构[1]。 它继承自ViewGroup 而不是FrameLayout或LinearLayout,提高了性能。 也吸取了现在流行的各种刷新布局的优点,包括谷歌官方的 SwipeRefreshLayout, 其他第三方的 Ultra-Pull-To-Refresh、

TwinklingRefreshLayout 。还集成了各种炫酷的 Header 和 Footer。注:在SmartRefreshLayout若没有使用特殊Header,可以不添加SmartRefreshHeader依赖包

2 标签增减

标签增减功能位于主页右下角的设置栏中,我们利用ChipsView组件及其相关动作函数实现了这一功能,方便且带有动态效果。我们利用Intent在主界面Activity与工具栏Activity之间传递信息,从而实现了近乎同步的标签增删操作。

3 疫情界面

疫情界面主要为基础的主界面框架,WebView主要是嵌入了一个夸克网址(https://broccoli.uc.cn/apps/pneumonia/routes/index),Android WebView在Android平台上是一个特殊的View,基于webkit引擎、展现web页面的控件,这个类可以被用来在你的app中仅仅显示一张在线的网页,WebView内部实现是采用渲染引擎来展示view的内容,提供网页前进后退,网页放大,缩小,搜索。
现在很多APP都内置了Web网页,本项目采用的是夸克网站平台比如说很多电商平台,淘宝、京东、聚划算等等。WebView比较灵活,不需要升级客户端,只需要修改网页代码即可。一些经常变化的页面可以用WebView这种方式去加载网页。例如中秋节跟国庆节打开的页面不一样,如果是用WebView显示的话,只修改修改html页面就行,而不需要升级客户端。

4 学者界面

疫情学者界面分为高关注学者与追忆学者两个标签,每个标签栏下有对应学者的信息(与新闻列表类似),最外层用竖向排列的 LinearLayout 包裹,它有两个子节点,上面是用于滑动和装载 Fragment 的 ViewPager,下面是两个 Tab 的布局。且能够点击进入学者名片,查看学者头像、生平简介、主要贡献等信息。这里也调用了一个Material Design Chip View库实现返回桌面。

5 历史界面

在主界面右下角的工具栏中能够查看浏览历史,此处我们追踪了每一个新闻对象的”被浏览“事件,并在程序后台自动进行历史记录,同时能够在离线状态下进行查看。.当点击到某一个新闻的时候,访问数据库是否有该新闻的信息,有的话更新新闻浏览的时间,更新数据库。没有的话添加到数据库中。

6 分享功能

利用系统自带的分享功能进行分享,目前能够通过任何能够发送文本的应用(包括蓝牙)分享包含新闻摘要与具体内容的纯文本。创建一个选择器,让用户自己选择分享到哪里。这里有一点得注意,Intent传递的数据的Type(就是setType()方法)一定要控制好,不然会出错。

四、代码
以下只是5%代码,加以参考即可。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
>

    <FrameLayout
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/nav_view"
    />

    <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/nav_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
        android:background="@color/bisque"
            android:layout_alignParentBottom="true"
            app:menu="@menu/bottom_nav_menu"/>

</RelativeLayout>

MainActivity.java

package com.java.zhushuqi;

import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import com.java.zhushuqi.backend.ConnectInterface;
import com.java.zhushuqi.backend.News;
import com.java.zhushuqi.backend.Server;
import com.java.zhushuqi.ui.Scholar.ScholarFragment;
import com.java.zhushuqi.ui.data.PlaceholderFragment;
import com.java.zhushuqi.ui.news.NewsFragment;
import com.java.zhushuqi.ui.knowledge.KnowledgeFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import androidx.appcompat.app.AppCompatActivity;
import io.reactivex.functions.Consumer;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private Fragment[] fragments;
    private int lastFragment = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Server.server = new Server();
        ConnectInterface.InitServer().subscribe(new Consumer<List<News>>() {
            @Override
            public void accept(List<News> currentNews) {
                initView();
            }
        });
    }

    private void initView() {
        NewsFragment newsFragment = new NewsFragment();
        PlaceholderFragment dashboardFragment = new PlaceholderFragment();
        KnowledgeFragment notificationsFragment = new KnowledgeFragment();
        ScholarFragment scholarFragment = new ScholarFragment();
        fragments = new Fragment[]{ newsFragment,dashboardFragment,scholarFragment,notificationsFragment};

        getSupportFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, newsFragment).show(newsFragment).commit();
        BottomNavigationView bottomNavigation = findViewById(R.id.nav_view);
        bottomNavigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
    }

    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.navigation_news:
                    if (lastFragment != 0) {
                        switchFragment(lastFragment, 0);
                        lastFragment = 0;
                    }
                    return true;
                case R.id.navigation_data:
                    if (lastFragment != 1) {
                        switchFragment(lastFragment, 1);
                        lastFragment = 1;
                    }
                    return true;
                case R.id.navigation_knowledge:
                    if (lastFragment != 2) {
                        switchFragment(lastFragment, 2);
                        lastFragment = 2;
                    }
                    return true;

                default:
                    break;
            }
            return false;
        }
    };

    private void switchFragment(int lastFragment, int index) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.hide(fragments[lastFragment]);
        if (!fragments[index].isAdded())
            transaction.add(R.id.nav_host_fragment, fragments[index]);
        transaction.show(fragments[index]).commitAllowingStateLoss();
    }
}

package com.java.zhushuqi.backend;

import android.util.Log;

import org.json.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;

public class NewsLoader {
    static String link = "https://covid-dashboard.aminer.cn/api/events/list?type=%s&page=%d&size=%d";

    static String GetContentFromURL(String url) throws IOException {
        URL cs = new URL(url);
        URLConnection urlcnt = cs.openConnection();
        urlcnt.setConnectTimeout(10 * 1000);
        urlcnt.connect();
        BufferedReader in = new BufferedReader(new InputStreamReader(urlcnt.getInputStream()));
        String line, body = "";
        while ((line = in.readLine()) != null)
            body = body + line;
        in.close();
        return body;
    }

    public static void GetNews(final int page, final String type, final int size, ArrayList<News> newsl) throws IOException, JSONException {
        String URL_String = new String(String.format(link, type, page, size));
        String body = GetContentFromURL(URL_String);
        if (body.equals("")) {
            Log.d("warning", "No message received.");
        }
        JSONObject news_json = new JSONObject(body);
        GetNewsFromJSON(news_json, newsl);
    }

    public static void GetNewsFromJSON(JSONObject src, ArrayList<News> newsl) throws JSONException {
        JSONArray list, authorlist;
        JSONObject obj, author;
        list = src.optJSONArray("data");
        for (int i = list.length() - 1; i >= 0; i--) {
            News news = new News();
            obj = list.getJSONObject(i);//这一页里的第i条新闻
            news.id = obj.optString("_id");
            news.content = obj.optString("content");
            news.date = obj.optString("date");
            news.seg_text = obj.optString("seg_text").split(" ");
            news.source = obj.optString("source");
            news.title = obj.optString("title");
            news.type = obj.optString("type");
            newsl.add(0, news);
        }
    }

    public static int RenewNews(final int page, final String type, final int size, ArrayList<News> newsl) throws IOException, JSONException {
        String URL_String = new String(String.format(link, type, page, size));
        String body = GetContentFromURL(URL_String);
        if (body.equals("")) {
            Log.d("warning", "No message received.");
        }
        JSONObject news_json = new JSONObject(body);
        return (RenewNewsFromJSON(news_json, newsl));
    }

    public static void RetrieveNews(final int page, final String type, final int size, ArrayList<News> newsl) throws IOException, JSONException {
        String URL_String = new String(String.format(link, type, page, size));
        String body = GetContentFromURL(URL_String);
        if (body.equals("")) {
            Log.d("warning", "No message received.");
        }
        JSONObject news_json = new JSONObject(body);
        RetrieveNewsFromJSON(news_json, newsl);
    }

    public static void RetrieveNewsFromJSON(JSONObject src, ArrayList<News> newsl) throws JSONException{
        JSONArray list;
        JSONObject obj;
        list = src.optJSONArray("data");
        for (int i = 0; i < list.length(); i++) {
            News news = new News();
            obj = list.getJSONObject(i);//这一页里的第i条新闻
            news.id = obj.optString("_id");
            news.content = obj.optString("content");
            news.date = obj.optString("date");
            news.seg_text = obj.optString("seg_text").split(" ");
            news.source = obj.optString("source");
            news.title = obj.optString("title");
            news.type = obj.optString("type");
            newsl.add(news);//把旧新闻一条一条加到新闻列表的末端
        }
    }


    public static int RenewNewsFromJSON(JSONObject src, ArrayList<News> newsl) throws JSONException {
        String latest_id = newsl.get(0).id;
        int num = 10;
        String id = "";
        JSONArray list;
        JSONObject obj;
        list = src.optJSONArray("data");
        for (int i = 0; i < list.length(); i++){
            obj = list.getJSONObject(i);
            id = obj.optString("_id");
            if(id.equals(latest_id)){
                num = i;
                break;
            }
        }
        for (int i = num - 1; i >= 0; i--) {
            News news = new News();
            obj = list.getJSONObject(i);//这一页里的第i条新闻
            news.id = obj.optString("_id");
            news.content = obj.optString("content");
            news.date = obj.optString("date");
            news.seg_text = obj.optString("seg_text").split(" ");
            news.source = obj.optString("source");
            news.title = obj.optString("title");
            news.type = obj.optString("type");
            newsl.add(0, news);
        }
        return num;
    }
}


package com.java.zhushuqi.ui.data;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;


import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import com.java.zhushuqi.R;


/**
 * A placeholder fragment containing a simple view.
 */
public class PlaceholderFragment extends Fragment {

    private static final String ARG_SECTION_NUMBER = "section_number";

    private PageViewModel pageViewModel;

    public static PlaceholderFragment newInstance(int index) {
        PlaceholderFragment fragment = new PlaceholderFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(ARG_SECTION_NUMBER, index);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        pageViewModel = ViewModelProviders.of(this).get(PageViewModel.class);
        int index = 1;
        if (getArguments() != null) {
            index = getArguments().getInt(ARG_SECTION_NUMBER);
        }
        pageViewModel.setIndex(index);
    }

    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_main, container, false);
//        final TextView textView = root.findViewById(R.id.section_label);
        final WebView webView = root.findViewById(R.id.web);
        pageViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
            @Override
            public void onChanged(@Nullable String s) {
                WebSettings settings = webView.getSettings();
                settings .setRenderPriority(WebSettings.RenderPriority.HIGH);
                //开启本地DOM存储
                settings.setDomStorageEnabled(true);
                settings.setUseWideViewPort(true);
                settings.setLoadWithOverviewMode(true);
                // 是否可访问Content Provider的资源,默认值 true
                settings.setAllowContentAccess(true);
                // 是否可访问本地文件,默认值 true
                settings.setAllowFileAccess(true);
                settings.setJavaScriptEnabled(true);
                settings.setSupportZoom(true);

                webView.loadUrl(s);
                webView.setWebViewClient(new WebViewClient(){
                    @Override
                    public boolean shouldOverrideUrlLoading(WebView view, String url) {
                        //使用WebView加载显示url
                        view.loadUrl(url);
                        //返回true
                        return true;
                    }
                });
            }
        });
        return root;
    }
}
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木头科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值