安卓APP源码和设计报告——北京旅游系统

目 录

一、概述11

1.1 课题描述11

1.2 需求分析22

1.3 开发环境33

二、系统分析与概要设计55

2.1 系统功能分析55

2.2 系统模块结构图66

2.3 数据库表的设计66

三、北京旅游系统的登录功能模块的详细设计88

3.1 登录模块的功能描述88

3.2 登录模块的界面布局的设计99

3.3 注册模块的Activity的设计1111

3.3.1 添加用户模块信息1414

3.3.2 删除用户模块信息1616

四、北京旅游系统的旅游攻略功能模块的详细设计2121

4.1 旅游攻略模块的功能描述2121

4.2 旅游攻略模块的界面布局的设计2222

4.3 旅游攻略模块的Activity的设计2424

4.3.1旅游攻略的列表的实现2626

4.3.2旅游攻略的菜单的实现2929

4.3.3 查找旅游攻略模块信息3131

五、系统测试3636

5.1 登录功能模块测试3636

5.2 景点攻略功能模块测试3636

5.3 社区评论功能模块测试3737

六、项目总结3838

七、参考文献3939

一、概述

1.1 课题描述

中国旅游业发展趋势众所周知已经越来越火爆,而北京的旅游景点更是许多人的第一选择,但是只从线下购票的方式很难实现持续发展。随着生活水平的不断提高,旅游成为人们生活不可或缺的一部分;旅游本是享受,然而传统旅游的一成不变的模式、千篇一律的线路,成为游客集中抱怨的焦点;因此,自助游越来越受到人们的青睐。

现在旅游行业不同往日,逐年的高速发展人们已经离不开网络了。以前旅游的方法和现在旅游已经有很大的不同,互联网可以让人们更好的生活,在想要旅游点击网络就可以获得大量的旅游攻略、景点介绍、小理票务、预订酒店等信息,利用网络的方便来旅行已经是大势所趋,利用互联网对于旅游爱好者来说方使了很多,也节省了很多的时间来做一些排队买票这类的事,有关旅游这方面的服务都得到了经济上的增长,现在旅游的趋势是旅游的主要竞争手段转移到了于机应用上,利用手机的便捷及手机应用的全面性取得了广大旅游用户的喜爱。

现在有关旅游的应用软件主攻的服务方向不同,其中一类是包容性的,也就是在一个应用上可以选择多个应用,另外一类具有专攻性质,如酒店预订功能,票务预订功能、旅游攻略功能等,不论它们倾向哪一种,每一位旅行爱好者的手机中都会有一款旅游应用。现在是物联网大数据时代,各种各样的信息将向每一个人袭来,手机中的旅游应用也会提供游客各种有关旅游的信息。

大部分使用者都希望有一种全面的旅游手机应用软件,所以制作手机旅游软件需要有更多的实用功能,任何一个使用者都可以在软件中找到自己想要的服务,这就促成了一体化服务的产生,这些用户想要功能在一起,就可以让用户更加快捷的去旅游,利用一些零散的时间,完全足够旅行者了解想要去的地方。这些年来手机上的旅游应用越来越多,让人们不再以以前单一的旅游方式活动,旅游是放松人精神的一种活动,可以让人们更加热爱生活享受生活,旅游应用逐年的改进,方便了广大的旅行爱好者,只要是用户有可能需要的服务,手机旅游应用中都会有,这就让游客感受到旅游是一种纯粹的亨受生活的方式,现在人们使用的手机应用有很多。

在科技飞速发展的今天,我们已经离不开网络,手机旅游应用中的各种功能不断改善,越来越强大,各种旅游软件公司都想让自己在旅游业有更强的竞争力,让更多的用户使用它们的产品。网络与手机的结合使旅行更加方便,因此旅游应用软件也越来越火爆,成为了人们必备的手机应用。随着自助游的快速发展,市场上关于旅游的应用程序方兴未艾,但针对旅游景点开发的应用程序尚处于不成熟阶段,所以此次我开发一个关于北京旅游的APP。

1.2 需求分析

1.2.1 技术需求

北京旅游App方便广大游客更容易针对性的对地方进行旅游攻略,北京旅游APP系统在Java、Android、XML、SQLite数据库上的技术应用需求极其广泛,包含界面和后端程序的开发。通过借助这些技术使整个前后端的衔接变得更加顺利,并且在开发程序时所使用的系统环境、应用环境上都有较为明显的适用体现,能够做到功能完善、整体架构清晰、整齐划一的操作流程。在对于数据库的建立和维护方面,都更贴合系统要求,实现数据正确安全,保证系统的顺利进行。同时,旅游APP对于整个类似系统的技术设计进行了详细的分析,这对于开发本系统所使用的技术环境提供了极大的帮助。

1.2.2 功能需求

(1)登录

