作品文档

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 32

移动应用开发

作品文档

作品名称: 茶博士

作 者: 王佳鸿,苏志源,吴培润

班 级:软件工程 3 班

填写说明:
1、 正文一律用五号宋体,一级标题为小二号黑体,其他级别标题如有需要,可根据
需 要设置;
2、 提交文档时,以 PDF 格式提交本文档。

日 期 : 2023.06.20
作品概要
作品名称:茶博士

总代码量: 2525 行

作品简介(200 字以内):茶博士是一个专注于茶叶知识和头条消息的项目。它旨在为茶叶爱好
者和对茶文化感兴趣的人提供一个全面了解茶叶的平台。通过茶博士,用户可以轻松获取各种
茶叶的详细信息,包括种类、产地、采摘和加工方式等。此外,茶博士还提供最新的茶叶行业
头条消息,包括新品发布、品鉴活动和茶文化活动等。无论是初学者还是专业人士,茶博士都
致力于为用户提供有价值的茶叶知识和精彩的茶文化内容,帮助用户深入了解茶叶世界,提升
茶叶品味和鉴赏能力。

创新描述(200 字以内):茶博士是一项创新性的项目,利用大数据技术,为用户
提供个性化的茶叶知识和头条消息。通过智能算法,茶博士能够根据用户的兴趣和
偏好,为他们推荐最适合的茶叶品种和相关资讯。这项创新技术不仅可以帮助用户
快速了解各种茶叶的特点和功效,还能根据用户的口味偏好,推荐适合他们的茶叶
搭配和冲泡方式,提供个性化的茶叶体验。茶博士还通过与茶叶供应商和茶文化专
家的合作,实时获取最新的茶叶行业动态和热门话题,确保用户始终掌握茶叶界的
最新趋势和新闻。此外,茶博士还提供互动社区功能,让用户可以分享自己的茶叶
经验、交流品鉴心得,并与其他茶叶爱好者进行互动。

作者及贡献值

姓名 1 姓名 2 姓名 3

贡献值(总的贡献值为 3,每
王佳鸿 苏志源 吴培润
1 1 1
个人的贡献值可为小数)
1. 需求分析
1.1 面向用户:
茶博士面向的用户主要是茶叶爱好者和对茶叶感兴趣的人群。具体包括以下用户:
1. 茶叶爱好者:对茶叶有浓厚兴趣,追求品质和独特的茶叶体验的人群。他们希
望了解不同茶叶品种、制作工艺和产地等相关知识,并希望通过茶博士获取最新的茶
叶行业动态和头条消息。
2. 初学者:对茶叶感兴趣但缺乏相关知识的人群。他们希望通过茶博士学习茶叶
的基础知识、品鉴技巧和冲泡方法,逐步了解茶叶的世界并提升自己的茶叶品鉴能力。
3. 社区交流者:喜欢与其他茶叶爱好者分享经验、交流心得的人群。他们希望通
过茶博士的社区功能与其他用户互动、讨论茶叶话题,并扩大自己的茶叶交流圈子。
4. 茶叶商家和供应商:希望通过茶博士宣传和推广自己的茶叶产品的商家和供应
商。他们希望通过茶博士的平台向用户展示自己的茶叶品牌、产品特点和购买链接,
增加茶叶销售和品牌影响力。

1.2 功能需求:
1. 界面设计:简洁美观的用户界面,方便用户快速查看信息。
2. 功能设计:
用户注册:用户如果是首次登录该应用就需要进行的注册,注册后下次即可登录。
用户登录:为确保用户的数据安全,用户进入应用中需要进行登录。
头条展示:主页中展示了最新的关于茶的头条信息。
茶叶品种展示:知道页面中可以展示出所有最新的茶叶,点击后可以查看到指定
的茶叶中的描述,烹饪方式,存储方式。
用户咨询:在咨询页面中,可以快速的咨询到相关茶叶的指定信息。
茶叶买卖经营方法展示:在经营模块中,可以快速的了解到如何进行茶叶的买卖
的经营方法。
茶叶市场数据展示:在数据模块中,用户可以快速的查询到市场的茶叶经营数据,
该数据通过图的形式来展示,更加具体直观,用户根据需求来制定自己的经营方式。
关键词搜索:在搜索模块中,通过关键词的输入,可以快速的搜索到相关的内容。
收藏:用户在其他页面中如果存在有喜欢的内容想要保存,在指定页面中点击收
藏后就可以自己的收藏中查询到自己收藏的内容。
分享:用户如果想要将该应用分享给其他的用户,可以使用该功能进行分享。
用户意见反馈:用户如果有想要对应用进行改进的地方,就可以在该功能下写入
想的建议,点击反馈后,应用的开发人员将会接收到相关的建议进行改进。
浏览记录查询:用户在该功能下,可以查看到自己的浏览过的相关的记录,也可
以将其删除。
3. 用户体验:
性能优化:保证数据加载速度和应用运行流畅。
稳定性:避免闪退、死机等问题,保证应用稳定运行。
操作简便:应用容易上手,使用简单而直观。
4. 用户安全与隐私:
用户数据保护:保证用户数据安全,不泄露用户隐私信息。
获取权限:获取必要的手机权限来提供更好的服务。
图 1 功能需求

1.2.1 客户端系统
客户端的主要划分为六大模块,各个模块为用户提供指定的重要功能使用。
具体细分如下所示:
1).个人空间模块:用户和可以进行搜索,管理分享,分享应用,意见的反馈,管
理浏览记录。
2).头条展示模块:展示最新的关于茶叶的相关的头条信息。
3).种类展示模块:展示各种茶叶,点击具体的茶叶后还可以查到相关的信息。
4).茶叶经营方法模块:展示茶叶买卖的相关的经营方法。
5).用户咨询模块:展示各种种类的做法等内容。
6).茶叶市场数据模块:展示茶叶买卖市场的相关的数据,并且并且以图的形式展
示。
图 2 客户端

