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

news2024/11/18 6:04:00

目 录

一、概述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.coloradmin.cn/o/70312.html

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

相关文章

185: vue+openlayers 引用hover插件,展示各种鼠标cursor样式

第185个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+openlayers中使用hover效果,这里是引用了一个hover插件。鼠标对应到相应的feature中时候,获取其类型,并且设定不同的鼠标样式。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意如果Ope…

一篇知晓-内存竟被”无意“破坏,真相究竟如何?

内存是C/C程序员的好帮手&#xff0c;我们通常说C/C程序性能更高其原因之一就在于可以自己来管理内存&#xff0c;然而计算机科学中没有任何一项技术可以包治百病&#xff0c;内存问题也给C/C程序员带来无尽的烦恼。 野指针、数组越界、错误的内存分配或者释放、多线程读写导致…

kotlin之hello world

如果你想一个人写全栈的话&#xff0c;Kotlin Multiplatform &#xff08;以下简称MPP&#xff09;是目前这个星球上最好的选择&#xff0c;没有之一。 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言&#xff0c;被称之为 Android 世界的Swift&#xff0c;由 JetBrain…

CTFSHOW web入门 java反序列化篇(更新中)

在做这部分题前&#xff0c;推荐大家先去学习下java反序列化&#xff0c;尤其是CC链 可以看下两个系列视频&#xff0c;收获颇多 https://space.bilibili.com/2142877265/channel/collectiondetail?sid29805&ctype0 https://www.bilibili.com/video/BV16h411z7o9/?spm_i…

手写Spring2(实现 Bean 的定义、注册、获取)

文章目录前言本章目标一、实现1、项目结构2、BeanFactory-bean工厂3、BeanDefinition -bean定义4、单例注册接口定义和实现-SingletonBeanRegistry 、DefaultSingletonBeanRegistry5、AbstractBeanFactory-抽象bean工厂类(定义模板方法)6、AbstractAutowireCapableBeanFactory-…

python配置环境问题记录------2022/12/07

python配置问题记录1、版本匹配的问题2、指令安装相关依赖包3、pycharm指定解释器4、运行网络模块5、总结1、版本匹配的问题 到官网下载合适的版本&#xff08;注意位数&#xff0c;我这里选的是64位&#xff09;&#xff0c;pycharm选的是21年版本的&#xff0c;太新的话会有…

【C++】异常exception

目录 一.C语言错误处理方式 1.assert(断言) 2.返回/设置错误码 二.C异常的概念与使用 1.异常的概念 2.异常的使用 三.自定义异常体系MyException 四.异常的重新抛出 五.异常安全问题 六.异常规范 七.异常的优缺点对比 一.C语言错误处理方式 一个C语言程序, 在运行期…

回归分析与相关分析的区别和联系

在本节中&#xff0c;我们将首先讨论相关性分析&#xff0c;它用于量化两个连续变量之间的关联&#xff08;例如&#xff0c;独立变量与因变量之间或两个独立变量之间&#xff09;。 最近我们被客户要求撰写关于回归分析与相关分析的研究报告&#xff0c;包括一些图形和统计输…

软件测试经验与教训

下面精选出10条&#xff0c;和大家分享。 01 测试人员是项目的前灯 一个项目就像是一次陆上旅行。有些项目很简单、很平常&#xff0c;就像是大白天开车去商店买东西。但是大多数值得开发的项目更像是夜间在山里开越野卡车&#xff0c;这些项目需要前灯&#xff0c;而测试员要照…

直播带货行业如何入局?先了解一下直播商城源码吧

直播行业的爆火已经持续了多个年头&#xff0c;直到今天&#xff0c;在人们的生活中依然有着举足轻重的地位&#xff0c;它通过多元化的方案为许多行业带来了新的思路&#xff0c;特别是与传统商业所结合的“直播电商”、“直播商城”的卖货新形式&#xff0c;让多方因此而受益…

数理化解题研究杂志社数理化解题研究编辑部2022年第30期目录