首先进行登录操作,通过输入正确的用户名、密码即可登录成功,还有记住密码和自动登录功能,然后进入旅游app首页界面,从而对数据进行相关操作,达到可视化的实时效果。

  1. 注册
    在注册页面,可以进行游客信息的注册,能够选择账号和填写密码并添加到数据库中。
  2. 首页
    首页头部有搜索,可以搜索旅游信息功能,往下就是一个轮播图,是北京旅游景点的特色地方,其次是各个景点的点击,能进行查看景点。
  3. 发现
    采用瀑布式布局,发现页面可以实现旅游信息的查看,可查看景点的具体信息,点击图片进行具体历史文化的展示,包含RecyclerView展示各种景点,点击图片可以跳转到相应的景点介绍。
  4. 社区评论
    展示各个景点评论的界面。
  5. 个人中心
    游客信息展示,包含4个按钮,包含个人信息、账号安全、我的收藏、旅行日记4个按钮,可以进行自己的旅游心得记录。
    1.3 开发环境
    1.3.1 Android简介
    Android是一种基于Linux的自由及开放源代码的操作系统,Android 分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和 Linux内核层。
    Android有四大基本组件:Activity、Service、broadcast receiver、Content Provider。其中Activity是四大组件中最基本的一个,但基础并不等同于简单、不重要。恰恰相反,Activity作为基础组件,学好Activity就是我们开发者学好Android的前提。
    1.3.2 Java简介
    Java语言是一款非常热门的并且又具有代表性的编程语言,在实际应用过程中有着不可替代的作用。Java语言实际上是一种面向对象类型的编程语言,在实际开发领域中也会借助系统自带的功能去实现系统的设计,包含类、接口等功能的辅助实现,以此完成整个系统的设计。那么对于其中的接口来说,封装可以说是一种很好的辅助方式,可以按照人们传统的思想观念,实现父与子之间的功能的继承,免去编写代码时的重复度,简化复杂性,实现动态、多态的应用环境,达到标准的应用效果。Java语言实际上就是整个系统的后台,主要实现程序的后台管理,通过结合类、接口并配置数据库连接等操作来完成整个后端数据的动态显示,实现对存储数据的高效衔接和日常交互、维护的一体化管理。
    1.3.3 XML简介
    XML的简单易于在任何应用程序中读/写数据,这使XML很快成为数据交换语言,虽然不同的应用软件也支持其他的数据交换格式,但不久之后它们都将支持XML,那就意味着程序可以更容易的与Windows、Mac OS、Linux以及其他平台下产生的信息结合,然后可以很容易加载XML数据到程序中并分析它,并以XML格式输出结果。
    扩展标记语言与Access,Oracle和SQL Server等数据库不同,数据库提供了更强有力的数据存储和分析能力,例如:数据索引、排序、查找、相关一致性等,可扩展标记语言仅仅是存储数据。事实上它与其他数据表现形式最大的不同是:可扩展标记语言极其简单,这是一个看上去有点琐细的优点,但正是这点使它与众不同。
    1.3.4 SQLite数据库简介
    SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。
    1.3.5运行环境需求
    操作系统: Android手机基于Linux 操作系统
    Android系统要求无响应时间为5秒,所以旅游攻略、景点查看、社区评论、个人中心、发表看法等等操作的系统响应时间最长均不能超过5秒。
    支持环境:Android 11-13版本。
    二、系统分析与概要设计
    2.1 系统功能分析
    1.第一个页面是用户登录界面,有用户注册、用户登录、退出、记住我的下次再说功能。退出Dialog与用户交互。有记录登录功能(Sharedpreferences实现):设计注册和登陆界面,要求实现保存用户登录信息的功能,用户第一次登录时可设置是否记录密码和是否自动登录。如果用户勾选记住密码复选框,则下次登录时,会直接默认登录系统。用户如果想切换账号,可以先退出账号再登录。
    2. 注册界面,若用户合法完成注册后返回到登录页面,并使用Toast提示注册成功,密码和账号都不能为空,否则会使用Toast提示账号不能为空,密码不能为空 。
    3. 登录成功后,默认显示的页面是首页,下方导航栏的是旅游攻略、社区评论和个人中心。
    4. 首页Fragment,上面有一个搜索框,搜索框下面紧挨着是每一个景点的介绍图,可以点击到关于北京海洋馆、南宫旅游景区、长城等的页面进行景点展示介绍。
  6. 发现Fragment,包含RecyclerView展示各种景点,点击图片可以跳转到相应的景点介绍。

6. 社区评论Fragment,展示各个景点评论的界面。

7.个人中心Fragment,包含个人信息、账号安全、我的收藏、旅行日记4个按钮,可以进行自己的旅游心得记录。

2.2 系统模块结构图

图2-1

2.3 数据库表的设计

用户管理模块

用户管理tb_user用来存储用户个人信息,主要包括username、passwordphone等字段。

tb_user表结构如表2-2所示:

表2-2 tb_user表

名称类型是否可空备注
usernametext登录名
passwordtext密码

景点信息管理模块

旅游信息表tb_goods用来存储景点信息,主要包括id、imgId、goodsName、goodsStock等字段。

t_goods表结构如表2-3所示:

表2-3 t_goods表

名称类型是否可空备注
idinteger主键自动递增
imgIdinteger图片id
goodsNametext景点名

客户端、服务器和数据库之间的访问过程图:

图2-2

3.1 登录模块的功能描述

登录模块的功能是游客在文本框中输入用户名和密码后,点击“登录”按钮,activity会获取到输入的用户名和密码,并且使用数据库进行条件查询,将查询到的数据放入cursor游标对象中,然后进行判断,若cursor能够进行游标下移操作,则证明用户名和密码正确,然后将从数据库中取出的id等字段数据添加到bundle中用,再将bundle通过intent.putExtras(bundle)方法存入intent以进行activity之间的数据传输,最后通过startActivity跳转到MActivity,登录成功。若输入的用户名和密码不正确或有未填写项,则使用Toast提示用户名或密码不正确。

3.2 登录模块的界面布局的设计

图3-1

