365bet地区构建由365bet地区后端驱动的Android客户端

365bet地区本指南演示了如何将365bet地区用作Android应用程序的后端

s塞尔吉奥·德尔阿莫

365bet地区版本 4.0.1

365bet地区365bet地区培训

365bet地区培训由创建并积极维护365bet地区框架的人们开发和交付

入门

在本指南中,您将构建一个365bet地区365bet地区应用它将用作公司Intranet后端。它公开了公司公告的JSON API

另外,您将建立一个Android应用程式使用后端提供的JSON API的Intranet客户端

该指南探讨了不同API版本的支持

您将需要什么

要完成本指南,您将需要以下内容

  • 花些时间在你手上

  • 体面的文本编辑器或IDE

  • 安装了JDK或更高版本JAVA首页适当配置

如何完成指南

要完成本指南,您需要从Github中签出源代码并按照指南中介绍的步骤进行操作

要开始,请执行以下操作

365bet地区遵循365bet地区部分

  • 光盘进入grails指导构建由grails后端初始驱动的android客户端

365bet地区或者,如果您已经安装了365bet地区,则可以在“终端”窗口中使用以下命令创建新的应用程序

grails创建应用程序intranet后端grails应用程序配置文件rest api cd grails应用程序

365bet地区当create app命令完成时,365bet地区将使用配置为创建REST应用程序的应用程序创建grails应用程序目录,这是由于使用了参数配置文件rest api并配置为将休眠功能与H数据库一起使用

365bet地区您可以直接转到完整的365bet地区示例,如果您光盘进入grails指导构建由grails后端驱动的android客户端完成

遵循Android部分

  • 光盘进入grails指导构建由grails后端初始android驱动的android客户端

  • 前往下一部分

另外,您可以使用Android Studio的“新建项目向导”创建一个android应用,如以下屏幕截图所示

Android Studio NewProject
Android Studio NewProject
Android Studio NewProject
Android Studio NewProject
您可以直接转到Android示例的完整版本,光盘进入grails指导构建由grails后端驱动的android客户端完整android v
您可以直接转到Android示例的完整版本,光盘进入grails指导构建由grails后端驱动的android客户端完整android v

总览

下图说明了Android应用版本的行为。Android应用由两个活动组成

  • 当Android应用程序初始屏幕加载时,它会请求一个公告列表

  • 365bet地区365bet地区应用程序发送一个JSON负载,其中包括公告列表。对于每个公告,都包含唯一的标识符,标题和HTML正文

  • android应用程序在ListView中呈现JSON有效负载

  • 用户点击公告的标题,然后应用程序过渡到详细信息屏幕。初始屏幕向详细信息屏幕发送公告标识符标题和HTML正文,后者将在WebView中呈现。

概观

365bet地区编写365bet地区应用程序

365bet地区现在您可以开始编写365bet地区应用程序了

创建域类持久性实体

365bet地区我们需要创建持久性实体来存储公司公告,365bet地区通过使用来处理持久性365bet地区365bet地区域类:

365bet地区域类满足Model View Controller MVC模式中的M,并表示映射到基础数据库表上的持久实体。在365bet地区中,域是位于grails应用程序域目录中的类。

365bet地区365bet地区使用以下命令简化了域类的创建创建域类命令.

grailsw创建域类公告解决依赖关系请等待成功配置总时间secs创建grails应用grails公司intranet公告groovy创建src test groovy grails公司intranet AnnouncementSpec groovy

为了简单起见,我们假设公司公告中仅包含一个标题还有一个HTML主体我们将修改在上一步中生成的域类以存储该信息

365bet地区应用程序域Intranet后端公告groovy
内部网后端 公告 {

    标题身体静态的约束标题尺寸: 0..255身体可为空: 
    }

    静态的映射体类型: '文本'  (1)
    }
}
1 它使我们能够在字符串中存储多个字符身体.

域类单元测试

365bet地区365bet地区使测试更加容易从低级单元测试到高级功能测试