1.3 性能要求
1.数据获取速度:
该应用需要能够迅速并准确地获取数据。用户需要获取到最新的实时的数据,因此,
应用需要能够在尽可能短的时间内获取并显示这些数据。
2.应用响应速度:
应用的 UI 必须流畅,无明显的卡顿或延迟。这包括滑动、点击、打开和关闭各种 UI
元素等。
3. 低资源消耗:
为了避免对手机电池寿命或其他应用的运行造成影响,应用需要在 CPU、内存和电池
使用方面保持高效。特别是,应用在后台运行时(例如,当它定期检查天气更新时),其
资源消耗应该保持在最低。
4. 网络效率:
应用应设计为在不同的网络条件下都能良好运行,包括低速或不稳定的网络环境。这
可能需要实现一些优化策略,例如数据压缩、缓存以及在数据获取失败时的重试机制。
5. 启动速度:
用户打开应用时,应用应能在短时间内启动并准备好供用户使用。
6. 系统兼容性:
应用需要在各种 Android 版本和设备上运行流畅,不会出现崩溃或其他错误。
图 3 性能需求

1.4 运行需求
1.网络连接:茶博士需要与互联网连接,以获取最新的茶叶信息、行业动态和头条消
息,并提供在线社区交流功能。用户需要通过稳定的网络连接访问茶博士的各项功能。
2.数据存储和处理:茶博士需要具备足够的存储空间来存储茶叶分类、详细信息、用
户个人账户数据等。同时,茶博士需要具备高效的数据处理能力,以支持茶叶推荐、个性
化推荐和用户交互等功能。
3.安全性和隐私保护:茶博士应该采取合理的安全措施,保护用户的个人信息和数据
安全。这包括使用加密技术保护数据传输过程中的安全性,以及合规地处理和存储用户数
据。
4.用户界面和交互设计:茶博士应该具备友好的用户界面和良好的交互设计,使用户
能够方便地浏览茶叶分类、获取茶叶信息、参与社区交流等。界面应该清晰明了,操作流
程应该简单易懂。
5.及时更新和维护:茶博士应该及时更新最新的茶叶信息、行业动态和头条消息,保
持内容的新鲜性和准确性。同时,茶博士需要进行定期的系统维护和升级,以确保应用的
稳定性和性能。
6.持续更新和支持:
应用程序需要持续收集用户反馈进行优化,提供技术支持和更新服务,保持与
Android 系统的兼容性。

2. 概要设计
1. 界面设计: 简洁美观的用户界面,在不同的页面实现了的相关的内容,首页中的主
要的显示了头条消息的展示,进入后可以快速的浏览的信息,其他的页面也是简洁的展示
出内容。
2. 数据源: 从数据库中查询出数据,主要的是使用的 sqlite 数据进行的查询出最新
的数据。
3. 数据存储: 存储用户收藏,历史记录等数据,使用 SQLite 数据库进行存储。通过
本地存储可实现出的收藏,历史记录等数据的查询。
4. 权限管理: 由于需要访问网络、定位、存储等敏感权限,需要在应用启动时动态申
请权限。同时需要遵循隐私保护原则,不会泄露用户的个人信息。
5. 自动更新: 系统会定时的查询得到的数据库的中的数据,得到最新的数据展示的到
页面中。
图 4 概要设计

2.1 系统模块层次
1. 个人空间模块:
1. 用户首次使用该应用,就应该先注册,在注册页面输入相关的信息后就完成
注册。
2. 用户注册完毕后进完成登录操作,在登录页面中输入用户名密码后登录成功。
3. 进入应用后可以右划,可以看到自己的个人空间,包括关键词搜索,我的收
藏,意见反馈,浏览记录和应用的版本信息。
4. a.点击搜索,进入关键词搜索,在文本输入框中输入关键词可以搜索出相关
的内容。
b.点击我的收藏,在这里可以快速的查看到从种类展示模块和茶叶经营模块
的收藏的内容,并且可以长按单独的删除收藏的内容或者是点击清空按钮全部清
空。
c.点击分享,用户可以通过短信等渠道将该应用分享给其他的用户,便于推
广。
d.点击意见反馈,在文本输入框中输入想要反馈的意见,点击的提交按钮,
开发人员即可收到相关的建议,对应用进行改进优化。
e.点击浏览记录,在这里可以快速的查看到从其他各个模块浏览过的所有的
内容和浏览的时间,并且可以长按单独的删除浏览记录或者是点击清空按钮全部
清空。
f.点击版本信息,可以查看到该应用的版本信息。

2. 头条展示模块:
1. 通过注册后登录应用,进入主页面。
2. 主页面即为头条展示模块,该页面中展示了最新的关于茶的相关的头条消息,
主要是以 ViewPager 组件和线性布局实现了该页面。
3. 页面中展示的是头条消息的标题,用户可以简要的浏览的简要的信息。
4. 点击指定的头条信息,可以进入该头条消息的详情页面,查看到该头条的详
细内容。

3. 种类展示模块:
1. 通过注册后登录应用,进入主页面,在下方的导航栏中选择知道,进入种类
展示模块。
2. 该页面会展示所有的茶叶的种类,主要是以图片加名称的形式展示,用户可
以快速的浏览和了解茶叶的主要信息。
3. 点击的指定的茶叶的图片,进入到茶叶的详细信息,主要的包括的的信息有
茶叶图片,具体描述,做法和存储方式。用户可以快速的了解到该茶叶。
4. 该页面中具有点赞和收藏功能,用户可以点击点赞功能来表达对该茶叶的喜
爱,点击收藏还可以对该茶叶进行收藏,在个人中心的收藏中可以查看到。