public class LoginActivity extends Activity {

MySqliteOpenHelper helper = null;

private static final String TAG = "LoginActivity";

private Activity activity;

private ActionBar mTitleBar;//标题栏

private EditText etAccount;//手机号

private EditText etPassword;//密码

private TextView tvRegister;//注册

private Button btnLogin;//登录按钮

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

activity=this;

helper = new MySqliteOpenHelper(this);

setContentView(R.layout.activity_login);//加载页面

etAccount =(EditText) findViewById(R.id.et_account);//获取手机号

etPassword=(EditText)findViewById(R.id.et_password);//获取密码

tvRegister=(TextView)findViewById(R.id.tv_register);//获取注册

btnLogin=(Button)findViewById(R.id.btn_login);//获取登录

mTitleBar = (ActionBar)findViewById(R.id.myActionBar);

mTitleBar.setData(activity,"登录",0, 0, 0,getResources().getColor(R.color.colorPrimary), new ActionBar.ActionBarClickListener() {

@Override

public void onLeftClick() {

finish();

}

@Override

public void onRightClick() {

}

});

登录页面使用了线性布局,利用一个ImageView图片控件、两个EditText和两个Button实现了用户名和密码的输入框以及登录和注册两个按钮。

3.3 注册模块的Activity的设计

图3-2

用户注册页面采用相对布局,注册页面结构上使用线性布局的排列,该页面含有若干个文本输入框和按钮,一个可点击的图片按钮和一个单选按钮组,可以满足用户填写信息的需要。

tvRegister.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//跳转到注册页面

Intent intent=new Intent(activity, RegisterActivity.class);

startActivity(intent);

}

});

//设置点击按钮

btnLogin.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

//关闭虚拟键盘

InputMethodManager inputMethodManager= (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(),0);

//获取请求参数

String account= etAccount.getText().toString();

String password=etPassword.getText().toString();

if ("".equals(account)){//账号不能为空

Toast.makeText(activity,"账号不能为空", Toast.LENGTH_LONG).show();

return;

}

if ("".equals(password)){//密码为空

Toast.makeText(activity,"密码为空", Toast.LENGTH_LONG).show();

return;

}

User mUser = null;

String sql = "select * from user where account = ?";

SQLiteDatabase db = helper.getWritableDatabase();

Cursor cursor = db.rawQuery(sql, new String[]{account});

if (cursor != null && cursor.getColumnCount() > 0) {

while (cursor.moveToNext()) {

Integer dbId = cursor.getInt(0);

String dbAccount = cursor.getString(1);

String dbPassword = cursor.getString(2);

String dbNickName = cursor.getString(3);

Integer dbAge = cursor.getInt(4);

String dbEmail = cursor.getString(5);

mUser = new User(dbId, dbAccount,dbPassword,dbNickName,dbAge,dbEmail);

}

}

db.close();

if (mUser != null) {

if (!password.equals(mUser.getPassword())) {

Toast.makeText(LoginActivity.this, "密码错误", Toast.LENGTH_SHORT).show();

}else{

SPUtils.put(LoginActivity.this,SPUtils.USER_ID,mUser.getId());

Intent intent = new Intent(LoginActivity.this, MainActivity.class);

startActivity(intent);

finish();

}

}else{

Toast.makeText(LoginActivity.this, "账号不存在", Toast.LENGTH_SHORT).show();

}

}

});

}

@Override

protected void onResume() {

super.onResume();

}

}

图3-3

3.3.1 添加用户模块信息

private void initView() {

User user = null;

String sql = "select * from user where id = ?";

SQLiteDatabase db = helper.getWritableDatabase();

Cursor cursor = db.rawQuery(sql, new String[]{String.valueOf(userId)});

if (cursor != null && cursor.getColumnCount() > 0) {

while (cursor.moveToNext()) {

Integer dbId = cursor.getInt(0);

String dbAccount = cursor.getString(1);

String dbPassword = cursor.getString(2);

String dbNickName = cursor.getString(3);

Integer dbAge = cursor.getInt(4);

String dbEmail = cursor.getString(5);

user = new User(dbId, dbAccount,dbPassword,dbNickName,dbAge,dbEmail);

}

}

db.close();

if (user != null) {

tvAccount.setText(user.getAccount());

etNickName.setText(user.getNickName());

etAge.setText(String.valueOf(user.getAge()));

etEmail.setText(user.getEmail());

}

//保存

btnSave.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

SQLiteDatabase db = helper.getWritableDatabase();

String nickName = etNickName.getText().toString();

String age = etAge.getText().toString();

String email = etEmail.getText().toString();

if ("".equals(nickName)) {

Toast.makeText(mActivity,"昵称不能为空", Toast.LENGTH_SHORT).show();

return;

}

if ("".equals(age)) {

Toast.makeText(mActivity,"年龄不能为空", Toast.LENGTH_SHORT).show();

return;

}

if ("".equals(email)) {

Toast.makeText(mActivity,"邮箱不能为空", Toast.LENGTH_SHORT).show();

return;

}

String updateSql = "update user set nickName=?,age=?,email=? where id =?";

db.execSQL(updateSql,new Object[]{nickName,age,email,userId});

db.close();

Toast.makeText(mActivity,"保存成功", Toast.LENGTH_SHORT).show();

finish();//关闭页面

}

});

}

图3-4

3.3.2 删除用户模块信息

public class CollectActivity extends AppCompatActivity {

MySqliteOpenHelper helper = null;

private Activity myActivity;

private ActionBar mTitleBar;//标题栏

private LinearLayout llEmpty;

private RecyclerView rvCollectList;

private CollectAdapter mCollectAdapter;

private List<Strategy> strategyList;

private Integer userId;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_collect);

