Our Community team is hard at work, producing new SDKs for Kentico Cloud for all types of platforms. Recently, we launched our new Kentico Cloud Delivery JavaRx SDK, enabling Java and Android developers to easily integrate Kentico Cloud into their apps. In this article, I’ll take a closer look at the SDK and sample projects to help you get started with these new GitHub projects.
One of the best parts of development is the ever-changing landscape of technology. Sure, you may be an expert in a library or framework, but there’s about 50 new ones just waiting to be released. It keeps things very exciting and there’s always something new to learn. When it comes to mobile, this is especially true as the major providers look to stake their claim as the go-to platform for developers.
It’s no secret there are plenty of Android devices floating around. With the most diversified and distributed ecosystem, the Android OS is one of the first frameworks that developers look to when creating their mobile apps. To keep up with demand, we recently announced our new Kentico Cloud Delivery JavaRx SDK.
This new SDK is designed to simplify integrating Kentico Cloud into your Java or Android apps by providing built in support for multiple programming styles while giving you built in support for ReactiveX observables. With support for multiple content types, query parameters, and nearly every other Kentico Cloud feature, the SDK should be your one-stop shop for all things Android.
In this article, I want to let you know a little more about the SDK, the sample apps included, and walk you through developing a custom mobile app. Recently, I took the new sample app and updated it to display the always exciting Kentico Cloud News feed. KenticoCloud.com is completely powered by our Kentico Cloud service, so it makes for a great demo of the capabilities.
Be sure to read up on the Kentico Cloud Delivery API to understand the concepts and terms in this article. Also, check out the SDK and it’s included Readme for in-depth info. Alright, let’s get to it!
The Setup
Before I could get going, I needed to make sure my environment was set up for development. Because I’m using Windows 10, this meant getting the Android Studio IDE on my machine. Now, this is a pretty big install, so plan on it taking a bit to complete.
The Android Studio IDE provides a decent interface for development, with code completion, formatting, and coloring options. It’s not Visual Studio 2017, but does have some familiar features. The emulators are baked right in, so no need to download extra components to debug your app. Also, any change to your app can kick off a build process, including tests, ensuring that the code you just wrote will compile.
If you’re just getting started with the IDE, I recommend firing up a sample app and testing it out to get the hang of things.
Kentico Cloud Delivery Java RX SDK
With Android Studio in place, I was ready to get going with the Kentico Cloud Delivery Android SDK. A combination of both the Java and Android platforms, this SDK is designed to bring you all the great functionality of the Kentico Cloud Delivery API to your projects.
Kentico Cloud Delivery Java RX SDK
Built to support ReactiveX projects, the SDK supports the latest trends in Android development, while also maintaining support for traditional programming styles through standard, synchronous, web requests. We also provide two libraries that present different observables, one for standard JavaRx (delivery-rx) and one for Android-specific RX observables using Rx2Android requests (delivery-android). Of course, if you are not using ReactiveX, we also have an adapter for standard http web requests. This makes the SDK a very powerful tool in your arsenal, regardless of your development style.
NOTE
When developing a new application that will utilize our SDK, you should create a new project and follow the GitHub documentation to get started. In my case, I downloaded the entire GitHub project to my local machine to share the sample along that I had access to the entire SDK to show.
Starting with the sample project
The GitHub project contains a lot of code, from the SDK itself to sample projects for Java and Android. Following the pattern for other Kentico Cloud demos, these applications demonstrate how to use the SDK to display sample content from the Dancing Goat site. It’s great way to see how the SDK works with “real” data, however this full project should not be the starting point for your project as it includes the entire SDK rather than including it through Gradle. Let’s check out the sample project structure.
NOTE
You can also start with a blank project. Just follow the GitHub project documentation to see how to create your Kentico Cloud Delivery client and access your content.
SDK Project Structure
The SDK contains several projects, including the delivery-core (the bulk of the SDK), delivery-rx and delivery-android (ReactiveX components), testing projects, and the sample applications for Java and Android. The main area we will take a look at is the sample-android-app and its underlying structure as this the type of project we will be creating in our separate project.
java
In the sample-android-app project, you can see that the code is separated into logical sections, depending on the purpose.
app
This folder contains the logic for each area of the application. This includes core functionality for the base app, as well as content type-specific code.
data
This folder contains the models for the Kentico Cloud content types. It also contains the CloudSource, DataSource, and Repository classes for the content types. This is where the DeliveryClient is used to retrieve the content.
injection
This folder contains classes related to how injection is handled within the app. In the case of the sample project, this is where the different content repositories are loaded.
util
This folder contains several helper classes used within the application. This includes a NetworkHelper, SyncHelper, and ActivityUtils class for working with the data.
res
For the layouts, the sample app contains multiple files for each content type, allowing the display to be customized for each one. Each content type has a unique look and feel.
Here is what the sample app looks like on a device.
The Android Sample app contains a lot of functionality out the box. I would recommend you run the app locally to familiarize yourself with all the components. For the rest of this article, I’ll be creating my own app using a lot of the code from the sample project to model my project around.
Content Type Models
To start my custom development, I needed to define my new content type models. Because my app would be using the Kentico Cloud blog posts, this meant defining my Author and BlogPost models. I also cleared out the existing models, to keep things clean. Because the SDK encompasses the entire Delivery API, we can use strongly-type classes and objects to retrieve content type elements and data.
Author
The Author content type is a pretty basic model, consisting of only a name. The important aspect of this model is it will be used for modular content in my BlogPost model. Other than that, it extends the ContentItem class and has one function for returning the name.
public
final
class
Author
extends
ContentItem
{
public
static
final
String TYPE =
"author"
;
@ElementMapping
(
"name"
)
public
TextElement name;
public
String getName() {
return
name.getValue();
}
}
BlogPost
The BlogPost is the more complex of the two, with several fields for the different content elements. This includes an AssetElement (header image), DateTimeElement (post date), MultipleChoiceElement (topic), and ModularContentElement (author). The SDKs can support several types of elements, so be sure to map yours correctly for your Kentico Cloud content types.
@ElementMapping
(
"title"
)
public
TextElement title;
@ElementMapping
(
"header_image"
)
public
AssetsElement headerImage;
@ElementMapping
(
"perex"
)
public
RichTextElement perex;
@ElementMapping
(
"body"
)
public
RichTextElement body;
@ElementMapping
(
"date"
)
public
DateTimeElement postDate;
@ElementMapping
(
"topic"
)
public
MultipleChoiceElement topic;
@ElementMapping
(
"author"
)
public
ModularContentElement<Author> author;
The BlogPost model contains several functions to return the data. Because AssetElement fields may have multiple values, the class contains a function to return the first item in the collection.
public
String getTeaserImageUrl(){
AssetModel[] assets =
this
.headerImage.getValue();
if
(assets ==
null
){
return
null
;
}
if
(assets.length ==
0
){
return
null
;
}
return
assets[
0
].url;
}
The same concept is applied to the MultipleChoice element for the topic.
public
String getTopic(){
if
(topic.getValue().length >
0
) {
MultipleChoiceOption option = topic.getValue()[
0
];
return
option.name;
}
else
{
return
"General"
;
}
}
Lastly, blog posts use modular content for the author. The class contains a function to return the author name, using the SDK to retrieve the modular content.
public
String getAuthor(){
String strAuthor =
""
;
if
(!author.getValue().isEmpty())
{
for
(Author auth : author.getValue())
{
if
(strAuthor.length() >
0
)
{
strAuthor +=
", "
;
}
strAuthor += auth.getSystem().getName();
}
return
"by "
+ strAuthor;
}
else
{
return
"by General"
;
}
}
For the layout folder, I created new files for my content types, leveraging the existing pattern.
TypeResolver
Next, I updated the TypeResolver to handle my new models. In the /app/config/AppConfig class, I added my new content types. I also updated my project id to the Kentico Cloud website.
public
final
static
String KENTICO_CLOUD_PROJECT_ID =
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
;
public
static
List<TypeResolver<?>> getTypeResolvers(){
// Type resolvers are responsible for creating the strongly typed object out of type
List<TypeResolver<?>> typeResolvers =
new
ArrayList<>();
/// BlogPost resolver
typeResolvers.add(
new
TypeResolver<>(BlogPost.TYPE,
new
Function<Void, BlogPost>() {
@Nullable
@Override
public
BlogPost apply(
@Nullable
Void input) {
return
new
BlogPost();
}
}));
/// Author resolver
typeResolvers.add(
new
TypeResolver<>(Author.TYPE,
new
Function<Void, Author>() {
@Nullable
@Override
public
Author apply(
@Nullable
Void input) {
return
new
Author();
}
}));
return
typeResolvers;
}
Retrieve the content
The next step was to create my repository for the content. Following the sample app pattern, I created the BlogPostsCloudSource, BlogPostsDataSource, and BlogPostsRepository classes in the /data/source/blogposts folder. The only real modification from the sample app was to update the BlogPostsRepository class to retrieve blogpost content items, sorted by the post date.
@Override
public
void
getBlogPosts(
@NonNull
final
LoadBlogPostsCallback callback) {
this
.deliveryService.<BlogPost>items()
.type(BlogPost.TYPE)
.orderParameter(
"elements.date"
, OrderType.Desc)
.limitParameter(
10
)
.getObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new
Observer<DeliveryItemListingResponse<BlogPost>>() {
@Override
public
void
onSubscribe(Disposable d) {
}
@Override
public
void
onNext(DeliveryItemListingResponse<BlogPost> response) {
List<BlogPost> items = (response.getItems());
if
(items ==
null
|| items.size() ==
0
){
callback.onDataNotAvailable();
return
;
}
callback.onItemsLoaded(items);
}
@Override
public
void
onError(Throwable e) {
callback.onError(e);
}
@Override
public
void
onComplete() {
}
});
}
This code leverages the Delivery Filter Parameters in the call to retrieve only the first 10 items, sorted by the post date.
Inline Assets
By using the sample app and its patterns, my app was already close to being done. The main outstanding issue was displaying inline images. By default, Android Studio will replace an <img> tags with placeholder images. Because Kentico Cloud can support super cool inline images, I wanted to make sure those displayed properly. This meant implementing a custom ImageGetter into my project.
PicassoImageGetter
In my /util folder, I created a new class called PicassoImageGetter. This class contains the logic needed to parse HTML and create a Drawing object for any images. The idea is that when the HTML content is retrieved from Kentico Cloud, the custom ImageGetter will parse it and create the image objects for each asset it finds.
package
com.kenticocloud.delivery.sample.androidapp.util;
import
android.content.Context;
import
android.graphics.Bitmap;
import
android.graphics.Canvas;
import
android.graphics.drawable.BitmapDrawable;
import
android.graphics.drawable.Drawable;
import
android.text.Html;
import
com.kenticocloud.delivery.sample.androidapp.R;
import
com.squareup.picasso.Picasso;
import
com.squareup.picasso.Target;
public
class
PicassoImageGetter
implements
Html.ImageGetter {
private
Context mContext;
public
PicassoImageGetter(Context context) {
mContext = context;
}
@Override
public
Drawable getDrawable(String source) {
BitmapDrawablePlaceHolder drawable =
new
BitmapDrawablePlaceHolder();
Picasso.with(mContext)
.load(source)
.placeholder(R.drawable.ic_image_placeholder)
.into(drawable);
return
drawable;
}
private
class
BitmapDrawablePlaceHolder
extends
BitmapDrawable
implements
Target {
protected
Drawable drawable;
@Override
public
void
draw(
final
Canvas canvas) {
if
(drawable !=
null
) {
drawable.draw(canvas);
}
}
public
void
setDrawable(Drawable drawable) {
this
.drawable = drawable;
int
width = drawable.getIntrinsicWidth();
int
height = drawable.getIntrinsicHeight();
drawable.setBounds(
0
,
0
, width, height);
setBounds(
0
,
0
, width, height);
}
@Override
public
void
onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
setDrawable(
new
BitmapDrawable(mContext.getResources(), bitmap));
}
@Override
public
void
onBitmapFailed(Drawable errorDrawable) {
//handle later
}
@Override
public
void
onPrepareLoad(Drawable placeHolderDrawable) {
//handle later
}
}
}
With the ImageGetter created, I updated my /app/blogpost_detail/BlogPostDetailFragment class to utilize the new class. This meant creating a new PicassoImageGetter object and passing it to the Html.fromHtml function.
// body
PicassoImageGetter imageGetter =
new
PicassoImageGetter(view.getContext());
TextView bodyCopyTV = (TextView) view.findViewById(R.id.blogpostDetailBodyCopyTV);
bodyCopyTV.setText(Html.fromHtml(blogpost.getBody(), imageGetter,
null
));
Note that the sample app already utilizes the Picasso library, so adding this was pretty simple.
Other stuff
For my demo, I modified a number of other areas of the sample app.
Colors
The sample app contains a helpful /res/values/colors.xml file for the primary app colors. I updated this with my custom colors.
<resources>
<color name=
"colorPrimary"
>#1e88e5</color>
<color name=
"colorPrimaryDark"
>#303F9F</color>
<color name=
"colorPrimaryLight"
>#FFFFFF</color>
<color name=
"colorAccent"
>#2196f3</color>
</resources>
Strings
The app uses several strings to set labels for titles, menus, and other areas. I updated the /res/values/strings.xml file with my custom values.
<!-- global items -->
<string name=
"app_name"
>Kentico Cloud News</string>
<string name=
"app_main_activity_title"
>Kentico Cloud News</string>
<string name=
"action_settings"
>Settings</string>
<string name=
"error_network_failure_msg"
>Network connection failed</string>
<string name=
"error_msg"
>Error occurred</string>
<string name=
"error_network_not_available"
>Network not available</string>
<string name=
"error_loading_data"
>Error loading data</string>
<string name=
"error_problem_fetching_data"
>There was a problem fetching data</string>
<string name=
"try_again"
>TRY AGAIN</string>
<!-- navigation drawer -->
<string name=
"navigation_drawer_open"
>Open navigation drawer</string>
<string name=
"navigation_drawer_close"
>Close navigation drawer</string>
<string name=
"navigation_drawer_title"
>Kentico Cloud News</string>
<string name=
"navigation_drawer_subtitle"
>cloud
@kentico
.com</string>
<!-- main menu items -->
<string name=
"main_menu_home"
>Kentico Cloud News</string>
<string name=
"main_menu_blogposts"
>Blog Posts</string>
<string name=
"hello_blank_fragment"
>Hello blank fragment</string>
<string name=
"teaser_image"
>Teaser image</string>
<string name=
"no_data"
>There is no data</string>
Menus
Because the sample app has a flyout menu, these values needed to be updated to match my structure. In the /res/menu/drawer_menu.xml, I updated the code with my single menu item.
<group android:checkableBehavior=
"single"
>
<item
android:id=
"@+id/blogposts"
android:icon=
"@drawable/ic_list"
android:title=
"@string/main_menu_blogposts"
/>
</group>
Testing
Once all the code was complete, I was ready to test. I built the app, then fired up the emulator. I confirmed the app launched properly. I also confirmed my blog posts were being displayed correctly.
I selected an item and confirmed the details properly.
Lastly, I confirmed the inline images properly displayed.
Moving forward
In this blog, I took a closer look at the new Kentico Cloud Delivery JavaRx SDK. This project is packed full of great examples and code, to help jump start your Android or Java development. By leveraging the built-in architecture, you can quickly create your Android apps and get up and running quickly. Now, go and make some awesome Kentico Cloud-powered mobile apps!