Android天气预报应用开发实战

打印 上一主题 下一主题

主题 773|帖子 773|积分 2319

本文另有配套的精品资源,点击获取  

  简介:在Android平台上构建天气预报应用需要综合应用多种技能。开发者需认识Android体系架构、把握Android Studio使用,理解Activity与Intent工作原理。应用需要处理网络数据获取,包罗HTTP哀求和JSON解析,以及使用第三方天气API。界面计划要遵照Material Design并考虑用户体验,使用XML布局与RecyclerView展示数据。应用还需考虑数据存储,权限管理和提供定位服务。终极,应用应能通过关照和Widget与用户交互,确保功能完善和用户体验精良。

1. Android体系架构和开发基础

1.1 Android体系架构概述

  Android体系架构分为四个主要层次:Linux内核、Android运行时、库和Android框架、应用步伐。Linux内核负责硬件抽象,运行时包罗核心库和Dalvik虚拟机(对于Android 5.0及以上版本,是Android Runtime, ART)。库提供体系运行所需的服务,如SQLite和Webkit。Android框架允许开发者利用体系功能和硬件,而应用步伐层则提供了用户界面和交互逻辑。
1.2 Android开发环境搭建

  开发Android应用的首选工具是Android Studio,它支持代码编辑、调试、性能监控等全面的开发任务。开发者可以通过Android SDK Manager来下载和管理Android平台的开发工具和组件。
1.3 应用开发基础

  Android应用开发始于对Java或Kotlin语言的认识,随后是对其核心组件(如Activity、Service、BroadcastReceiver和ContentProvider)的理解。创建一个根本的Android应用包罗编写布局XML文件来定义用户界面,以及在Activity类中加载和管理这些界面。
2. 网络数据获取与HTTP哀求处理

  随着移动互联网的发展,客户端与服务器端的数据互换成为常态。Android 应用步伐常常需要从网络获取数据,而 HTTP 协议是如今应用最广泛的网络通信协议。本章我们将深入相识网络基础知识,学习如何使用 HTTP 库进行数据哀求,并对返回的数据进行处理。
2.1 网络基础知识

  网络通信是数据交互的基石,任何网络数据的互换都需要遵照肯定的通信模型。HTTP协议作为一种应用层协议,其计划目标是提供一种发布和吸收 HTML 页面的方法。
2.1.1 网络通信模型

  TCP/IP 是互联网的基础协议,它定义了数据在网络中传输的规则。这个模型大抵可以分为四层:应用层、传输层、网络互联层和网络接口层。
  在应用层,HTTP协议负责定义数据的格式和互换规则。传输层主要处理数据传输的细节,例如 TCP 和 UDP 就是这个层次的协议。网络互联层是 IP 协议工作的层面,负责在复杂的网络中将数据包精确地送达目的地。网络接口层则是将数据包封装成可以在物理网络上传输的帧。
2.1.2 HTTP协议的理解与应用

  HTTP 是基于哀求/响应模型的无状态协议,客户端(如Android设备)发送哀求(Request),服务器返反响应(Response)。HTTP 协议是无连接的,这意味着每一次连接都是独立的,服务器不会记取先前的哀求信息。
  对于 HTTP 协议,开发者需要认识常见的哀求方法,好比 GET、POST、PUT、DELETE 等,它们对应于差别的操作类型。例如,GET 通常用于从服务器获取资源,而 POST 用于提交数据至服务器。
  在 Android 开发中,我们主要关注的是如何发起 HTTP 哀求以及如何处理响应的数据。这通常通过使用 HTTP 库来简化,下一节将介绍如何使用 OkHttp 库进行网络哀求。
2.2 使用HTTP库进行数据哀求

2.2.1 OkHttp库的安装与设置

  OkHttp 是一个高效的 HTTP 客户端库,支持 HTTP/2 和连接池等特性。要在 Android 项目中使用 OkHttp,首先需要将其添加到项目的依赖中:
  1. dependencies {
  2.     implementation 'com.squareup.okhttp3:ok***'
  3. }