我们将测试在“发布”域中的“约束”属性中定义的约束,尤其是两者的可空性和长度标题身体属性

src测试groovy内部网后端公告Spec groovy
内部网后端 免费测试gorm DomainUnitTest
 spock lang规格

        期望:
        公告身体: 空值验证'身体'])
    }

    虚空 "测试标题不能为空"() {
        期望:
        !公告标题: 空值验证'标题'])
    }

    虚空 "测试体可以有多个字符"() {

        什么时候: '用于一串字符'
        海峡''
        256Times Str'一种' }

        然后: '身体验证合格'
        公告身体str验证'身体'])
    }

    虚空 "测试标题最多可包含字符"() {

        什么时候: '用于一串字符'
        海峡''
        256Times Str'一种' }

        然后: '标题验证失败'
        !公告标题str验证'标题'])

        什么时候: '用于一串字符'海峡''
        255Times Str'一种' }

        然后: '标题验证通行证'
        公告标题str验证'标题'])
    }
}

我们可以运行所有测试,包括我们刚刚使用命令test应用创建的测试

grailsw test app解析依赖项,请等待成功配置总时间secs完成compileJava UP截止日期完成compileGroovy完成buildProperties完成processResources完整类完成compileTestJava UP截止日期完整compileTestGroovy完成processTestResources截止日期Date testGroy完成测试完成compileIntegrationTest DATE完成processIntegrationTestResources UP截止日期DATE完全IntegrationTestClasses UP截止日期DATE完全IntegrationTest UP截止日期DATE完全mergeTestReports建立成功的测试通过

版本控制

从一开始就考虑API版本控制非常重要,尤其是当您创建手机应用程序使用的API时用户将运行该应用程序的不同版本,并且需要对API进行版本控制以创建高级功能,但仍要支持旧版本

365bet地区365bet地区允许多种方式版本REST资源.

  • 使用URI

  • 使用接受版本标题

  • 使用超媒体Mime类型

在本指南中,我们将使用接受版本HTTP头

运行版本的设备将调用公告指定在接受版本标头中传递

curl i H接受版本X GET http localhost公告

运行版本的设备将调用公告指定在接受版本标头中传递

curl i H接受版本X GET http localhost公告

创建一个控制器

我们创建一个控制者为了域类我们之前创建的Controller扩展了RestfulController这将为我们提供RESTful功能,以列出创建更新和删除操作公告使用不同HTTP方法的资源

365bet地区应用程序控制器Intranet后端v AnnouncementController groovy
内网后端v 365bet地区 Rest RestfulController
 Intranet后端公告

 公告控制器 延伸RestfulController {
    静态的命名空间'' (1)
    静态的responseFormats'json'] (2)公告控制器公告
1 该控制器将处理我们的api的v
2 我们只想回应JSON有效负载

网址映射

我们希望端点监听公告代替公告此外,我们希望为其声明了v的命名空间的先前控制器处理“接受版本Http标头”设置为的请求。

365bet地区365bet地区使功能强大URL映射进行配置,将下一行添加到映射闭包中

365bet地区应用程序控制器Intranet后端UrlMappings groovy
得到"公告"(:'1.0', 控制者: '公告', 命名空间:'')

加载测试数据

当应用程序启动时,我们将用几条公告填充数据库

为了做到这一点,我们编辑grails应用程序初始化grails公司Intranet BootStrap常规.

365bet地区公司内部网 引导带 {

    定义初始化servletContext公告每个保存定义破坏静态的 清单公告公告标题: '365bet地区365bet地区 Quickcast 365bet地区拦截器'),
                公告标题: '365bet地区365bet地区 Quickcast JSON视图')
        ]
    }
}
上一个代码片段中的公告不包含身体保持代码样本较小的内容365bet地区应用程序初始化Intranet后端BootStrap常规查看完整的代码

功能测试

功能测试涉及对正在运行的应用程序发出HTTP请求并验证结果行为

我们使用365bet地区Rest Client Builder 365bet地区插件当我们使用休息api轮廓

