Introduction
Wrapandroid and the CLE project give a choice to write Android GUI applications with multiple languages, such as Python, lua, or C++. This article continues
to talk about programming using C++. For GUI applications, the list view control is the most commonly used control, which is
used to present information to users
to perform some action. For a list view, to speed up scroll speed, a view holder is often used. We can find many materials talking about it in Java. But how
do we write a holder using C++?
The Android GUI object is wrapped with a CLE object. For each CLE object,
CLE presents the functions MallocPrivateBuf
and GetPrivateBuf
to
malloc
its private buf,
which can be used to contain object pointers. The buffer will be freed with the object automatically. Like this:
struct Holder{
void *Object1;
void *Object2;
…
}*holder;
holder = (struct Holder *)SRPInterface -> MallocPrivateBuf(…);
and then get the holder:
holder = (struct Holder *)SRPInterface -> GetPrivateBuf(…);
Create Project
We are using Eclipse and NDK to develop the application. To know more on how to install them, please refer to
the other related articles. The Android version should be above 2.2. Wrapandroid has
been updated to version 0.9.0, please download it from
http://code.google.com/p/wrapandroid-for-multilanguage. CLE has
benn updated to version r7,
the website is http://www.code.google.com/p/cle-for-android.
The functions of the Wrapandroid object are nearly 90% same with the corresponding
Android object. To learn about how to use these functions and which functions are presented, please refer
to the Android SDK document and the wrapandroid.chm document.
Steps
- Open Eclipse, create a new Android project named “listviewholder”.
- CLE may be installed from the network when application starts, in this case, the following permission should be added:
<uses-permission android:name="android.permission.INTERNET" />0
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
- Copy the Java libraries starcore_android_r7.jar and wrapandroid.jar to
the project directory, and add them into the project:
- Edit ListviewholderActivity.java and change as follows, loading the native share library.
import com.srplab.wrapandroid.*;
public class ListviewholderActivity extends WrapAndroidActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StarActivity._Call("DoFile","",
"/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
- The CLE may also be included in the project, in this case, you should copy
the share libraries of CLE to the directory of the project:
And change the download flag to false:
public class ListviewholderActivity extends WrapAndroidActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
DownloadFromNetFlag = false;
super.onCreate(savedInstanceState);
StarActivity._Call("DoFile","",
"/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
List View
There are many examples to explain how to create list views and how to use a holder to speed up scroll. But they are all written with Java.
How do we program with the C++ language? This article gives an example. To create
a list view, we need three steps. First, create a layout using an XML file.
Of course you can create the layout dynamically. Next, create an adapter which is used to provide widgets shown in each view item. And finally,
create a list view widget and assign the adapter to the list view.
Step 1: Define layout
The following is an example of the layout which includes linear layout, image view, text view, and button.
The layout file is written in XML format.
="1.0"="utf-8"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5px"/>
<LinearLayout android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
android:textSize="22px" />
<TextView android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
android:textSize="13px" />
</LinearLayout>
<Button android:id="@+id/view_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="more"
android:layout_gravity="bottom|right" />
</LinearLayout>
Step 2: Create adapter
An adapter is used to provide the contents for the list view. Android defines many kinds of adapters such as cursor adapter, array list adapter, etc.,
which are subclassed from BaseAdapter
. To create our own adapter,
we can extend BaseAdapter
and override its functions getCount
,
getItem
, getItemId
, and getView
. The
getCount
function should return the number of items to be displayed
in the list view. The getItem
function returns the object at a special position and
getItemId
returns the ID of the object. getView
is the main part. In this function, we inflate the layout defined in
the above XML file, set the contents of the widgets in the layout, and provide it to
the list view.
The following is example of an adapter:
Create an adapter
The Android BaseAdapter
is wrapped with BaseAdapterClass
. We create an instance of it using
the function MallocObjectL
,
and using the function CreateOVLFunction
of the CLE interface to override its functions.
The parameter of MallocObjectL
is an object id of BaseAdapterClass
, which is defined in the
C++ source file SRPWrapAndroidEngine_UUIDDef.cpp
of the Wrapandroid development files. This file must be included in the project when compiling. Other parameters of
MallocObjectL
do not need to be taken care of, and we set them as
in the following code.
The CreateOVLFunction
function is used to override functions defined in the class.
The input parameter of it is a function ID and function address.
The function ID is also defined in the file SRPWrapAndroidEngine_UUIDDef.cpp.
void *MyAdapter = SRPInterface->MallocObjectL(&VSOBJID_BaseAdapterClass,0,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getCount,(void *)MyAdapter_getCount,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItem,(void *)MyAdapter_getItem,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItemId,(void *)MyAdapter_getItemId,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getView,(void *)MyAdapter_getView,NULL);
getCount function
This function returns the number of items to be shown in the list view. In this example, we simply return a number 20.
static VS_INT32 SRPAPI MyAdapter_getCount(void *Object)
{
return 20; }
getItem function
This function returns the object at a special position. In the Android Java prototype of this function, the return value is
Object
, which means any type of Java object.
But for C++, we must be return a clear.
static VS_INT32 SRPAPI MyAdapter_getItem(void *Object,VS_INT32 Position)
{
return Position;
}
Create a jni directory under the project, copy the header files of Wrapandroid and
CLE into the jni directory. Create new files named code.cpp and Android.mk, edit
Android.mk as follows:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and sourcefile(s)
LOCAL_CFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_CPPFLAGS += -Wno-write-strings -fexceptions -DENV_ANDROID
LOCAL_LDFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_C_INCLUDES += cle_files/include
#--------source file
MODULE_CXXSRCS := Code.cpp SRPWrapAndroidEngine_UUIDDef.cpp
LOCAL_SRC_FILES := ${MODULE_CXXSRCS}
LOCAL_LDLIBS := cle_files/libs/armeabi/libstarlib.a
LOCAL_MODULE := Code
include $(BUILD_SHARED_LIBRARY)
#------------------------
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cle_files/so/armeabi/libstarcore.so
LOCAL_MODULE := starcore
include $(PREBUILT_SHARED_LIBRARY)
#------------------------
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cle_files/so/armeabi/libstar_java.so
LOCAL_MODULE := star_java
include $(PREBUILT_SHARED_LIBRARY)
code.cpp
Write native code in Android, and we should compile the source file into a share library. The share library exposes two functions:
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
void StarCoreService_Term(class ClassOfStarCore *starcore)
The first function will be called when the library is loaded, which can be used to do some initializing.
StarCoreService_Term
will be called before the share library is unloaded. The code of
code.cpp is listed below. We will see this in detail:
#include "SRPWrapAndroidEngine_VSDHeader.h"
static class ClassOfSRPInterface *SRPInterface;
static void *StarActivity;
static void *mInflater;
static VS_INT32 MyButton_onClick(VS_ULONG FunctionChoice,void *EventPara)
{
void *toast = SRPInterface->MallocObjectL(&VSOBJID_ToastClass,0,NULL);
SRPInterface -> ScriptCall(toast,NULL,"makeText","(si)","Button is click", 0);
SRPInterface -> ScriptCall(toast,NULL,"show","()");
return 0;
}
static VS_INT32 SRPAPI MyAdapter_getCount(void *Object)
{
return 20; }
static VS_INT32 SRPAPI MyAdapter_getItem(void *Object,VS_INT32 Position)
{
return Position;
}
static VS_LONG SRPAPI MyAdapter_getItemId(void *Object,VS_INT32 Position)
{
return Position;
}
static VS_OBJPTR SRPAPI MyAdapter_getView(void *Object,
VS_INT32 position,VS_OBJPTR convertView,VS_OBJPTR parent)
{
void *i;
struct MyHolder{
void *img;
void *title;
void *info;
void *view_btn;
}*holder;
if( convertView == NULL ){
int vlist2 = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","layout/vlist2");
convertView = (void *)SRPInterface -> ScriptCall(mInflater,NULL,"inflate",
"(sio)o","LinearLayoutClass",vlist2, NULL);
holder = (struct MyHolder *)SRPInterface -> MallocPrivateBuf(convertView,
SRPInterface -> GetLayer(convertView),0,sizeof(struct MyHolder));
int img = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/img");
holder -> img = (void *)SRPInterface -> ScriptCall(convertView,NULL,
"findViewById","(si)o","ImageViewClass", img);
int title = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/title");
holder -> title = (void *)SRPInterface -> ScriptCall(convertView,NULL,
"findViewById","(si)o","TextViewClass", title);
int info = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/info");
holder -> info = (void *)SRPInterface -> ScriptCall(convertView,NULL,
"findViewById","(si)o","TextViewClass", info);
int view_btn = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","id/view_btn");
holder -> view_btn = (void *)SRPInterface -> ScriptCall(convertView,NULL,
"findViewById","(si)o","ButtonClass", view_btn);
}else{
holder = (struct MyHolder *)SRPInterface -> GetPrivateBuf(convertView,
SRPInterface -> GetLayer(convertView),0,NULL);
}
int resid;
switch( position % 3 ){
case 0 :
resid = SRPInterface -> ScriptCall(StarActivity,NULL,
"getResource","(s)i","drawable/i1");
SRPInterface -> ScriptCall(holder -> img,NULL,"setBackgroundResource","(i)",resid);
SRPInterface -> ScriptCall(holder -> title,NULL,"setText","(s)","G1");
SRPInterface -> ScriptCall(holder -> info,NULL,"setText","(s)","google 1");
break;
case 1 :
resid = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","drawable/i2");
SRPInterface -> ScriptCall(holder -> img,NULL,"setBackgroundResource","(i)",resid);
SRPInterface -> ScriptCall(holder -> title,NULL,"setText","(s)","G2");
SRPInterface -> ScriptCall(holder -> info,NULL,"setText","(s)","google 2");
break;
case 2 :
resid = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","drawable/i3");
SRPInterface -> ScriptCall(holder -> img,NULL,"setBackgroundResource","(i)",resid);
SRPInterface -> ScriptCall(holder -> title,NULL,"setText","(s)","G3");
SRPInterface -> ScriptCall(holder -> info,NULL,"setText","(s)","google 3");
break;
}
SRPInterface -> RegEventFunction(holder -> view_btn,&VSOUTEVENTID_ViewClass_onClick,
holder -> view_btn,(void *)MyButton_onClick,0);
SRPInterface -> ScriptCall(holder -> view_btn,NULL,"setOnClickListener","()");
return convertView;
}
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
class ClassOfBasicSRPInterface *BasicSRPInterface;
BasicSRPInterface = starcore ->GetBasicInterface();
SRPInterface = BasicSRPInterface ->GetSRPInterface(
BasicSRPInterface->QueryActiveService(NULL),"","");
void *ActivityClass;
ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
StarActivity = (void *)SRPInterface -> ScriptCall(ActivityClass,NULL,"getCurrent","()O");
SRPInterface -> Print("Get Main Activity = %s", SRPInterface -> GetName(StarActivity));
void *MyLayout = SRPInterface->MallocObject(StarActivity,VSATTRINDEX_ACTIVITYCLASS_VIEWGROUPQUEUE,
&VSOBJID_AbsoluteLayoutClass,0,NULL);
mInflater = SRPInterface->MallocObjectL(&VSOBJID_LayoutInflaterClass,0,NULL);
void *MyAdapter = SRPInterface->MallocObjectL(&VSOBJID_BaseAdapterClass,0,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getCount,(void *)MyAdapter_getCount,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItem,(void *)MyAdapter_getItem,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItemId,(void *)MyAdapter_getItemId,NULL);
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getView,(void *)MyAdapter_getView,NULL);
void *MyListView = SRPInterface->MallocObject(MyLayout,VSATTRINDEX_VIEWGROUPCLASS_VIEWQUEUE,&VSOBJID_ListViewClass,0,NULL);
SRPInterface -> ScriptCall(MyListView,NULL,"setAbsoluteLayoutParams",
"(iiii)",FILL_PARENT,FILL_PARENT,0,0);
SRPInterface -> ScriptCall(MyListView,NULL,"setAdapter","(o)",MyAdapter);
return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
SRPInterface -> Release();
return;
}
Screenshot