复制代码
在初始化 OkHttp 客户端之前,我们可以对其进行设置,例如添加拦截器处理哀求和响应,设置连接超时等:
  1. OkHttpClient client = new OkHttpClient.Builder()
  2.     .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
  3.     .connectTimeout(10, TimeUnit.SECONDS)
  4.     .readTimeout(10, TimeUnit.SECONDS)
  5.     .build();
复制代码
2.2.2 发送GET与POST哀求

  使用 OkHttp 发送 GET 哀求非常简单:
  1. Request request = new Request.Builder()
  2.     .url("***")
  3.     .build();
  4. client.newCall(request).enqueue(new Callback() {
  5.     @Override
  6.     public void onFailure(Call call, IOException e) {
  7.         // 请求失败处理
  8.     }
  9.     @Override
  10.     public void onResponse(Call call, Response response) throws IOException {
  11.         if (response.isSuccessful()) {
  12.             // 请求成功处理
  13.             String responseData = response.body().string();
  14.             // 处理响应字符串数据
  15.         }
  16.     }
  17. });
复制代码
对于 POST 哀求,需要添加哀求体(RequestBody)并指定媒体类型(MediaType):
  1. MediaType JSON = MediaType.get("application/json; charset=utf-8");
  2. String json = "{"key":"value"}"; // JSON 格式数据
  3. RequestBody body = RequestBody.create(json, JSON);
  4. Request request = new Request.Builder()
  5.     .url("***")
  6.     .post(body)
  7.     .build();
  8. client.newCall(request).enqueue(new Callback() {
  9.     // 同上
  10. });
复制代码
2.2.3 处理网络响应数据

  在回调函数  onResponse  中,我们通常会查抄响应状态码是否为 200 系列,表示哀求乐成。假如乐成,我们就可以从 Response 的 Body 中获取响应数据。这通常是一个字符串形式的数据,假如需要,我们可以将其转换为 JSON 对象进一步解析。
  1. if (response.isSuccessful()) {
  2.     String responseData = response.body().string();
  3.     // 可以使用第三方库如Gson解析JSON字符串
  4.     Type type = new TypeToken<Map<String, Object>>(){}.getType();
  5.     Map<String, Object> dataMap = new Gson().fromJson(responseData, type);
  6.     // 现在可以使用 Map 数据
  7. }
复制代码
本章节介绍了网络通信的基础知识以及如何使用 OkHttp 库来发送 HTTP 哀求并处理响应数据。下一章将介绍如何解析 JSON 数据,这在处理网络响应时非常常见。
3. JSON数据解析方法

  在移动开发中,处理网络数据是至关重要的一个环节。JSON(JavaScript Object Notation)作为轻量级的数据互换格式,在移动应用中广泛使用,特别是在与服务器进行数据交互时。本章节将深入探讨JSON数据结构及其在Android中的解析方法。
3.1 JSON数据结构与解析原理

3.1.1 JSON格式简介

  JSON是一种轻量级的数据互换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript语言,但却是独立于语言的数据格式。JSON可以表示以下数据类型:


  • 数字(Number):如 123.45,1.2e3 等。
  • 字符串(String):用双引号括起来的字符序列,如 "Hello World"。
  • 布尔值(Boolean):true 或 false。
  • 数组(Array):用方括号括起来的一组值,值之间用逗号分隔,如 [1, "abc", true]。
  • 对象(Object):用大括号括起来的一组“键值对”,值之间用逗号分隔,如 {"name": "Alice", "age": 30}。
  JSON 数据的结构以键值对的形式出现,可以嵌套使用。例如:
  1. {
  2.   "name": "Alice",
  3.   "age": 30,
  4.   "isStudent": false,
  5.   "courses": ["Math", "Physics"],
  6.   "address": {
  7.     "street": "123 Main St",
  8.     "city": "Wonderland"
  9.   }
  10. }
复制代码
3.1.2 解析JSON数据的方法

  解析JSON数据主要有两种方法:一种是直接使用Android原生API;另一种是借助第三方库,如Gson或Moshi等。