首页travis build grails指南构建由grails后端驱动的android客户端完成

src集成测试groovy内部网后端AnnouncementControllerSpec groovy
内部网后端 grails测试mixin集成集成
 365bet地区测试Spock一次
 grails网站http HttpHeaders
 io micronaut http HttpRequest
 io micronaut http HttpResponse
 io micronaut http HttpStatus
 io micronaut http客户端HttpClient
 只是自动清理
 spock lang共享
 spock lang规格

积分
 公告控制器规格 延伸规格共享
    自动清理HttpClient客户端之前
    虚空在里面的baseUrl"HTTP本地主机$服务器端口"
        这个HttpClient的客户创造的baseUrl的toURL定义 "测试体存在于Api的json公告有效载荷中"() {
        给定HttpRequest请求HttpRequest GET"公告"标头"接受版本", "1.0")

        什么时候: '要求发布版本'HttpResponse清单<地图响应客户端以阻止交换请求清单) (1)

        然后: '请求成功'分别显示HttpStatus状态(3)

        : '响应是JSON有效负载'
        : 'json有效内容包含完整的公告'
1 serverPort是自动注入的,它包含功能测试期间grails应用程序在其中运行的随机端口
2 将api版本作为Http头传递
3 验证响应代码是否正确
4 正文存在于JSON有效负载中

365bet地区365bet地区命令测试应用运行单元集成和功能测试

运行应用程序

要运行该应用程序,请使用gradlew bootRun命令将在端口上启动应用程序

编写Android应用程序

获取公告

365bet地区下图说明了365bet地区应用程序公开的通知的获取和呈现中涉及的类

android公告概述

联网代码

我们有一类初始化服务器常量的类

应用src主java内部网客户端网络常量java
 内部网客户网络;

上市  常数 {
    静态的 最后 GRAILS APP URL"http"; (1)
    静态的 最后 公告路径"公告"; (2)
    静态的 最后 接受版本"1.0"; (3)
}
1 365bet地区365bet地区应用服务器网址
2 365bet地区我们在365bet地区应用中配置的路径UrlMappings常规
3 API版本
您可能需要更改IP地址以匹配本地计算机

模型

服务器发送的公告将呈现到此POJO中

应用src主Java内部网客户端网络模型公告Java
 内部网客户端网络模型;