4. 用户咨询模块:
1. 通过注册后登录应用,进入主页面,在下方的导航栏中选择咨询,进入用户
咨询模块。
2. 在该页面中,用户可以通过浏览页面中展示的简要的信息快速的了解到相关
茶叶。
3. 页面主要是展示了茶叶的名称,做法还有存储方式,简洁的将内容的展示出。

5. 茶叶经营方法模块:
1. 通过注册后登录应用,进入主页面,在下方的导航栏中选择咨询,进入用户
咨询模块。
2. 该页面中展示了如何进行茶叶买卖经营,以供用户进行学习,便于其更快的
去进行茶叶的经营。
3. 点击进入到指定的方法信息,进入到该方法的详情,用户可以具体的了解到
该方法的具体做法和方式。
5. 该页面中具有点赞和收藏功能,用户可以点击点赞功能来表达对该文章的喜
爱,点击收藏还可以对该文章进行收藏,在个人中心的收藏中可以查看到。

6. 茶叶市场数据模块:
1. 通过注册后登录应用,进入主页面,在下方的导航栏中选择数据,进入茶叶
市场数据模块。
2. 该页面会展示的茶叶市场的交易等相关的数据,用户可以通过这个了解到茶
叶市场的行情,并且对自己的经营方式方法进行调整。
3. 页面中的信息是以图的方式进行展示,用户可以通过点击图中的内容,对图
进行调整样式,使其可以更加快速方便清晰的了解到相关的数据。

3. 详细设计
3.1 功能模块设计
图 5 功能模块

1. 个人空间模块
- 用户注册:用户如果是首次登录该应用就需要进行的注册,注册后下次即可登录。
- 用户登录:为确保用户的数据安全,用户进入应用中需要进行登录。
- 用户咨询:在咨询页面中,可以快速的咨询到相关茶叶的指定信息。
- 关键词搜索:在搜索模块中,通过关键词的输入,可以快速的搜索到相关的内容。
- 收藏:用户在其他页面中如果存在有喜欢的内容想要保存,在指定页面中点击收藏
后就可以自己的收藏中查询到自己收藏的内容。
- 分享:用户如果想要将该应用分享给其他的用户,可以使用该功能进行分享。
- 用户意见反馈:用户如果有想要对应用进行改进的地方,就可以在该功能下写入想
的建议,点击反馈后,应用的开发人员将会接收到相关的建议进行改进。
- 浏览记录查询:用户在该功能下,可以查看到自己的浏览过的相关的记录,也可以
将其删除。
2. 头条展示模块
- 头条展示:主页中展示了最新的关于茶的头条信息。
3. 种类展示模块
- 茶叶品种展示:知道页面中可以展示出所有最新的茶叶,点击后可以查看到指定的
茶叶中的描述,烹饪方式,存储方式。
4. 茶叶经营方法模块
- 茶叶买卖经营方法展示:在经营模块中,可以快速的了解到如何进行茶叶的买卖的
经营方法。
5. 茶叶市场数据模块
- 茶叶市场数据展示:在数据模块中,用户可以快速的查询到市场的茶叶经营数据,
该数据通过图的形式来展示,更加具体直观,用户根据需求来制定自己的经营方式。

4. 实现:
核心代码:

//底部按钮点击事件
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener{

private BottomNavigationView.OnNavigationItemSelectedListener
mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {

//底部按钮跳转(默认情况下,没有任何 item 被选中,就不会触发


onNavigationItemSelected 方法,也就不会执行任何操作)
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_headlines:

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
HeadlinesFragment()).commit();
return true;
case R.id.navigation_know:

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
KnowFragment()).commit();
return true;
case R.id.navigation_consult:

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
ConsultFragment()).commit();
return true;
case R.id.navigation_operate:

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
OperateFragment()).commit();
return true;
case R.id.navigation_data:

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
DataFragment()).commit();
return true;
}
return true;
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//检查是否联网
boolean isNetwork=isNetworkAvailable(this);
if (!isNetwork) {
Toast.makeText(getApplicationContext(), "设备没有联网" ,
Toast.LENGTH_SHORT).show();
}
setContentView(R.layout.activity_main);

//底部按钮
BottomNavigationView navigation = (BottomNavigationView)
findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListene
r);

//设置导航栏
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);


ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer,
toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();

NavigationView navigationView = (NavigationView)


findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);

getSupportFragmentManager().beginTransaction().replace(R.id.frame, new
HeadlinesFragment()).commit();
}

@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is
present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();

//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}

return super.onOptionsItemSelected(item);
}

@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Intent intent=new Intent();

// Handle the action,侧边栏按钮点击页面跳转


switch (id) {
case R.id.nav_search:
intent.setComponent(new
ComponentName(MainActivity.this,Search.class));
startActivity(intent);
return true;
case R.id.nav_collections:
intent.setComponent(new
ComponentName(MainActivity.this,Collections.class));
startActivity(intent);
return true;
case R.id.nav_share:
sharePage();
return true;
case R.id.nav_opinions:
intent.setComponent(new
ComponentName(MainActivity.this,Opinions.class));
startActivity(intent);
return true;
case R.id.nav_records:
intent.setComponent(new
ComponentName(MainActivity.this,Records.class));
startActivity(intent);
return true;
case R.id.nav_version:
intent.setComponent(new
ComponentName(MainActivity.this,Version.class));
startActivity(intent);
return true;
}

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);


drawer.closeDrawer(GravityCompat.START);
return false;
}