使用Android原生API

  Android提供了  org.json  包来处理JSON数据,此中包含  JSONObject  和  JSONArray  类,用于解析JSON字符串。
  1. try {
  2.     JSONObject json = new JSONObject(responseString);
  3.     String name = json.getString("name");
  4.     int age = json.getInt("age");
  5.     JSONArray courses = json.getJSONArray("courses");
  6.     JSONObject address = json.getJSONObject("address");
  7.     String street = address.getString("street");
  8.     String city = address.getString("city");
  9.     // 处理解析后的数据
  10. } catch (JSONException e) {
  11.     e.printStackTrace();
  12. }
复制代码
利用Gson库进行对象映射

  Gson是Google提供的一个用于将Java对象转换为JSON格式数据,或反之的库。使用Gson时,你可以将JSON字符串映射到Java对象,反之亦然。
  首先,定义与JSON数据结构对应的Java类:
  1. public class Person {
  2.     private String name;
  3.     private int age;
  4.     private boolean isStudent;
  5.     private List<String> courses;
  6.     private Address address;
  7.     // getters and setters
  8. }
  9. public class Address {
  10.     private String street;
  11.     private String city;
  12.     // getters and setters
  13. }
复制代码
然后使用Gson进行对象映射:
  1. Gson gson = new Gson();
  2. Person person = gson.fromJson(responseString, Person.class);
  3. // person 对象现在包含了从JSON字符串解析出来的数据
复制代码
3.2 在Android中解析JSON数据

3.2.1 使用JSONObject和JSONArray

  当处理简单的JSON数据时,使用  JSONObject  和  JSONArray  就足够了。这对于快速解析和小型项目来说非常方便,但当项目规模增大,JSON结构变得更加复杂时,手动解析就会变得繁琐且容易堕落。
3.2.2 利用Gson库进行对象映射

  对于复杂的JSON数据,Gson库提供了一个更加便捷的方式来自动映射JSON数据到Java对象。它不仅简化了代码,还提高了数据处理的精确性和效率。
  1. Gson gson = new GsonBuilder().setPrettyPrinting().create();
  2. Type type = new TypeToken<List<Person>>() {}.getType();
  3. List<Person> people = gson.fromJson(responseString, type);
  4. // people 列表现在包含了从JSON数组解析出来的数据
复制代码
总结起来,JSON数据解析是移动开发中的核心技能之一。把握它不仅可以有用地处理网络数据,还能提高应用的用户体验和数据处理能力。在Android开发中,无论是使用原生API还是第三方库,相识JSON解析的原理和方法都十分重要。随着数据结构的复杂性增长,使用Gson等第三方库可以显著提高开发效率和代码质量。
4. 第三方天气API的使用

4.1 天气API选择与接入

4.1.1 比力差别天气API服务

  为了在我们的天气应用步伐中提供实时的天气更新,我们需要接入第三方天气API服务。市场上存在多种天气API,例如OpenWeatherMap、WeatherAPI和AccuWeather等。每个服务都有其独特的功能和定价模型。在选择天气API时,应考虑以下几个关键因素:


  • 精确性 :天气数据的精确性是最重要的考虑因素。比力各个API提供的数据精度,查看它们是否满足您的应用步伐需求。
  • 覆盖范围 :一些服务大概在特定地区的天气数据上更完备或更精确。
  • 更新频率 :根据应用步伐需要,选择更新频率较高的API可以保证用户获得最新天气信息。
  • 价格 :许多天气API提供免费层级,但根据哀求次数或功能的增长大概需要付费。
  • 文档 :易读且详尽的API文档对于集成和维护至关重要。
  • 社区支持 :一个活跃的开发者社区可以提供额外的支持和使用案例。
4.1.2 注册API并获取密钥

  大多数第三方天气API都要求开发者注册并获取一个API密钥,以便可以或许调用其提供的服务。以下是注册API并获取密钥的步骤:

  • 访问目标天气API的官方网站。
  • 注册一个账户,通常需要提供电子邮件地点和暗码。
  • 注册后,通常需要在控制面板中创建一个新应用步伐以获取API密钥。
  • 填写必要的信息,例如应用步伐的名称和用途。
  • 创建后,将获得一个API密钥,该密钥在每次哀求API时都需要使用。
  一旦拥有API密钥,就可以开始编写代码以在Android应用步伐中集成API服务。记取要安全地存储密钥,不要将其直接包含在公共代码库中。
4.2 API数据的哀求与解析