上市  公告 {
    私人的 longID私人的 标题私人的 身体上市 longgetId返回ID上市 虚空setIdlongID这个id id上市 getTitle返回标题上市 虚空setTitle标题这个标题标题上市 getBody返回身体上市 虚空setBody身体这个身体

网络依赖

您需要将INTERNET权限添加到应用src主AndroidManifest xml

应用src主AndroidManifest xml
    <> android名称="android权限INTERNET"/>

OkHttp

我们将使用Android上最受欢迎的http客户端之一OkHttp

要将OkHttp添加为依赖项,请编辑文件应用程序构建gradle并在依赖性块中添加下一行

应用程序构建gradle
实作'com squareup okhttp okhttp'

格森

格森是一个Java库,可用于将Java对象转换为其JSON表示形式。它还可用于将JSON字符串转换为等效的Java对象

要将Gson添加为依赖项,请编辑文件应用程序构建gradle并在依赖性块中添加下一行

应用程序构建gradle
实作'com google code gson gson'

我们将封装OkHttp Request的实例化到一个类中,以确保始终将Accept Version Http标头设置为常量java

应用src主Java内部网客户端网络NetworkTask Java
 内部网客户网络;

 okhttp请求;

 网络任务 {
    静态的请求requestWithUrl网址返回 请求构建器url url标头"接受版本"常量接受版本

下一个类获取并返回公告列表

应用src主Java内部网客户端网络公告提取器Java
 内部网客户网络;

 android util日志;

 com Google gson Gson;
 com google gson反映TypeToken;

 java io IOException;
 java长反映类型;
 Java有用的ArrayList;
 java有用列表;

 Intranet客户端网络模型公告;
 okhttp OkHttpClient;
 okhttp请求;
 okhttp响应;

上市  公告提取程序 {

    私人的 最后 静态的 TAG公告Fetcher类getSimpleName私人的OkHttpClient客户端OkHttpClient私人的 最后格森·格森格森上市 清单fetchAnnouncements类型listType类型令牌清单getType尝试 {
            url常量GRAILS APP URL常量公告路径jsonString fetchAnnouncementsJsonString网址返回gson fromJson jsonString listType抓住 (IOExceptione登录e TAG e toString返回  数组列表<>();
        }
    }

    私人的 fetchAnnouncementsJsonString网址抛出 IOException请求请求NetworkTask requestWithUrl url响应响应客户端newCall请求执行返回响应主体字符串

为了避免在UI线程中运行网络代码,我们将网络代码封装在异步任务

应用src主Java内部网客户端android asynctasks RetrieveAnnouncementsTask Java
 Intranet客户端android asynctasks;

 Android OS AsyncTask;

 java有用列表;

 Intranet客户端android委托RetrieveAnnouncementsDelegate;
 Intranet客户端网络公告;
 Intranet客户端网络模型公告;

上市  检索公告任务 延伸异步任务空洞, 空洞, 清单> {

    私人的公告Fetcher fetcher公告提取程序私人的RetrieveAnnouncementsDelegate委托上市RetrieveAnnouncementsTask RetrieveAnnouncementsDelegate委托这个代表覆写
     清单doInBackground空洞空洞返回fetcher fetch公告 虚空onPostExecute清单公告如果代表空值委托onAnnouncements提取公告

一旦获得公告列表,我们将把响应传达给实现委托的类

应用src主Java内部网客户端android委托RetrieveAnnouncementsDelegate java
 Intranet客户端android委托;

 java有用列表;

 Intranet客户端网络模型公告;

上市 接口 检索公告委托 {
    虚空onAnnouncementsFetched清单公告

实现接收通知的委托的类是初始Activity

应用src主Java内部网客户端android活动MainActivity java
 Intranet客户端android活动;

 android应用活动;
 android内容意图;
 Android OS捆绑包;
 android小部件ListView;

 Java有用的ArrayList;
 java有用列表;

 内部网客户端R;
 Intranet客户端android适配器AnnouncementAdapter;
 Intranet客户端android asynctasks RetrieveAnnouncementsTask;
 Intranet客户端android委托AnnouncementAdapterDelegate;
 Intranet客户端android委托RetrieveAnnouncementsDelegate;
 Intranet客户端网络模型公告;

上市  我的城市 延伸活动实施RetrieveAnnouncementsDelegate AnnouncementAdapterDelegate上市 静态的 最后 额外编号"ID";
    上市 静态的 最后 额外标题"标题";
    上市 静态的 最后 额外的身体"身体";
    私人的公告适配器适配器覆写
     虚空onCreate Bundle savedInstanceStateonCreate savedInstanceState setContentView R布局活动主要列表显示NoticesListView列表显示findViewById R ID公告ListView适配器公告适配器这个,  数组列表(), 这个NoticesListView setAdapter适配器检索公告任务这个执行(1)
    }

    覆写
    上市 虚空onAnnouncementsFetched清单公告(2)适配器清除适配器addAll公告覆写
    上市 虚空onAnnouncementTapped公告公告segueToAnnouncement活动公告私人的 虚空segueToAnnouncementActivity公告公告Intent i意图这个AnnouncementActivity类,我putExtra EXTRA ID公告getId我putExtra EXTRA TITLE公告getTitle我putExtra EXTRA BODY公告getBody startActivity我
1 触发异步任务以异步获取公告
2 收到通知列表后,刷新UI

MainActivity使用在中定义的ListView

应用src主要res布局活动主要xml

<> xmlns android="http模式android com ap android android"
    xmlns工具="http模式android com工具"
    Android ID="id活动主要"
    android布局宽度="匹配父母"
    android布局高度="匹配父母"
    android paddingBottom="二维活动垂直边距"
    Android paddingLeft="二维活动水平边距"
    android paddingRight="二维活动水平边距"
    android paddingTop="二维活动垂直边距"
    工具上下文="365bet地区公司客户Intranet客户MainActivity">

    <>
        Android ID="ID公告"
        android布局宽度="匹配父母"
        android布局高度="匹配父母">
    

下一个类和布局文件在ListView中呈现不同的公告并处理用户点击

应用src主java内联网客户端android适配器AnnouncementAdapter java
 Intranet客户端android适配器;

 android内容上下文;
 Android视图LayoutInflater;
 android视图;
 Android视图ViewGroup;
 android小部件ArrayAdapter;
 android小部件TextView;

 java有用列表;

 androidx批注NonNull;
 内部网客户端R;
 Intranet客户端android委托AnnouncementAdapterDelegate;
 Intranet客户端网络模型公告;

上市  公告适配器 延伸阵列适配器 {
    私人的AnnouncementAdapterDelegate委托上市公告适配器语境语境清单公告AnnouncementAdapterDelegate委托语境0公告这个代表一些
    上市 视图getView整型位置视图convertView一些ViewGroup父级如果convertView空值来自getContext的convertView LayoutInflater为R布局项目公告父级充气TextView tvTitle TextView convertView findViewById R id tvTitle公告公告getItem位置如果公告空值tvTitle setText公告getTitle tvTitle setOnClickListenerAnnouncementClickListener公告返回convertView私人的  公告点击监听器 实施 视图OnClickListener私人的公告公告公告Click Listener公告公告这个公告公告覆写
        上市 虚空onClick视图视图如果代表空值委托onAnnouncementTap公告
应用src主java内联网客户端android委托AnnouncementAdapterDelegate java
 Intranet客户端android委托;

 Intranet客户端网络模型公告;

上市 接口 AnnouncementAdapterDelegate {
    虚空onAnnouncementTapped公告公告
应用src主要资源布局项目公告xml
<> xmlns android="http模式android com ap android android"
    android布局宽度="匹配父母"
    android布局高度="匹配父母" >
    <>
        Android ID="id tvTitle"
        android paddingTop="二维活动垂直边距"
        android paddingBottom="二维活动垂直边距"
        android布局宽度="包装内容"
        android布局高度="包装内容"/>

详细活动

当用户点击公告时,公告将使用Android Intent Extras

临时演员

您将需要在清单中添加第二个活动

应用src主AndroidManifest xml
        <> android名称="android活动AnnouncementActivity" />
应用src主Java内部网客户端android活动AnnouncementActivity java
 Intranet客户端android活动;

 android应用活动;
 android内容意图;
 Android OS捆绑包;
 Android Webkit WebView;
 android小部件TextView;

 内部网客户端R;

上市  公告活动 延伸活动私人的TextView电视标题私人的WebView wvBody覆写
     虚空onCreate Bundle savedInstanceStateonCreate savedInstanceState setContentView R布局活动公告tvTitle TextView findViewById R id tvTitle wvBody WebView findViewById R id wvBody populateUi私人的 虚空populateUi Intent intent getIntent最后 标题意图getStringExtra MainActivity EXTRA TITLE最后 正文意图getStringExtra MainActivity EXTRA BODY populateUiWithTitleAndBody标题正文私人的 虚空populateUiWithTitleAndBody最后 标题最后 正文电视标题setText标题最后 哑剧"文字HTML";
        最后 编码方式"utf"wvBody loadDataWithBaseURL空值身体哑剧编码空值);
    }
}
应用src主要res布局活动公告xml

<> xmlns android="http模式android com ap android android"
    xmlns工具="http模式android com工具"
    Android ID="id活动主要"
    android布局宽度="匹配父母"
    android布局高度="匹配父母"
    android paddingBottom="二维活动垂直边距"
    Android paddingLeft="二维活动水平边距"
    android paddingRight="二维活动水平边距"
    android paddingTop="二维活动垂直边距"
    工具上下文="365bet地区公司客户Intranet客户MainActivity">

    <>
        Android ID="id tvTitle"
        工具文字="公告标题"
        android textSize="dp"
        android布局宽度="匹配父母"
        android布局高度="包装内容" />

    <>
        Android ID="id wvBody"
        下面的android布局="id tvTitle"
        android布局宽度="包装内容"
        android布局高度="包装内容" />

API版本

API的第一个版本的问题是,我们在用于显示列表的有效载荷中包含了每个公告主体。公告主体可以是很大的HTML块,用户可能只想检查几个公告即可。如果不在初始请求中发送公告正文,则可以增加带宽并提高应用程序的速度。相反,我们将要求API提供完整的公告,包括身体一旦用户点击公告

版本概述

365bet地区365bet地区 V的变化

我们将使用create Controller处理API的版本。我们将使用带有投影的Criteria查询来仅获取公告的ID和标题

365bet地区应用程序控制器Intranet后端v AnnouncementController groovy
内网后端v 365bet地区 Rest RestfulController
 Intranet后端公告

 公告控制器 延伸RestfulController {
    静态的命名空间''
    静态的responseFormats'json']

    定义NoticeService公告控制器公告定义 指数(整数最大参数最大数学最小最大10, 100)
        定义公告公告announceService findAllIdAndTitleProjections参数响应公告模型: [("${resourceName}计数"toString countResources

我们将查询封装在服务中

365bet地区应用程序服务Intranet后端AnnouncementService groovy
内部网后端 grails gorm Transactions事务性

交易性只读)
 公告服务 {

    清单<地图findAllIdAndTitleProjections地图参数定义c公告createCriteria定义公告c列表参数投影属性'ID'属性'标题'收藏ID: [0], 标题: [1]] }  清单<地图>
    }
}

我们测试一下

src测试groovy内部网后端AnnouncementServiceSpec groovy
内部网后端 grails测试休眠HibernateSpec
 免费测试服务ServiceUnitTest

 公告服务规格 延伸休眠规范实施ServiceUnitTest {

    定义 "带有投影的测试标准查询返回地图列表"() {

        什么时候: '保存一些公告'
        [公告标题: '365bet地区 Quickcast 365bet地区拦截器'),
        公告标题: '365bet地区 Quickcast JSON视图'),
        公告标题: '365bet地区365bet地区 Quickcast多项目构建'),
        公告标题: '365bet地区365bet地区 Quickcast角形脚手架'),
        公告标题: '365bet地区在365bet地区中检索运行时配置值'),
        公告标题: '365bet地区使用IntelliJ IDEA开发365bet地区应用程序'保存然后: '公告已保存'公告数6

        什么时候: '获取投影'
        定义响应服务findAllIdAndTitleProjections然后: '响应中有六张地图'分别大小6

        : '地图仅包含ID和标题'分别键集'标题', 'ID']  <>
         }

        : '非空值'分别断言 标题断言 ID