//分享到其他应用
private void sharePage() {

Intent shareIntent = new Intent(Intent.ACTION_SEND); // 创建一个


ShareIntent 对象
shareIntent.setType("text/plain"); // 设置分享内容的类型
shareIntent.putExtra(Intent.EXTRA_TEXT, "茶博士 app,最新最全的茶信息都
在这"); // 设置分享的文本内容
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 添加标志,防止
出现 ActivityNotFoundException 错误
shareIntent.addCategory(Intent.CATEGORY_DEFAULT); // 添加默认的分享类型
startActivity(Intent.createChooser(shareIntent, "要分享到")); // 启动系
统的分享对话框
/*
//Android7.0 及以上的版本不允许在应用之间共享 file://类型的 Uri,因为存
在安全隐患。
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.mipmap.logo);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
File file = new File(Environment.getExternalStorageDirectory() +
File.separator + "share_image.jpg");
FileOutputStream fo;
try {
file.createNewFile();
fo = new FileOutputStream(file);
fo.write(bytes.toByteArray());
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
Uri imageUri = FileProvider.getUriForFile(this, getPackageName() +
".fileprovider", file);
shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
shareIntent.putExtra(Intent.EXTRA_TEXT, "茶博士 app");
startActivity(Intent.createChooser(shareIntent, "分享"));
}catch (Exception e) {
e.printStackTrace();
}
*/
}

//检测设备是否联网
private boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (cm != null) {
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null && info.isConnected()) {
return true;
}
}
return false;
}
}

//主页面
public class HeadlinesFragment extends Fragment {
String headline_title,headline_time,headline_source, headline_text,
headline_author, headline_imageurl,record;
private MyPagerAdapter myPagerAdapter;
private List<Integer> imageResIds = new ArrayList<>(); // 存储图片资源 ID
的列表
private List<MyItem> mItemList = new ArrayList<>();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable
ViewGroup container, @Nullable Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.page_headlines,container,false);
ListView listView = view.findViewById(R.id.Pst_my_headlines);
// 获取 TeaDBHelper 对象
TeaDBHelper dbHelper = new TeaDBHelper(getActivity());
// 获取 SQLiteDatabase 对象
SQLiteDatabase db = dbHelper.getReadableDatabase();
// 初始化 ViewPager
final ViewPager viewPager = view.findViewById(R.id.view_pager);
imageResIds.add(R.drawable.image1);
imageResIds.add(R.drawable.image2);
imageResIds.add(R.drawable.image3);
myPagerAdapter = new MyPagerAdapter(imageResIds);
viewPager.setAdapter(myPagerAdapter);
final Handler handler = new Handler();
final Runnable update = new Runnable() {
public void run() {
int currentPage = viewPager.getCurrentItem(); // 获取当前页面
int nextPage = (currentPage + 1) % imageResIds.size(); // 计算
下一个页面的位置
viewPager.setCurrentItem(nextPage, true); // 切换到下一个页面
}
};
Timer myTimer = new Timer();
myTimer.schedule(new TimerTask() {
@Override
public void run() {
handler.post(update);
}
}, 2000, 2000);
String query = "SELECT * FROM headline";
Cursor cursor = db.rawQuery(query, null);
ArrayList<String> dataList = new ArrayList<>();
final ArrayList<String> titleList = new ArrayList<>();
final ArrayList<String> urlList = new ArrayList<>();
while(cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndex("headline_id"));
headline_title =
cursor.getString(cursor.getColumnIndex("headline_title"));
headline_time =
cursor.getString(cursor.getColumnIndex("headline_time"));
headline_source =
cursor.getString(cursor.getColumnIndex("headline_source"));
headline_text =
cursor.getString(cursor.getColumnIndex("headline_text"));
headline_imageurl =
cursor.getString(cursor.getColumnIndex("headline_imageurl"));
headline_author =
cursor.getString(cursor.getColumnIndex("headline_author"));
record = id + " " + headline_author + " " + headline_time + " "
+ headline_source;
dataList.add(record);
urlList.add(headline_imageurl);
titleList.add(headline_title);
}
final ImageView imageView = view.findViewById(R.id.image_view);
ImageRequest imageRequest = new ImageRequest(headline_imageurl, new
Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
// 将服务器的图片设置到 ImageView 中
imageView.setImageBitmap(bitmap);
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, null, new
Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 请求出错时,什么也不做
}
});

/*int[] array={R.drawable.head1,R.drawable.head2,R.drawable.head3,
R.drawable.head4,R.drawable.head5,R.drawable.head6,

R.drawable.head7,R.drawable.head8,R.drawable.head9,R.drawable.head10};*/
for (int i = 0; i < 10; i++) {
mItemList.add(new MyItem(titleList.get(i),
urlList.get(i),dataList.get(i)));
}
MyListAdapter adapter = new MyListAdapter();
listView.setAdapter(adapter);
// 点击记录跳转,要传递数据过去,具体展示
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {

// 解析记录中的数据
String headline_title = titleList.get(position);

// 将茶名通过 intent 传递给要跳转的页面


Intent intent = new Intent(getActivity(), newinfo.class);
intent.putExtra("headline_title", headline_title);
startActivity(intent);
}
});
// 关闭结果集和数据库连接
cursor.close();
db.close();
return view;
}
//listview 适配器
private class MyListAdapter extends BaseAdapter {

@Override
public int getCount() {
return mItemList.size();
}

@Override
public Object getItem(int position) {
return mItemList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
convertView =
LayoutInflater.from(getContext()).inflate(R.layout.list_item_layout, parent,
false);
viewHolder = new ViewHolder();
viewHolder.titleTextView =
convertView.findViewById(R.id.text_view);
viewHolder.dateTextView =
convertView.findViewById(R.id.text_view1);
viewHolder.imageView =
convertView.findViewById(R.id.image_view);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}

MyItem item = mItemList.get(position);


viewHolder.titleTextView.setText(item.getTitle());
viewHolder.dateTextView.setText(item.getDate());
ImageRequest imageRequest = new ImageRequest(item.getImageUrl(),
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
// 将服务器的图片设置到 ImageView 中
viewHolder.imageView.setImageBitmap(bitmap);
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, null, new
Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 请求出错时,什么也不做
}
});
// 使用 Volley 请求服务器的图片
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
requestQueue.add(imageRequest);