4.2.1 构建API哀求URL

  大多数天气API都通过HTTP协议以RESTful的方式提供服务。为了从API获取天气数据,我们需要构建一个包含必要参数的HTTP哀求URL。下面是一个构建哀求URL的根本示例:
  1. String apiKey = "YOUR_API_KEY"; // 用你的API密钥替换
  2. String city = "Beijing"; // 假设我们查询北京的天气
  3. String url = "***" + city + "&appid=" + apiKey;
复制代码
4.2.2 解析天气API返回的数据

  API响应通常为JSON格式,我们需要解析这些数据以在应用步伐中使用。以下是如何使用Android内置的  JSONObject  类来解析响应的步骤:
  1. URL requestUrl = new URL(url);
  2. HttpURLConnection urlConnection = (HttpURLConnection) requestUrl.openConnection();
  3. InputStream inputStream = urlConnection.getInputStream();
  4. BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
  5. String line;
  6. StringBuilder response = new StringBuilder();
  7. while ((line = bufferedReader.readLine()) != null) {
  8.     response.append(line);
  9. }
  10. bufferedReader.close();
  11. JSONObject jsonResponse = new JSONObject(response.toString());
复制代码
一旦有了  jsonResponse  对象,我们就可以根据API返回的数据结构提取所需信息。例如,获取天气和温度:
  1. JSONObject main = jsonResponse.getJSONObject("main");
  2. double temperature = main.getDouble("temp");
复制代码
这里  temp  字段通常表示开尔文温度,根据需要,可以将其转换为摄氏度或华氏度。同样的方法可以用来提取天气描述、湿度、气压等信息。
  解析JSON时应确保有适当的错误处理机制,如try-catch块,以防JSON解析失败。在真实的应用中,还需要处理网络连接问题,例如使用  HttpURLConnection  时的  IOException  。
  通过以上步骤,我们可以将第三方天气API集成到Android应用中,并有用地获取和解析天气数据。下一章节将介绍如何使用这些数据来计划和实现天气应用的用户界面。
5. 用户界面计划与XML布局

5.1 Android用户界面布局基础

5.1.1 布局文件的编写规则

  在Android中,用户界面是通过XML文件来定义的,这些文件被称为布局文件。布局文件遵照肯定的编写规则来构建用户界面的结构。每个布局文件中至少要有一个根元素,它代表了布局的类型。常见的根元素包罗LinearLayout(线性布局)、RelativeLayout(相对布局)、FrameLayout(帧布局)等。
  布局文件的编写规则还涉及到对布局属性的定义,例如宽度、高度、边距等。此外,为了使布局文件更具有可读性和可维护性,应该遵照命名规范和缩进规范。
5.1.2 常用的布局类型与属性

LinearLayout(线性布局)

  LinearLayout是最简单的布局之一,它按照水平或垂直方向次序排列子视图。它有两个关键属性:  androidrientation  用于设置排列方向,  android:layout_gravity  用于设置子视图在其父视图中的对齐方式。
RelativeLayout(相对布局)

  RelativeLayout是通过指定子视图相对于彼此或其他父视图元素的位置来布局子视图的。它的特性允许开发者创建复杂的布局,而不需要嵌套多层布局。  android:layout_toRightOf  和  android:layout_below  是RelativeLayout中常用的位置相关属性。
FrameLayout(帧布局)

  FrameLayout主要用于放置单个子视图,它将子视图叠加在一起,子视图的位置是由其在FrameLayout中的次序决定的。它适适用于实现覆盖效果,如加载动画或弹出层。
ConstraintLayout(束缚布局)

  ConstraintLayout是Android较新的布局方式,它提供了一种灵活的方式来计划复杂的布局结构。通过给子视图设置束缚,子视图可以在父布局中居中、对齐到任意边、成比例分布等。ConstraintLayout大大淘汰了嵌套的层级,提高了布局效率。
5.2 使用XML计划天气应用界面

5.2.1 界面元素的计划原则

  计划一个天气应用的用户界面时,需要考虑简便性和用户体验。界面元素的计划原则包罗清晰的视觉层次、合理的元素布局和一致的样式。


  • 视觉层次 :确保界面中的元素按照重要性进行排序,重要的元素应该更加突出。
  • 元素布局 :合理使用空白(margin和padding),避免界面过于拥挤。
  • 样式一致性 :使用统一的字体、颜色和巨细来保持界面的一致性。