myActivity = this;

helper = new MySqliteOpenHelper(this);

rvCollectList = findViewById(R.id.rv_collect_list);

llEmpty = findViewById(R.id.ll_empty);

mTitleBar = (ActionBar) findViewById(R.id.myActionBar);

mTitleBar.setData(myActivity, "我的收藏", R.drawable.ic_back, R.drawable.ic_clear, 0, getResources().getColor(R.color.colorPrimary), new ActionBar.ActionBarClickListener() {

@Override

public void onLeftClick() {

finish();

}

@Override

public void onRightClick() {

AlertDialog.Builder dialog = new AlertDialog.Builder(myActivity);

dialog.setMessage("确认要清空所有数据吗");

dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

SQLiteDatabase db = helper.getWritableDatabase();

String sql = "delete from collect where userId="+userId;

db.execSQL(sql);

db.close();

Toast.makeText(myActivity, "删除成功", Toast.LENGTH_SHORT).show();

loadData();

}

});

dialog.setNeutralButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

}

});

dialog.show();

}

});

initView();

}

图3-5

3.3.3 修改个人信息模块信息

public class PasswordActivity extends AppCompatActivity {

MySqliteOpenHelper helper = null;

private Activity activity;

private ActionBar mTitleBar;//标题栏

private EditText etEmail;

private EditText etNewPassword;

private Integer userId;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

activity =this;

setContentView(R.layout.activity_password);

helper = new MySqliteOpenHelper(this);

userId = (Integer) SPUtils.get(activity,SPUtils.USER_ID,0);

etEmail = findViewById(R.id.et_email);

etNewPassword = findViewById(R.id.et_new_password);

mTitleBar = (ActionBar)findViewById(R.id.myActionBar);

mTitleBar.setData(activity,"重置密码", R.drawable.ic_back, 0, 0,getResources().getColor(R.color.colorPrimary), new ActionBar.ActionBarClickListener() {

@Override

public void onLeftClick() {

finish();

}

@Override

public void onRightClick() {

}

});

}

图3-6


四、北京旅游系统的旅游攻略功能模块的详细设计

4.1 旅游攻略模块的功能描述

旅游攻略页面通过Fragment的方式放置在fragment_tab_home中的,fragment_tab_home使用了约束布局,在页面底部用了BottomNavigationView底部导航视图放置四个自定义的菜单导航按钮,用fragment标签填充页面内容,从而实现点击底部按钮跳转到相应fragment的功能,还有轮播图是实现以及图片的点击时间,旅游攻略点点击以及页面跳转。

页面使用了适配器来显示旅游景点的信息,采用的是相对布局,在布局文件中将高度设置为wrap_content,用来确保适配器加载完毕后不会出现一条数据独占一整个页面的情况,布局里面使用了一个ImageView和两个TextView来进行布局,定义轮播图居中显示和圆角的设定是页面更美化。

4.2 旅游攻略模块的界面布局的设计

图4-1

protected void onCreate( Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

myActivity = this;

setContentView(R.layout.activity_main);

MyApplication.Instance.setMainActivity(myActivity);

userId = (Integer) SPUtils.get(myActivity,SPUtils.USER_ID,0);

llContent = (LinearLayout) findViewById(R.id.ll_main_content);

rbStrategy = (RadioButton) findViewById(R.id.rb_main_strategy);

rbCommunity = (RadioButton) findViewById(R.id.rb_main_community);

rbUser = (RadioButton) findViewById(R.id.rb_main_user);

mActionBar = (ActionBar) findViewById(R.id.myActionBar);

//侧滑菜单

mActionBar.setData(myActivity,"旅游攻略", 0, 0, 0, getResources().getColor(R.color.colorPrimary), new ActionBar.ActionBarClickListener() {

@Override

public void onLeftClick() {

}

@Override

public void onRightClick() {

}

});

initView();

setViewListener();

}

private void setViewListener() {

rbStrategy.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

mActionBar.setTitle("旅游攻略");

switchFragment(0);

}

4.3 旅游攻略模块的Activity的设计

图4-2

public class StrategyFragment extends Fragment {

MySqliteOpenHelper helper = null;

private Activity myActivity;//上下文

private RecyclerView rvList;

private StrategyAdapter strategyAdapter;

private LinearLayout llEmpty;

private EditText etQuery;//搜索内容

private ImageView ivSearch;//搜索图标

private List<Strategy> strategyList;

private Integer userId;

@Override

public void onAttach(Context context) {

super.onAttach(context);

myActivity = (Activity) context;

}

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.fragment_strategy, container, false);

helper = new MySqliteOpenHelper(myActivity);

rvList = (RecyclerView) view.findViewById(R.id.rv_list);

llEmpty = view.findViewById(R.id.ll_empty);

etQuery = view.findViewById(R.id.et_query);

ivSearch = view.findViewById(R.id.iv_search);

//获取控件

initView();

//软键盘搜索

ivSearch.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

loadData();//加载数据

}

});

//点击软键盘中的搜索

etQuery.setOnEditorActionListener(new TextView.OnEditorActionListener() {

@Override

public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

if (actionId == EditorInfo.IME_ACTION_SEARCH) {

loadData();//加载数据

return true;

}

return false;

}

});

return view;

}

图4-3

4.3.1旅游攻略的列表的实现

图4-4