return convertView;
}

private class ViewHolder {


TextView titleTextView;
TextView dateTextView;
ImageView imageView;
}
}

//.....
public class MyItem {
private String title;
private String imageUrl; // 保存图片链接
private String date;

public MyItem(String title, String imageUrl, String date) {


this.title = title;
this.imageUrl = imageUrl;
this.date = date;
}

public String getTitle() {


return title;
}

public String getImageUrl() {


return imageUrl;
}

public String getDate() {


return date;
}
}

//适配器
public class MyPagerAdapter extends PagerAdapter {

private List<Integer> mImageResIds;

public MyPagerAdapter(List<Integer> imageResIds) {


mImageResIds = imageResIds;
}

@Override
public int getCount() {
return mImageResIds.size();
}

@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int
position) {
ImageView imageView = new ImageView(container.getContext());
// 设置图片填充方式为 CENTER_CROP
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageResource(mImageResIds.get(position));
//container.addView(imageView);
// 设置 ImageView 的宽高为 MATCH_PARENT,以充满 ViewPager
container.addView(imageView, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
return imageView;
}

@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object
object) {
return view == object;
}

@Override
public void destroyItem(@NonNull ViewGroup container, int position,
@NonNull Object object) {
container.removeView((View) object);
}
}
}

图 6 主页面

//茶信息的具体展示界面
public class Information extends AppCompatActivity {
private Button btnLike;
private Button btnFavorite;
private SharedPreferences sp;
private Set<String> favoriteNames;
ImageView imageView;
TextView textView1,textView2,textView3,textView4;
String name,image,description,method,storage;
private Drawable drawable,drawable2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.page_information);

//获取上一个页面的茶名
Intent intent = getIntent();
final String name = intent.getStringExtra("name");

// 获取 TeaDBHelper 对象
TeaDBHelper dbHelper = new TeaDBHelper(Information.this);
// 获取 SQLiteDatabase 对象
SQLiteDatabase db = dbHelper.getReadableDatabase();
//根据茶名,找到该茶对应的 image、description
String query = "SELECT * FROM tea_info where name=?";
Cursor cursor = db.rawQuery(query, new String[]{name});
if(cursor.moveToNext()) {
image = cursor.getString(cursor.getColumnIndex("image"));
description =
cursor.getString(cursor.getColumnIndex("description"));
method = cursor.getString(cursor.getColumnIndex("method"));
storage = cursor.getString(cursor.getColumnIndex("storage"));
}

//获取服务器存储的图片,volley 框架
imageView = findViewById(R.id.tea_image);
String imageUrl = image;
ImageRequest imageRequest = new ImageRequest(imageUrl, new
Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
//Toast.makeText(getApplicationContext(), "图片加载成功",
Toast.LENGTH_SHORT).show();
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, null, new
Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 处理网络请求错误
imageView.setImageResource(R.mipmap.logo);
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(imageRequest);

//将茶的存储信息、做法写在文本框中中
textView1 = findViewById(R.id.tea_name);
textView1.setText(name);
textView2 = findViewById(R.id.tea_description);
textView3 = findViewById(R.id.tea_method);
textView3.setText(method);
textView4 = findViewById(R.id.tea_storage);
textView4.setText(storage);

//要获取的 txt 文件的 URL 地址


String url = description;
//创建一个 StringRequest 对象,使用 GET 方式获取茶的描述信息 txt 文件内容
StringRequest stringRequest = new StringRequest(Request.Method.GET,
url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//处理获取到的 txt 文件内容
textView2.setText(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//在此处处理请求错误
textView2.setText("网络繁忙,请等待");
}
}) {
//指定请求字符编码格式为 UTF-8
@Override
protected String getParamsEncoding() {
return "UTF-8";
}
// 指定响应字符编码格式为 UTF-8
@Override
protected Response<String> parseNetworkResponse(NetworkResponse
response) {
String parsed;
try {
parsed = new String(response.data, "UTF-8");
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed,
HttpHeaderParser.parseCacheHeaders(response));
}
};

//将 StringRequest 对象添加到 RequestQueue 中


requestQueue.add(stringRequest);

//点赞收藏按键
btnLike = findViewById(R.id.btn_like);
btnLike.setText("点赞");
btnFavorite = findViewById(R.id.btn_favorite);
sp = getSharedPreferences("favorite", MODE_PRIVATE);

// 设置收藏按钮的状态
// 获取已收藏的 name 数组,若无则创建新数组
final Set<String> favoriteNames = sp.getStringSet("favoriteNames", new
HashSet<String>());
//获取收藏 star 图标
drawable = getResources().getDrawable(R.drawable.ic_star_black_24dp);
drawable.setBounds(0, 0, drawable.getMinimumWidth(),
drawable.getMinimumHeight());
drawable2 =
getResources().getDrawable(R.drawable.ic_star_border_black_24dp);
drawable2.setBounds(0, 0, drawable.getMinimumWidth(),
drawable.getMinimumHeight());
// 判断该 name 是否已经收藏
if (favoriteNames.contains(name)) {
btnFavorite.setText("取消收藏");
btnFavorite.setCompoundDrawables(drawable, null, null, null);
} else {
btnFavorite.setText("收藏");
btnFavorite.setCompoundDrawables(drawable2, null, null, null);
}