5.2.2 实现响应式布局

  响应式布局是指可以或许在差别尺寸的屏幕上提供精良表现效果的布局。在Android中,可以通过以下方式实现响应式布局:


  • 使用百分比宽度和高度,而非固定的dp值。
  • 使用权重(weight)分配差别控件的巨细比例。
  • 使用差别的布局资源文件夹(如layout-sw600dp)适配差别屏幕尺寸。
  接下来,我们将具体探讨如何使用XML编写天气应用界面的布局文件。代码示例将展示如何创建一个简便的天气信息展示界面,以及如何使用各种布局来实现响应式计划。
  1. <!-- 布局文件 activity_weather.xml -->
  2. <androidx.constraintlayout.widget.ConstraintLayout
  3.     xmlns:android="***"
  4.     xmlns:app="***"
  5.     android:layout_width="match_parent"
  6.     android:layout_height="match_parent">
  7.     <!-- 头部时间显示区域 -->
  8.     <TextView
  9.         android:id="@+id/tv_date_time"
  10.         android:layout_width="wrap_content"
  11.         android:layout_height="wrap_content"
  12.         android:textSize="18sp"
  13.         app:layout_constraintTop_toTopOf="parent"
  14.         app:layout_constraintStart_toStartOf="parent"
  15.         android:layout_marginStart="16dp"
  16.         android:text="Date & Time"/>
  17.     <!-- 天气状态显示区域 -->
  18.     <ImageView
  19.         android:id="@+id/iv_weather_state"
  20.         android:layout_width="wrap_content"
  21.         android:layout_height="wrap_content"
  22.         android:layout_marginTop="24dp"
  23.         app:layout_constraintTop_toBottomOf="@id/tv_date_time"
  24.         app:layout_constraintStart_toStartOf="parent"
  25.         app:layout_constraintEnd_toEndOf="parent"
  26.         android:contentDescription="@string/weather_state_icon"/>
  27.     <!-- 天气描述显示区域 -->
  28.     <TextView
  29.         android:id="@+id/tv_weather_description"
  30.         android:layout_width="wrap_content"
  31.         android:layout_height="wrap_content"
  32.         android:textSize="20sp"
  33.         android:layout_marginTop="8dp"
  34.         app:layout_constraintTop_toBottomOf="@id/iv_weather_state"
  35.         app:layout_constraintStart_toStartOf="parent"
  36.         app:layout_constraintEnd_toEndOf="parent"
  37.         android:text="@string/weather_description"/>
  38.     <!-- 其他天气信息如温度、风速等 -->
  39. </androidx.constraintlayout.widget.ConstraintLayout>
复制代码
上面的XML代码定义了一个简便的天气应用界面,包含时间表现、天气图标以及天气描述。它使用了  ConstraintLayout  来实现一个灵活的响应式布局,可以或许顺应差别屏幕尺寸。每个视图组件都根据计划原则进行了位置和巨细的束缚设置,确保在差别设备上都有精良的表现效果。
  通过分析这段代码,我们可以看到XML布局文件的结构化特性以及如何使用差别的属性来控制布局和元素的表现方式。这些布局计划原则和技能可以或许资助开发者创建出既美观又功能性强的Android应用步伐界面。
6. RecyclerView的使用和数据展示

  在现代Android应用中,列表视图是常见的用户界面元素之一,用于展示大量数据。RecyclerView是一个高度灵活的视图用于在有限的窗口中展示大量数据集。本章将深入探讨RecyclerView的内部原理以及如何使用它展示动态数据。
6.1 RecyclerView组件介绍

6.1.1 RecyclerView的工作原理

  RecyclerView通过一个可回收的视图池来提高性能,这种机制可以极大淘汰视图创建与烧毁的开销。它将列表分为几个主要组件:数据源、Adapter和ViewHolder。


  • 数据源 :这是列表需要展示的数据聚集。数据源可以是简单的数组、聚集大概复杂的数据模型。
  • Adapter :Adapter(适配器)负责将数据源中的数据与视图进行绑定。它控制数据如何表现在RecyclerView的各个item中。
  • ViewHolder :ViewHolder是RecyclerView中的一个内部类,它的作用是缓存已经初始化的视图。它像一个视图容器,当列表滚动时,RecyclerView会重用这些预加载的视图,而不是每次都创建新的视图。