网址映射

我们需要映射版本2.0接受标头到名称空间

365bet地区应用程序控制器Intranet后端UrlMappings groovy
得到"公告"(:'2.0', 控制者: '公告', 命名空间:''得到"公告$ID(.$格式)?"(:'2.0', 控制者: '公告', 行动: '', 命名空间:'')

api功能测试

我们要测试Api版本在收到GET请求时不包含body属性公告端点下一个功能测试将验证该行为

首页travis build grails指南构建由grails后端驱动的android客户端完成

src集成测试groovy内部网后端AnnouncementControllerSpec groovy
内部网后端 grails测试mixin集成集成
 365bet地区测试Spock一次
 grails网站http HttpHeaders
 io micronaut http HttpRequest
 io micronaut http HttpResponse
 io micronaut http HttpStatus
 io micronaut http客户端HttpClient
 只是自动清理
 spock lang共享
 spock lang规格

积分resp标头getFirst HttpHeaders内容类型get'应用程序json字符集UTF'

        : 'json有效内容包含ID为title和body的通告数组'每个身体断言 ID断言 标题断言 身体(4)
        }
    }

    定义 "测试体不存在于Api的json公告有效载荷中"() {
        给定HttpRequest请求HttpRequest GET"公告"标头"接受版本", "2.0")

        什么时候: '要求发布版本'HttpResponse清单<地图响应客户端以阻止交换请求清单)

        然后: '请求成功'分别显示HttpStatus状态(3)

        : '响应是JSON有效负载'resp标头getFirst HttpHeaders内容类型get'应用程序json字符集UTF'
        : 'json有效内容包含完整的公告'