// 设置点击点赞事件
btnLike.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "点赞成功",
Toast.LENGTH_SHORT).show();
}
});

// 设置点击收藏事件
btnFavorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 收藏操作
// 判断该 name 是否已经收藏
if (favoriteNames.contains(name)) {
favoriteNames.remove(name);
sp.edit().putStringSet("favoriteNames",
favoriteNames).apply();
btnFavorite.setText("收藏");
btnFavorite.setCompoundDrawables(drawable2, null, null,
null);
Toast.makeText(getApplicationContext(), "取消收藏成功",
Toast.LENGTH_SHORT).show();
} else {
favoriteNames.add(name);
sp.edit().putStringSet("favoriteNames",
favoriteNames).apply();
btnFavorite.setText("取消收藏");
btnFavorite.setCompoundDrawables(drawable, null, null,
null);
Toast.makeText(getApplicationContext(), "收藏成功",
Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
protected void onResume() {
super.onResume();
//获取上一个页面的茶名
Intent intent = getIntent();
name = intent.getStringExtra("name");
// 存储该页面的 name 到 SharedPreferences 中,包括浏览时间
sp = getSharedPreferences("BrowsingHistory", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
String[] pages = sp.getString("VisitedPages", "").split(",");
List<String> pageList = new ArrayList<>(Arrays.asList(pages));
String currentTime = new SimpleDateFormat("yyyy/MM/dd HH:mm",
Locale.getDefault()).format(new Date());
String pageWithTime = name + " " + currentTime;
pageList.add(pageWithTime);
String newPages = TextUtils.join(",", pageList);
editor.putString("VisitedPages", newPages);
editor.apply();

图 7 茶信息的具体展示
//登录功能
/**
* 此类 implements View.OnClickListener 之后,
* 就可以把 onClick 事件写到 onCreate()方法之外
* 这样,onCreate()方法中的代码就不会显得很冗余
*/
public class LoginActivity extends AppCompatActivity implements
View.OnClickListener {
private DBOpenHelper mDBOpenHelper;
private EditText et_User, et_Psw;
private CheckBox cb_rmbPsw;
private String userName;
private SharedPreferences.Editor editor;

/**
* 创建 Activity 时先来重写 onCreate() 方法
* 保存实例状态
* super.onCreate(savedInstanceState);
* 设置视图内容的配置文件
* setContentView(R.layout.activity_login);
* 上面这行代码真正实现了把视图层 View 也就是 layout 的内容放到 Activity 中
进行显示
* 初始化视图中的控件对象 initView()
* 实例化 DBOpenHelper,待会进行登录验证的时候要用来进行数据查询
* mDBOpenHelper = new DBOpenHelper(this);
*/
@SuppressLint("CommitPrefEdits")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏
状态栏
Objects.requireNonNull(getSupportActionBar()).hide();//隐藏标题栏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);//禁
止横屏
setContentView(R.layout.activity_login);

initView();//初始化界面
mDBOpenHelper = new DBOpenHelper(this);

SharedPreferences sp = getSharedPreferences("user_mes", MODE_PRIVATE);


editor = sp.edit();
if(sp.getBoolean("flag",false)){
String user_read = sp.getString("user","");
String psw_read = sp.getString("psw","");
et_User.setText(user_read);
et_Psw.setText(psw_read);
}
}

private void initView() {


//初始化控件
et_User = findViewById(R.id.et_User);
et_Psw = findViewById(R.id.et_Psw);
cb_rmbPsw = findViewById(R.id.cb_rmbPsw);
Button btn_Login = findViewById(R.id.btn_Login);
TextView tv_register = findViewById(R.id.tv_Register);
//设置点击事件监听器
btn_Login.setOnClickListener(this);
tv_register.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_Register: //注册
Intent intent = new Intent(LoginActivity.this,
RegisteredActivity.class);//跳转到注册界面
startActivity(intent);
finish();
break;
/**
* 登录验证:
*
* 从 EditText 的对象上获取文本编辑框输入的数据,并把左右两边的空格
去掉
* String name =
mEtLoginactivityUsername.getText().toString().trim();
* String password =
mEtLoginactivityPassword.getText().toString().trim();
* 进行匹配验证,先判断一下用户名密码是否为空,
* if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password))
* 再进而 for 循环判断是否与数据库中的数据相匹配
* if (name.equals(user.getName()) &&
password.equals(user.getPassword()))
* 一旦匹配,立即将 match = true;break;
* 否则 一直匹配到结束 match = false;
*
* 登录成功之后,进行页面跳转:
*
* Intent intent = new Intent(this, MainActivity.class);
* startActivity(intent);
* finish();//销毁此 Activity
*/
case R.id.btn_Login:
String name = et_User.getText().toString().trim();
String password = et_Psw.getText().toString().trim();
if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(password)) {
ArrayList<User> data = mDBOpenHelper.getAllData();
boolean match = false;
boolean match2 = false;
for (int i = 0; i < data.size(); i++) {
User user = data.get(i);
if ((name.equals(user.getName()) &&
password.equals(user.getPassword()))||

(name.equals(user.getEmail())&&password.equals(user.getPassword()))||

(name.equals(user.getPhonenum())&&password.equals(user.getPassword()))) {
userName = user.getName();
match = true;
if(cb_rmbPsw.isChecked()){
editor.putBoolean("flag",true);
editor.putString("user",user.getName());
editor.putString("psw",user.getPassword());
editor.apply();
match2 = true;
}else {
editor.putString("user",user.getName());
editor.putString("psw","");
// editor.clear();
editor.apply();
match2 = false;
}
break;
} else {
match = false;
}
}
if (match) {
if(match2){
Toast.makeText(this, "成功记住密码",
Toast.LENGTH_SHORT).show();
cb_rmbPsw.setChecked(true);
}
Toast.makeText(this, "登录成功",
Toast.LENGTH_SHORT).show();
Runnable target;
//用线程启动
Thread thread = new Thread(){
@Override
public void run(){
try {
sleep(500);//0.5 秒跳转
String user_name = userName;
Intent intent1 = new
Intent(LoginActivity.this, MainActivity.class);//设置自己跳转到成功的界面

//intent1.putExtra("user_name",user_name);
startActivity(intent1);
finish();
}catch (Exception e){
e.printStackTrace();
}
}
};
thread.start();//打开线程
} else {
Toast.makeText(this, "用户名或密码不正确,请重新输入",
Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "请输入你的用户名或密码",
Toast.LENGTH_SHORT).show();
}
break;
}
}
}
图 8 登录功能 图 9 注册功能

//注册功能
public class RegisteredActivity extends AppCompatActivity implements
View.OnClickListener {
private EditText et_rgsName, et_rgsEmail, et_rgsPhoneNum, et_rgsPsw1,
et_rgsPsw2;
private DBOpenHelper mDBOpenHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);//禁
止横屏
setContentView(R.layout.activity_registered);
setTitle("用户注册");//顶部标题改成用户注册

initView();//初始化界面
mDBOpenHelper = new DBOpenHelper(this);
}

private void initView() {


et_rgsName = findViewById(R.id.et_rgsName);
et_rgsEmail = findViewById(R.id.et_rgsEmail);
et_rgsPhoneNum = findViewById(R.id.et_rgsPhoneNum);
et_rgsPsw1 = findViewById(R.id.et_rgsPsw1);
et_rgsPsw2 = findViewById(R.id.et_rgsPsw2);

Button btn_register = findViewById(R.id.btn_rgs);


ImageView iv_back = findViewById(R.id.iv_back);
/**
* 注册页面能点击的就三个地方
* top 处返回箭头、刷新验证码图片、注册按钮
*/
iv_back.setOnClickListener(this);
btn_register.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_back://返回登录界面
Intent intent = new Intent(RegisteredActivity.this,
LoginActivity.class);
startActivity(intent);
finish();
break;
case R.id.btn_rgs://注册按钮
//获取用户输入的用户名、密码、验证码
String username = et_rgsName.getText().toString().trim();
String password1 = et_rgsPsw1.getText().toString().trim();
String password2 = et_rgsPsw2.getText().toString().trim();
String email = et_rgsEmail.getText().toString().trim();
String phonenum = et_rgsPhoneNum.getText().toString().trim();
//注册验证
if (!TextUtils.isEmpty(username) && !
TextUtils.isEmpty(password1) && !TextUtils.isEmpty(password2)) {
//判断两次密码是否一致
if (password1.equals(password2)) {
//将用户名和密码加入到数据库中
mDBOpenHelper.add(username, password2, email,
phonenum);
Intent intent1 = new Intent(RegisteredActivity.this,
LoginActivity.class);
startActivity(intent1);
finish();
Toast.makeText(this, "验证通过,注册成功",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "两次密码不一致,注册失败",
Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "注册信息不完善,注册失败",
Toast.LENGTH_SHORT).show();
}
break;
}
}
}