6.1.2 计划和实现一个简单的RecyclerView

  在实现RecyclerView之前,需要在项目中添加RecyclerView库依赖:
  1. implementation 'androidx.recyclerview:recyclerview:1.1.0'
复制代码
接下来,通过以下步骤可以计划和实现一个根本的RecyclerView:

  • 定义布局 :创建一个  item_layout.xml  文件,用于定义每个列表项的布局。
  • 创建Adapter类 :创建一个Adapter类,继续自  RecyclerView.Adapter  并实现必要的方法。
  • 定义ViewHolder类 :在Adapter类中定义内部类ViewHolder,用于绑定布局和数据。
  • 设置RecyclerView :在Activity或Fragment中设置RecyclerView的布局管理器,并绑定Adapter。
  下面是一个简单的Adapter实现示例:
  1. public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
  2.     private List<String> mData;
  3.     public MyAdapter(List<String> data) {
  4.         mData = data;
  5.     }
  6.     public static class ViewHolder extends RecyclerView.ViewHolder {
  7.         public TextView textView;
  8.         public ViewHolder(View v) {
  9.             super(v);
  10.             textView = (TextView) v.findViewById(R.id.text_view_item);
  11.         }
  12.     }
  13.     @Override
  14.     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  15.         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
  16.         ViewHolder vh = new ViewHolder(v);
  17.         return vh;
  18.     }
  19.     @Override
  20.     public void onBindViewHolder(ViewHolder holder, int position) {
  21.         holder.textView.setText(mData.get(position));
  22.     }
  23.     @Override
  24.     public int getItemCount() {
  25.         return mData.size();
  26.     }
  27. }
复制代码
6.2 动态数据展示与交互

6.2.1 利用Adapter适配数据

  当数据源发生变化时,需要关照RecyclerView进行数据革新。可以调用Adapter的  notifyDataSetChanged()  方法来关照RecyclerView数据集已更改,它会重新调用  onBindViewHolder()  方法以更新界面。
  1. mAdapter.notifyDataSetChanged();
复制代码
6.2.2 提高列表滚动性能的本事

  为了提高RecyclerView的滚动性能,可以采取如下策略:


  • 使用  RecyclerView.setHasFixedSize(true)   :当RecyclerView的巨细不会改变时,可以提高性能。
  • 预加载图片 :使用  RecyclerView  共同  Picasso  或  Glide  库来异步加载图片,淘汰主线程的压力。
  • 淘汰视图重绘 :尽量避免在  onBindViewHolder  中进行复杂的视图修改操作。
  • 使用  RecyclerView  的  RecycledViewPool   :共享多个RecyclerView的ViewHolder,避免重复创建雷同的ViewHolder。
  1. RecyclerView.RecycledViewPool sharedPool = new RecyclerView.RecycledViewPool();
  2. recyclerView.setRecycledViewPool(sharedPool);
复制代码
通过本章的学习,你已经对RecyclerView组件有了开端的理解,并学会了如何在实际应用中使用它来展示动态数据。在后续章节中,我们将继续学习Material Design风格的实现和Android数据存储等内容,让我们的应用不仅功能强盛,同时也有精良的用户体验。
   本文另有配套的精品资源,点击获取  

  简介:在Android平台上构建天气预报应用需要综合应用多种技能。开发者需认识Android体系架构、把握Android Studio使用,理解Activity与Intent工作原理。应用需要处理网络数据获取,包罗HTTP哀求和JSON解析,以及使用第三方天气API。界面计划要遵照Material Design并考虑用户体验,使用XML布局与RecyclerView展示数据。应用还需考虑数据存储,权限管理和提供定位服务。终极,应用应能通过关照和Widget与用户交互,确保功能完善和用户体验精良。
   本文另有配套的精品资源,点击获取  


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美食家大橙子

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表