private void initView() {

userId = (Integer) SPUtils.get(myActivity, SPUtils.USER_ID, 0);

GridLayoutManager layoutManager = new GridLayoutManager(myActivity, 2);//两列

layoutManager.setOrientation(LinearLayoutManager.VERTICAL);

//=1.3、设置recyclerView的布局管理器

rvList.setLayoutManager(layoutManager);

HashMap<String, Integer> mapSpaces = new HashMap<>();//间距

mapSpaces.put(RecyclerViewSpaces.TOP_DECORATION, 20);//上间距

mapSpaces.put(RecyclerViewSpaces.BOTTOM_DECORATION, 20);//下间距

mapSpaces.put(RecyclerViewSpaces.LEFT_DECORATION, 20);//左间距

mapSpaces.put(RecyclerViewSpaces.RIGHT_DECORATION, 20);//右间距

rvList.addItemDecoration(new RecyclerViewSpaces(mapSpaces));//设置间距

//==2、实例化适配器

//=2.1、初始化适配器

strategyAdapter = new StrategyAdapter();

//=2.3、设置recyclerView的适配器

rvList.setAdapter(strategyAdapter);

loadData();

strategyAdapter.setItemListener(new StrategyAdapter.ItemListener() {

@Override

public void ItemClick(Strategy strategy) {

Intent intent = new Intent(myActivity, StrategyDetailActivity.class);

intent.putExtra("strategy", strategy);

startActivityForResult(intent, 100);

}

});

}

private void loadData() {

String contentStr = etQuery.getText().toString();//获取搜索内容

strategyList = new ArrayList<>();

Strategy strategy = null;

String sql = "select * from strategy";

if (!"".equals(contentStr)){

sql+=" where title like ?";

}

SQLiteDatabase db = helper.getWritableDatabase();

Cursor cursor = db.rawQuery(sql,!"".equals(contentStr)?new String[]{"%"+contentStr+"%"}:null);

if (cursor != null && cursor.getColumnCount() > 0) {

while (cursor.moveToNext()) {

Integer dbId = cursor.getInt(0);

String title = cursor.getString(1);

String img = cursor.getString(2);

String content = cursor.getString(3);

String ticket = cursor.getString(4);

strategy = new Strategy(dbId,title, img, content, ticket);

strategyList.add(strategy);

}

}

Collections.reverse(strategyList);

if (strategyList != null && strategyList.size() > 0) {

rvList.setVisibility(View.VISIBLE);

llEmpty.setVisibility(View.GONE);

strategyAdapter.addItem(strategyList);

} else {

rvList.setVisibility(View.GONE);

llEmpty.setVisibility(View.VISIBLE);

}

}

@Override

public void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

if (requestCode == 100 && resultCode == RESULT_OK) {

loadData();//加载数据

}

}

}

4.3.2旅游攻略的菜单的实现