//经营信息的具体展示界面
public class BusinessInformation extends AppCompatActivity {

private Button btnLike;


private Button btnFavorite;
private SharedPreferences sp;
ImageView imageView;
TextView textView1,textView2;
String operate,name,title,image;

protected void onCreate(Bundle savedInstanceState) {


super.onCreate(savedInstanceState);
//获取收藏 star 图标
final Drawable drawable =
getResources().getDrawable(R.drawable.ic_star_black_24dp);
drawable.setBounds(0, 0, drawable.getMinimumWidth(),
drawable.getMinimumHeight());
final Drawable drawable2 =
getResources().getDrawable(R.drawable.ic_star_border_black_24dp);
drawable2.setBounds(0, 0, drawable.getMinimumWidth(),
drawable.getMinimumHeight());
setContentView(R.layout.page_business);
//获取上一个页面的经营简要信息
Intent intent = getIntent();
final String name = intent.getStringExtra("title");

// 获取 TeaDBHelper 对象
TeaDBHelper dbHelper = new TeaDBHelper(BusinessInformation.this);
// 获取 SQLiteDatabase 对象
SQLiteDatabase db = dbHelper.getReadableDatabase();
//根据标题,找到经营的具体信息
String query = "SELECT * FROM tea_business where business_title=?";
Cursor cursor = db.rawQuery(query, new String[]{name});
if(cursor.moveToNext()) {
//新增一行详细的经营信息
operate =
cursor.getString(cursor.getColumnIndex("business_information"));
image = cursor.getString(cursor.getColumnIndex("business_image"));
}
cursor.close();
db.close();

//将经营信息写在文本框中中
textView1 = findViewById(R.id.business_name);
textView1.setText(name);
textView2 = findViewById(R.id.business_description);

//要获取的 txt 文件的 URL 地址


String url = operate;
//创建一个 StringRequest 对象,使用 GET 方式获取茶的描述信息 txt 文件内容
StringRequest stringRequest = new StringRequest(Request.Method.GET,
url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
//处理获取到的 txt 文件内容
textView2.setText(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//在此处处理请求错误
textView2.setText("网络繁忙,请等待");
}
}) {
//指定请求字符编码格式为 UTF-8
@Override
protected String getParamsEncoding() {
return "UTF-8";
}

// 指定响应字符编码格式为 UTF-8
@Override
protected Response<String> parseNetworkResponse(NetworkResponse
response) {
String parsed;
try {
parsed = new String(response.data, "UTF-8");
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed,
HttpHeaderParser.parseCacheHeaders(response));
}
};
//将 StringRequest 对象添加到 RequestQueue 中
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(stringRequest);

//获取服务器存储的图片,volley 框架
imageView = findViewById(R.id.business_image);
String imageUrl = image;
ImageRequest imageRequest = new ImageRequest(imageUrl, new
Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
//Toast.makeText(getApplicationContext(), "图片加载成功",
Toast.LENGTH_SHORT).show();
}
}, 0, 0, ImageView.ScaleType.CENTER_CROP, null, new
Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 处理网络请求错误
imageView.setImageResource(R.mipmap.logo);
}
});
requestQueue.add(imageRequest);