1 正文不在JSON有效负载中

365bet地区命令测试应用运行单元集成和功能测试

Android V变更

首先,我们需要更改在中定义的api版本常量java

应用src主java内部网客户端网络常量java
 内部网客户网络;

上市  常数 {
    静态的 最后 GRAILS APP URL"http";
    静态的 最后 公告路径"公告";
    静态的 最后 接受版本"2.0";
}

详细活动使用asyncTask来获取完整的公告

应用src主要java内部网客户端android asynctasks RetrieveAnnouncementTask java
 Intranet客户端android asynctasks;

 Android OS AsyncTask;

 Intranet客户端android委托RetrieveAnnouncementDelegate;
 Intranet客户端网络AnnouncementFetcher;
 Intranet客户端网络模型公告;

上市  RetrieveAnnouncementTask 延伸异步任务long, 空洞公告私人的 静态的 最后 TAG RetrieveAnnouncementTask类getSimpleName AnnouncementFetcher提取程序公告提取程序私人的RetrieveAnnouncementDelegate委托上市RetrieveAnnouncementTask RetrieveAnnouncementDelegate委托这个代表覆写
    公告doInBackgroundlong编号如果编号空值ID长度1) {
            longnotificationId ID0];
            返回fetcher fetchAnnouncementannouncementId返回 空值;
    }

     虚空onPostExecute公告公告如果代表空值委托onAnnouncement取得公告