教学改革探索 信息技术下中职数学“翻转课堂”教学创新策略研究 李宇仙; 2-4《数理化解题研究》投稿&#xff1a;cn7kantougao163.com 基于高中数学核心素养的错题讲评课之探索与实践 施浩妹; 17-20 高中数学“问题导学”模式的实践研究 吴金桥; 21-23 立于神而…

【测试沉思录】21. 如何用 JMeter 编写性能测试脚本?

作者&#xff1a;宋赟 编辑&#xff1a;毕小烦 Apache JMeter 应该是应用最广泛的性能测试工具。怎么用 JMeter 编写性能测试脚本&#xff1f; 1. 编写 HTTP 性能测试脚本 STEP 1. 添加 HTTP 请求 STEP 2. 了解配置信息 HTTP 请求各项信息说明&#xff08;以 JMeter 5.1 为例…

【强化学习论文合集】十.2018智能体和多智能体系统国际联合会议论文(AAMAS2018)

强化学习(Reinforcement Learning, RL),又称再励学习、评价学习或增强学习,是机器学习的范式和方法论之一,用于描述和解决智能体(agent)在与环境的交互过程中通过学习策略以达成回报最大化或实现特定目标的问题。 本专栏整理了近几年国际顶级会议中,涉及强化学习(Rein…

十四、SpringBoot-自动装配原理

十四、SpringBoot-自动装配原理 SpringBoot与Spring比较起来&#xff0c;优化的点主要有&#xff1a; 自动配置&#xff1a;是一个运行时&#xff08;应用程序启动时&#xff09;的过程&#xff0c;考虑了众多因素&#xff0c;才决定Spring配置应该用哪个&#xff0c;不该用哪…

软件测试基础丨测试工程师之间要善于发现闪光点——测试理念篇

测试理念有多种&#xff0c;有一些理念&#xff0c;深藏于我的心中&#xff0c; 而这些理念&#xff0c;您或许偶尔想到&#xff0c;却没有说出&#xff0c;或许您感受到了&#xff0c;却因为工作生活的忙碌&#xff0c;没有将其背后的含义想具体&#xff0c; 在此我非常愿意和…

零基础小白hadoop分布式集群环境搭建(超详细)

搭建集群所需要安装包 虚拟机、ubuntu镜像文件、jdk安装包、hadoop安装包 百度云盘地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ejVamlrlyoWtJRo1QQqlsA提取码&#xff1a;fcqm 本文的环境是两台windows笔记本&#xff0c;在每台笔记本上安装一个虚拟机&…

超详细的水果FL Studio21最新版更新全功能详细介绍!80项更新与改进!

万众期待的 FL Studio 21 版本将于正式发布上线&#xff0c;目前在紧锣密鼓的安排上线中&#xff0c;届时所有购买正版 FL Studio 的用户&#xff0c;都可以免费升级到21版&#xff01;按照惯例&#xff0c;本次新版也会增加全新插件&#xff0c;来帮助大家更好地创作。今天先给…

SMART原则介绍

一、SMART原则简介 什么是SMART原则? SMART原则(S=Specific、M=Measurable、A=Attainable、R=Relevant、T=Time-bound)是为了利于员工更加明确高效地工作,更是为了管理者将来对员工实施绩效考核提供了考核目标和考核标准,使考核更加科学化、规范化,更能保证考核的公正、…

五万字详解“GoF”的23种设计模式

大家好&#xff0c;我是栗筝i&#xff0c;近期我总结梳理了 “GoF”的 23 种设计模式&#xff0c;并使用 Java 对每种设计模式都进行了伪代码与 Demo 实现&#xff0c;并总结了每种设计模式的应用场景&#xff0c;优缺点&#xff0c;UML图等相关内容&#xff0c;字/词数达到了5…

Java中的String

/*** 关于java.lang.String类* 1、String表示字符串类型&#xff0c;属于引用数据类型&#xff0c;不属于基本数据类型* 2、在java中用双引号括起来的都是String对象* 3、java中规定&#xff0c;字符串是不可变的* 4、字符串存储在方法区的字符串常量池当中*/ …