//点赞收藏按键
btnLike = findViewById(R.id.btn_like2);
btnLike.setText("点赞");
btnFavorite = findViewById(R.id.btn_favorite2);
sp = getSharedPreferences("favorite", MODE_PRIVATE);

// 设置收藏按钮的状态
// 获取已收藏的 name 数组,若无则创建新数组
final Set<String> favoriteNames = sp.getStringSet("favoriteNames", new
HashSet<String>());
// 判断该 name 是否已经收藏
if (favoriteNames.contains(name)) {
btnFavorite.setText("取消收藏");
btnFavorite.setCompoundDrawables(drawable, null, null, null);
} else {
btnFavorite.setText("收藏");
btnFavorite.setCompoundDrawables(drawable2, null, null, null);
}

// 设置点击点赞事件
btnLike.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "点赞成功",
Toast.LENGTH_SHORT).show();
}
});

// 设置点击收藏事件
btnFavorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 收藏操作
// 判断该 name 是否已经收藏
if (favoriteNames.contains(name)) {
favoriteNames.remove(name);
sp.edit().putStringSet("favoriteNames",
favoriteNames).apply();
btnFavorite.setText("收藏");
btnFavorite.setCompoundDrawables(drawable2, null, null,
null);
Toast.makeText(getApplicationContext(), "取消收藏成功",
Toast.LENGTH_SHORT).show();
} else {
favoriteNames.add(name);
sp.edit().putStringSet("favoriteNames",
favoriteNames).apply();
btnFavorite.setText("取消收藏");
btnFavorite.setCompoundDrawables(drawable, null, null,
null);
Toast.makeText(getApplicationContext(), "收藏成功",
Toast.LENGTH_SHORT).show();
}
}
});
}

@Override
protected void onResume() {
super.onResume();
//获取上一个页面传过来的 title
Intent intent = getIntent();
name = intent.getStringExtra("title");
// 存储该页面的 name 到 SharedPreferences 中,包括浏览时间
SharedPreferences sharedPreferences =
getSharedPreferences("BrowsingHistory", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
String[] pages = sharedPreferences.getString("VisitedPages",
"").split(",");
List<String> pageList = new ArrayList<>(Arrays.asList(pages));
String currentTime = new SimpleDateFormat("yyyy/MM/dd HH:mm",
Locale.getDefault()).format(new Date());
String pageWithTime = name + " " + currentTime;
pageList.add(pageWithTime);
String newPages = TextUtils.join(",", pageList);
editor.putString("VisitedPages", newPages);
editor.apply();
}
}
图 10 经营信息的具体展示

5. 安装及使用
以下是 Android Studio 的安装教程:
1. 打开浏览器,访问 Android Studio 官方网站
(https://developer.android.google.cn/studio)。
2. 在网站上,找到并点击“Download Android Studio”按钮。
3. 在下载页面,选择适合您操作系统的版本(Windows、Mac、Linux)并点击下载链接。
4. 下载完成后,双击安装程序文件,开始安装 Android Studio。
5. 在安装向导中,根据提示进行安装设置。默认情况下,建议保留所有默认设置。
6. 安装完成后,启动 Android Studio。在首次启动时,Android Studio 可能需要下载和
安装一些额外的组件,这可能需要一些时间。
7. 启动 Android Studio 后,您将看到“Welcome to Android Studio”界面。在这个界面
上,您可以选择创建新项目、打开现有项目或导入项目。
7. 将此文件解压后选择新窗口打开项目。

6. 总结
在茶博士应用的制作和开发过程中,我们经历了一系列的步骤和挑战。以下是对项目
的总结以及在开发过程中的一些感悟和后续升级的思考。
1. 项目协调和任务分解:在项目开始之前,我们进行了详细的项目规划和需求分析。
通过明确项目目标和任务,我们能够更好地协调团队成员的工作,并将任务分解为可管理
的小部分。这有助于提高工作效率和确保项目按时交付。
2. 面对困难:在项目开发过程中,我们遇到了一些技术和设计上的困难。面对这些挑
战,我们采取了积极的态度,并与团队成员紧密合作,共同寻找解决方案。我们发现,及
时的沟通和合作对于解决问题至关重要,并能够帮助我们克服困难。
3. 用户反馈和改进:在应用发布后,我们积极收集用户的反馈和意见。这些反馈对于
我们了解用户需求和改进应用非常重要。我们认真对待每一个反馈,并将其作为改进的方
向。通过不断优化和更新,我们可以提供更好的用户体验,并满足用户的需求。
4. 升级演进:茶博士应用是一个不断演进的项目。我们计划在后续的版本中添加更多
的功能和特性,以提升用户体验和增加应用的价值。这可能包括增加茶叶品鉴和评级功能、
提供更多的茶叶推荐算法、扩展社区交流功能等。我们将继续关注行业的最新发展,并根
据用户需求进行相应的升级和改进。
总的来说,茶博士应用的制作和开发过程是一个充满挑战和成长的过程。通过团队的
协作和努力,我们成功地开发了一个功能丰富、用户友好的茶叶知识和交流平台。我们将
继续努力改进和升级应用,以满足用户的需求,并为茶叶爱好者提供更好的体验。

You might also like