收到公告后,我们会将响应传达给实现委托的类

应用src主要java内部网客户端android委托RetrieveAnnouncementDelegate java
 Intranet客户端android委托;

 Intranet客户端网络模型公告;

上市 接口 检索公告委托 {
    虚空onAnnouncementFetched公告公告

公告活动实现委托并呈现公告

应用src主Java内部网客户端android活动AnnouncementActivity java
 Intranet客户端android活动;

 android应用活动;
 android内容意图;
 Android OS捆绑包;
 Android Webkit WebView;
 android小部件TextView;

 内部网客户端R;
 Intranet客户端android asynctasks RetrieveAnnouncementTask;
 Intranet客户端android委托RetrieveAnnouncementDelegate;
 Intranet客户端网络模型公告;

上市  公告活动 延伸活动实施检索公告委托私人的TextView电视标题私人的WebView wvBody覆写
     虚空onCreate Bundle savedInstanceStateonCreate savedInstanceState setContentView R布局活动公告tvTitle TextView findViewById R id tvTitle wvBody WebView findViewById R id wvBody Intent intent getIntent最后 longsubscriptionId intent getLongExtra MainActivity EXTRA ID);
        RetrieveAnnouncementTask这个执行announcementId私人的 虚空populateUiWithTitleAndBody最后 标题最后 正文电视标题setText标题最后 哑剧"文字HTML";
        最后 编码方式"utf"wvBody loadDataWithBaseURL空值身体哑剧编码空值);
    }

    覆写
    上市 虚空onAnnouncementFetched公告公告populateUiWithTitleAndBody公告getTitle公告getBody

结论

365bet地区借助365bet地区轻松的API版本控制,我们现在可以支持两个运行不同版本的Android应用程序

您需要365bet地区帮助吗

OCI赞助了本指南的创建OCI提供了几种365bet地区服务:

免费咨询

OCI 365bet地区团队包括365bet地区联合创始人Jeff Scott Brown和Graeme Rocher检查我们的365bet地区课程并向发展和维护365bet地区的工程师学习

Grails OCI团队