对其软件要求较高,要考虑兼容性。首先,在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
新闻界面由顶部搜索栏(带图片装饰)与新闻展示栏两部分组成。其中新闻展示栏集RecyclerView
、SmartRefreshLayout
两个类为一体,添加了装饰线和加载动画,加载流畅。新闻的点击进入详情页利用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依赖包
标签增减功能位于主页右下角的设置栏中,我们利用ChipsView
组件及其相关动作函数实现了这一功能,方便且带有动态效果。我们利用Intent
在主界面Activity
与工具栏Activity
之间传递信息,从而实现了近乎同步的标签增删操作。
疫情界面主要为基础的主界面框架,WebView主要是嵌入了一个夸克网址(https://broccoli.uc.cn/apps/pneumonia/routes/index),Android WebView在Android平台上是一个特殊的View,基于webkit引擎、展现web页面的控件,这个类可以被用来在你的app中仅仅显示一张在线的网页,WebView内部实现是采用渲染引擎来展示view的内容,提供网页前进后退,网页放大,缩小,搜索。
现在很多APP都内置了Web网页,本项目采用的是夸克网站平台比如说很多电商平台,淘宝、京东、聚划算等等。WebView比较灵活,不需要升级客户端,只需要修改网页代码即可。一些经常变化的页面可以用WebView这种方式去加载网页。例如中秋节跟国庆节打开的页面不一样,如果是用WebView显示的话,只修改修改html页面就行,而不需要升级客户端。
疫情学者界面分为高关注学者与追忆学者两个标签,每个标签栏下有对应学者的信息(与新闻列表类似),最外层用竖向排列的 LinearLayout 包裹,它有两个子节点,上面是用于滑动和装载 Fragment 的 ViewPager,下面是两个 Tab 的布局。且能够点击进入学者名片,查看学者头像、生平简介、主要贡献等信息。这里也调用了一个Material Design Chip View库实现返回桌面。
在主界面右下角的工具栏中能够查看浏览历史,此处我们追踪了每一个新闻对象的”被浏览“事件,并在程序后台自动进行历史记录,同时能够在离线状态下进行查看。.当点击到某一个新闻的时候,访问数据库是否有该新闻的信息,有的话更新新闻浏览的时间,更新数据库。没有的话添加到数据库中。
利用系统自带的分享功能进行分享,目前能够通过任何能够发送文本的应用(包括蓝牙)分享包含新闻摘要与具体内容的纯文本。创建一个选择器,让用户自己选择分享到哪里。这里有一点得注意,Intent传递的数据的Type(就是setType()方法)一定要控制好,不然会出错。
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;
}
}