public class StrategyDetailActivity extends AppCompatActivity {

MySqliteOpenHelper helper = null;

private Activity mActivity;

private ImageView ivImg;

private TextView tvTitle;

private TextView tvTicket;

private TextView tvContent;

private EditText etContent;

private TextView tvLike;

private TextView tvCollect;

private ImageView ivvCollect;

private ImageView ivCollectCheck;

private ImageView ivLike;

private ImageView ivLikeCheck;

private ActionBar mActionBar;//标题栏

private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

private Integer userId;

private SQLiteDatabase db;

private Strategy strategy;

private LinearLayout llEmpty;

private RecyclerView rvList;

private CommentAdapter commentAdapter;

private List<Comment> commentList;

private int praiseCount = 0;//点赞数

private int collectCount = 0;//收藏数

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mActivity = this;

setContentView(R.layout.activity_strategy_detail);

helper = new MySqliteOpenHelper(this);

ivImg = findViewById(R.id.img);

tvTitle = findViewById(R.id.title);

tvTicket = findViewById(R.id.ticket);

tvContent = findViewById(R.id.content);

etContent = findViewById(R.id.et_content);

tvLike = findViewById(R.id.tv_like);

tvCollect = findViewById(R.id.tv_collect);

ivvCollect = findViewById(R.id.iv_collect);

ivCollectCheck = findViewById(R.id.iv_collect_check);

ivLike = findViewById(R.id.iv_like);

ivLikeCheck = findViewById(R.id.iv_like_check);

llEmpty = findViewById(R.id.ll_empty);

rvList = findViewById(R.id.rv_list);

mActionBar = findViewById(R.id.myActionBar);

//侧滑菜单

mActionBar.setData(mActivity, "明细信息", R.drawable.ic_back, 0, 0, getResources().getColor(R.color.colorPrimary), new ActionBar.ActionBarClickListener() {

@Override

public void onLeftClick() {

finish();

}

@Override

public void onRightClick() {

}

});

userId = (Integer) SPUtils.get(mActivity, SPUtils.USER_ID, 0);

strategy = (Strategy) getIntent().getSerializableExtra("strategy");

tvTicket.setText(strategy.getTitle());

tvTitle.setText(String.format("¥%s", strategy.getTitle()));

tvContent.setText(strategy.getContent());

Glide.with(mActivity)

.asBitmap()

.skipMemoryCache(true)

.load(strategy.getImg())

.diskCacheStrategy(DiskCacheStrategy.NONE)

.into(ivImg);

db = helper.getWritableDatabase();

if (userId > 0) {//已登录

//查询点赞状态

String selectPraiseSql = "select * from praise where articleId=" + strategy.getId() + " and type=" + ArticleTypeEnum.Strategy.getCode() + " and userId=" + userId;

Praise praise = null;

Cursor cursorPraise = db.rawQuery(selectPraiseSql, null);

if (cursorPraise != null && cursorPraise.getColumnCount() > 0) {

while (cursorPraise.moveToNext()) {

Integer dbId = cursorPraise.getInt(0);

Integer dbArticleId = cursorPraise.getInt(1);

Integer dbUserId = cursorPraise.getInt(2);

Integer dbType = cursorPraise.getInt(3);

praise = new Praise(dbId, dbArticleId, dbUserId, dbType);

}

}

图4-5

4.3.3 查找旅游攻略模块信息

图4-6

图4-7

private void getCommentList() {

String commentSql = "select c.*,u.nickName from comment c,user u where c.userId = u.id and c.type=" + ArticleTypeEnum.Strategy.getCode() + " and c.articleId=" + strategy.getId();

List<CommentVo> list = new ArrayList<>();

Cursor cursor1 = db.rawQuery(commentSql, null);

if (cursor1 != null && cursor1.getColumnCount() > 0) {

while (cursor1.moveToNext()) {

Integer dbId = cursor1.getInt(0);

Integer dbArticleId = cursor1.getInt(1);

Integer dbUserId = cursor1.getInt(2);

String dbContent = cursor1.getString(3);

String dbDate = cursor1.getString(4);

Integer dbType = cursor1.getType(5);

String nickName = cursor1.getString(6);

CommentVo comment = new CommentVo(dbId, dbArticleId, dbUserId, dbContent, dbDate, dbType, nickName);

list.add(comment);

}

}

if (list.size() > 0) {

commentAdapter.addItem(list);

rvList.setVisibility(View.VISIBLE);

llEmpty.setVisibility(View.GONE);

} else {

rvList.setVisibility(View.GONE);

llEmpty.setVisibility(View.VISIBLE);

}

}

//发表

public void publish(View view) {

if (userId == 0) {未登录,跳转到登录页面

Toast.makeText(mActivity, "请登录后操作", Toast.LENGTH_SHORT).show();

}else {//已经登录

String content = etContent.getText().toString();

if ("".equals(content)) {

Toast.makeText(mActivity, "请输入查找内容", Toast.LENGTH_SHORT).show();

return;

}

String insertSql = "insert into comment(articleId,userId,content,date,type) values(?,?,?,?,?)";

db.execSQL(insertSql, new Object[]{strategy.getId(), userId, content, sf.format(new Date()), ArticleTypeEnum.Strategy.getCode()});

Toast.makeText(mActivity, "成功", Toast.LENGTH_SHORT).show();

etContent.setText("");

getCommentList();

}

}

}

图4-8


五、系统测试

5.1 登录功能模块测试

5.1.1软件的测试环境

软硬件要求:系统环境 win7;硬件系统环境core i3、3G内存、500G硬盘。此外对其他软件几乎没有依赖性,程序健壮性较好。

5.1.2测试

建立一张模拟的SD卡,上传软件;测试软件的注册登录功能用户体验是否良好。

5.1.3测试阶段

按照软件测试的策略和过程分类,软件测试可分为单元测试、集成测试、确认测试、系统测试和验收测试。它们被依次顺序地执行,此模块实验主要是进行功能测试。

5.1.4测试结果

此北京旅游攻略软件登录模块用户体验良好,基本符合设计要求。

5.2 景点攻略功能模块测试

5.2.1 软件的测试环境

软硬件要求:系统环境 win7;硬件系统环境core i3、3G内存、500G硬盘。此外对其他软件儿乎没有依赖性,程序健壮性较好。

5.2.2测试

建立一张模拟的SD卡,上传软件;测试软件的景点攻略功能是否能完好查看、还有在线查看门票价格、在线评论功能是否顺畅、用户体验是否良好。

5.2.3软件测试的评价

软件功能评价:此北京旅游攻略软件景点攻略模块用户体验良好,基本符合设计要求。

结论:此软件的设计和论证是可行的。

5.2.4测试阶段

软件测试工程量大、过程复杂,在整个软件开发周期中占据着举足轻重的地位,需求调研和软什测试占据了软件开发三分之二时间。此模块实验主要是进行功能测试。

5.2.5测试结果

在课题后期进行了大力度的软件测试,按照测试的流程和规则,主要进行了功能测试。软件主要的 bug 表现为闪退、卡死等现象,在编辑器上观看log则能发现主要问题是运行时异常。我们主要对bug采取了异常拦截的方式进行调试完善,测试完成后软件稳定运行。

5.3 社区评论功能模块测试

5.3.1软件的测试环境

软硬件要求:系统环境 win7;硬件系统环境core i3、3G内存、500G硬盘。此外对其他软件儿乎没有依赖性,程序健壮性较好。

5.3.2测试

建立一张模拟的SD卡,上传软件;测试软件的社区评论功能用户体验是否良好。

5.3.3测试阶段

对于软什测试我们需要从不同的角度考虑,明确测试的目的,精细化测试的过程,对测试过程进行明确的分类,制定好测试计划,尽量做到细致以及全面的测试。此模块实验主要是进行功能测试。

5.3.4测试结果

此北京旅游攻略软件社区评论模块用户体验良好,基本符合设计要求。

六、项目总结

本文主要是对Android平台北京旅游攻略的分析设计,主要实现了景点介绍、在线评论、景点购票、旅行日记、景点收藏、个人登录退出等功能。在本文中第一章简要的介绍了课题目前背景、研究现状等;第二章中讲述了Android的系统分析与概要设计;第三章进行了详尽的登录模块功能分析;第四章进行详细设计以及编码实现工作;最后的第五章进行了软件的测试工作,完善软件。本设计的北京旅游攻略软件能够稳定运行,体积小且反映灵敏,但还是有几点不足的地方,例如最近查看旅游景点无法排序、代码编写冗余重复率高、图片素材布局不太美观等等。在以后我会改进软件的不足,以更优的编码水平,更高超的布局思维模型,并且学习更多新的知识重构这款软件。这款北京旅游攻略软件还是比较好的,适用于智能手机市场,有良好的用户体验和反应速度。相信随着智能手机在发展中国家的普及,它们市场上会拥有庞大的用户群。


七、参考文献

[1]王兴中.中国旅游资源开发模式与旅游区域可持续发展理念[J.地理科学,2014,24 (1) : 51-58.

[2]王慧云.旅游教育与旅游业可持续发展[J].桂林旅游高等专科学校学报,2015,32(3) : 101-106.

[3]章锦河.中国国际旅游业与国际贸易比较研究〔J.安徽师大学报,2014,17 (2) : 101-106.

[4]柯元旦. Android内核剖析[M].北京:电子工业出版社,2012: 59-70.

[5]丰生强. Android软件安全与逆向分析[M].北京:人民邮电出版社,2013:78-90.

[6]余成锋,李代平,毛永华. Android3.0内存管理机制分析[M].北京:北京人民

邮电出版社,2013: 55-80.

[7]佐冰冰. Android平台下Launcher启动器的设计与实现[D].哈尔滨:哈尔滨工业大学博士学位论文. 2012: 4-9.

[8]杜吉志,徐明昆. Android系统内存管理研究及优化[J].软件工程,2012,24 (5): 69-80.

[9]高巍. Android操作系统软件自动化测试方案的设计与实施[D].北京:北京邮电大学博士学位论文.2014: 8-14.

[10〕孙剑. Android系统上应用程序按需加载机制的设计与实现 [M].北京:北京大学出版社,2014: 99-110.

[11]卢娜.基于Android平台的手机桌面资讯系统的设计与实现〔M].西安:西安电子科技大学出版社,2012: 290-300.

(注:此页为报告内容末页,打印在单面,与报告装订在一起)

课程报告评分:

评分点得分
报告格式和排版(10分)
系统概要设计(20分)
系统详细设计(20分)
系统测试(20分)
总结(10分)
代码注释(20分)
总分(100分)
加分项(10分)

指导教师签字:

年 月 日

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4月17号软件资讯更新合集.....

CrateDB 5.3.0 发布&#xff0c;分布式 SQL 数据库 CrateDB 是一个分布式的 SQL 数据库&#xff0c;使得实时存储和分析大量的机器数据变得简单。CrateDB 提供了通常与 NoSQL 数据库相关的可扩展性和灵活性&#xff0c;最小的 CrateDB 集群可以轻松地每秒摄取数万条记录。这些…

利用DocsGPT快速搭建一个问答式的文档检索服务

docsGPT 示例 基于企业内部独有的知识库&#xff0c;进行智能的客服问答&#xff0c;毫无疑问是 ChatGPT 出圈以后&#xff0c;所有公司想要融入 ChatGPT 技术时的第一反应。可惜 ChatGPT 实际上是一个基于大语言模型实现的&#xff0c;包括很多其他功能的&#xff0c;完整的聊…

成绩管理系统

suan.h文件代码 #pragma once #define _CRT_SECURE_NO_WARNINGS #undef UNICODE #undef _UNICODE #include <stdio.h> #include <stdlib.h> #include <graphics.h> #include <time.h> #include <conio.h> #include<iostream> #include&l…

360全景热点panolens.js 实现代码

本片主要介绍360全景热点基于panolens.js 实现的代码&#xff0c;主要通过如下步骤实现&#xff1a; 1&#xff0c;引入核心js库 <script src"js/three.min.js"></script><script src"js/panolens.min.js"></script> 2&#xff0…

2020年360亿条数据遭泄露 网络安全产业风口要来了

[网络安全重磅福利&#xff1a;入门&进阶全套282G学习资源包免费分享&#xff01;](https://mp.weixin.qq.com/s/BWb9OzaB-gVGVpkm161PMw ) 数据被视为21世纪的“钻石矿”&#xff0c;蕴含着巨大的动能&#xff0c;并且具有边际效应递增的特点&#xff0c;在不断的流动共享…

360腾讯计算机比赛,巅峰对决 腾讯电脑管家VS360详尽评测

【IT168 评测】提起目前国内杀毒软件市场&#xff0c;可谓群雄割据&#xff0c;从老一批的瑞星、卡巴斯基、360&#xff0c;到近些年崛起的腾讯电脑管家似乎在杀毒界也风起云涌&#xff0c;近期业界又有消息称电脑管家获得AV-TEST认证&#xff0c;包揽了国际四大权威杀毒测试奖…

奇虎360软件阻止腾讯电脑管家启动,3Q大战将再度上演?

今天下午值班&#xff0c;使用同事的电脑上网。开机进入桌面后看见系统托盘区冒出360安全卫士和360杀毒软件的图标&#xff0c;立马全部退出。到腾讯电脑管家官网下载了安装程序进行安装。 安装程序窗口在安装进度达到99%后&#xff0c;忽然就消失了&#xff0c;系统托盘区也没…

本周大新闻|John Carmack从Meta离职,OPPO发布双目AR一体机仅38g

本周大新闻&#xff0c;AR方面&#xff0c;微软已向客户承诺新款HoloLens&#xff1b;NASA成立Joint AR项目&#xff0c;计划在宇航服头盔中加入AR功能&#xff1b;OPPO Air Glass 2发布&#xff0c;双目光波导仅38g&#xff1b;Rokid开设全球首家品牌旗舰店&#xff1b;谷歌为…

周鸿祎亲自站台,360年度新旗舰究竟有何特别?

众所周知&#xff0c;360自从推出手机之后&#xff0c;每一代产品都以高性价比著称。即便是在竞争早已趋于白热化的智能手机红海市场&#xff0c;360手机依然能够占有一席之地。 不过&#xff0c;虽然360手机已经迭代到了N7系列&#xff0c;但是“红衣教主”周鸿祎在发布会上露…

腾讯360

尊敬的360用户&#xff1a; 360推出扣扣保镖的本意&#xff0c;是为了让QQ更安全更好用。而腾讯公司的 举措让用户陷入两难&#xff0c;这有悖于我们的初衷。 为了避免让用户做两难的抉择&#xff0c;360决定暂时召回扣扣保镖产品。 对给您带来的不便&#xff0c;我们非常抱歉…

12月24日科技资讯|12306 回应软件崩了;微信发布新版本,朋友圈可“斗图”;Ant Design 3.26.4 发布

「极客头条」—— 技术人员的新闻圈&#xff01; CSDN 的读者朋友们早上好哇&#xff0c;「极客头条」来啦&#xff0c;快来看今天都有哪些值得我们技术人关注的重要新闻吧。扫描上方二维码进入 CSDN App 可以收听御姐萌妹 Style 的人工版音频哟。 一分钟速览新闻点&#xff…

360安全卫士上线新功能: 一周电脑安全动态全掌握

在互联网行业高速发展的今天&#xff0c;不管你从事何种行业&#xff0c;都离不开电脑办公&#xff0c;更不用说在生活娱乐中电脑所发挥的巨大作用&#xff0c;可以说电脑已经成了我们生活中必备的一部分。 电脑跟人类一样&#xff0c;不良的使用习惯、外来攻击都会给电脑健康…

OPPO Watch新品将于9月16日正式发布

2021 年 9 月 15 日&#xff0c;中国&#xff0c;深圳——OPPO今日宣布&#xff0c;OPPO Watch系列新款产品&#xff0c;将于 9 月 16 日在OPPO秋季新品发布会正式发布。 新款OPPO Watch将主打健康监测功能&#xff0c;可以实时监测用户的身体健康数据&#xff0c;并提供的健康…

腾讯会议发布3.0版本;微软将推出元宇宙产品;Firefox启动最大WebRTC升级|WebRTC风向

点击一键订阅《云荐大咖》专栏&#xff0c;获取官方推荐精品内容&#xff0c;学技术不迷路&#xff01; 近年来&#xff0c;实时音视频快速发展&#xff0c;WebRTC做为实时音视频的标准也快速发展&#xff0c;从直播到通讯&#xff0c;其应用场景也在不断丰富。如果您关注实时音…

360测试之美技术分享大会(第十季)圆满结束(附直播回放及PPT分享链接)

疫情居家&#xff0c;何以解忧&#xff1f;在线分享&#xff0c;也是一种不出家门可了解技术动态天下事的绝佳途径&#xff0c;对测试感兴趣的同学看过来哟~ 为了应对疫情影响&#xff0c;第十季测试之美技术分享大会于2022年12月3日上午九点半在360幕印平台准时开播。本次大会…

第六届 Techo TVP 开发者峰会暨腾讯云大数据峰会来啦

引言 50 年前&#xff0c;数据库管理系统、关系型数据库诞生&#xff0c;数据处理效率大大提升。数据库软件开始被应用于业务数据处理。20 年前&#xff0c;单机存储能力遭遇瓶颈&#xff0c;分布式存储计算架构成为主流。Apache Hadoop 成为大数据技术的代名词。 10 年前&…

360和腾讯QQ的那场战争!

阅读本文大概需要10分钟。 这是我的10年程序人生的第五篇&#xff0c;记录一场惊心动魄的商业大战&#xff1a;3Q大战。 在中国互联网历史上&#xff0c;3Q大战是标志性的一战&#xff0c;堪称互联网第一次世界大战。 彼时洋哥还是一个工作不到两年的基层员工&#xff0c;有幸…

腾讯安全威胁情报品牌发布会召开 打造开放、共享的情报生态圈

近年来&#xff0c;全球网络安全威胁态势愈发严峻&#xff0c;安全事件层出不穷&#xff0c;企业传统的安全防御策略显得越来越力不从心。如何快速高效应对持续性的网络威胁&#xff0c;构建更具实战和联动能力的威胁情报能力&#xff0c;实现安全防御上的“化被动为主动”&…

TCP连接中TIME_WAIT状态过多原因分析

1.time_wait状态过多原因 在高并发短连接的TCP服务器上&#xff0c;当服务器处理完请求后立刻主动正常关闭连接。主动关闭的一方在发送最后一个 ack 后就会进入TIME_WAIT 状态 停留2MSL&#xff08;max segment lifetime&#xff09;的时间&#xff0c;这个场景下&#xff0c;会…

服务器出现大量 TIME_WAIT,如何解决

经常在服务器发现一些连接出现 TIME_WAIT 状态&#xff0c;那么为什么会有 TIME_WAIT状态&#xff0c;它是如何产生的&#xff1f;大量的 TIME_WAIT 有什么危害&#xff1f;如何排查&#xff1f;如何优化&#xff1f;带着这些问题逐步分析&#xff1a; 1. TCP 连接回顾 TCP 创建…