Writing android gui using c++(2:list view holder)
Introduction
Wrapandroid and CLE project gives a choice to write android gui applications with multiple languages, such as python, lua, or c++. This article continues to talk about writing programming using c++. For gui applications, list view control is the most commonly used control, which is to present information to users to perform some action. For 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 to write holder using c++?
Android gui object is wrapped with a cle object. For each cle object, cle presents functions “MallocPrivateBuf” and “GetPrivateBuf” to malloc it private buf, which can be used to contain objects pointers. The buffer will be freed with 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(…);
Begin programming
Using eclipse and NDK to development application. How to install them, please refer to other related articles. Android version should be above 2.2. Wrapandroid has updated to version 0.9.0, please download from http://code.google.com/p/wrapandroid-for-multilanguage. CLE has update to version r7, website is http://www.code.google.com/p/cle-for-android.
Steps :
a. Open eclipse, create a new android project named “listviewholder”
b. cle may be installed from network when application started, in this case, the following permission should be added:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
c. Copy java library starcore_android_r7.jar and wrapandroid.jar to project directory, and add them into project:

d. edit ListviewholderActivity.java,changed as follow,loading native share library.
import com.srplab.wrapandroid.*;
public class ListviewholderActivity extends WrapAndroidActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
StarActivity._Call("DoFile","","/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
d. cle may also be included in the project, in this case, you should copy share libraries of cle to the directory of the project: 

And change download flag to false
public class ListviewholderActivity extends WrapAndroidActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
DownloadFromNetFlag = false;
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
StarActivity._Call("DoFile","","/data/data/"+getPackageName()+"/lib/libCode.so");
}
}
e. edit listview layout:vlist2.xml.
<?xml version="1.0" encoding="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>
f. Create jni directory under project, copy header files of wrap android and cle into jni directory. create new file named code.cpp. and Android.mk, edit Android.mk as follow
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, we should compile source file into share library. The share library expose two functions :
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
void StarCoreService_Term(class ClassOfStarCore *starcore)
the first function will be call when the library is loaded, which can be used to do some initialize. StarCoreService_Term will be called before the share library is unloaded.
The code of code.cpp is list below. We explain in detail;
#include "SRPWrapAndroidEngine_VSDHeader.h"
static class ClassOfSRPInterface *SRPInterface;
static void *StarActivity;
static void *mInflater;
// event listener function of button click,
static VS_INT32 MyButton_onClick(VS_ULONG FunctionChoice,void *EventPara)
{
//create a toast and show some information
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; // the number list view item;
}
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;
// define holder, which contains image, title, info, and button objects. The objects are c pointers.
struct MyHolder{
void *img;
void *title;
void *info;
void *view_btn;
}*holder;
if( convertView == NULL ){
// get resource id contains in the project.
int vlist2 = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","layout/vlist2");
// inflate widgets from resource, using the inflate function of mInflater
convertView = (void *)SRPInterface -> ScriptCall(mInflater,NULL,"inflate","(sio)o","LinearLayoutClass",vlist2, NULL);
// Alloc object’s private buf which is used as holder.
holder = (struct MyHolder *)SRPInterface -> MallocPrivateBuf(convertView,SRPInterface -> GetLayer(convertView),0,sizeof(struct MyHolder));
// get image resource id contains in the layout.
int img = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/img");
// get image widgets, and store the pointer to holder.
holder -> img = (void *)SRPInterface -> ScriptCall(convertView,NULL,"findViewById","(si)o","ImageViewClass", img);
// get text resource id contains in the layout.
int title = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/title");
// get textview widgets, and store the pointer to holder.
holder -> title = (void *)SRPInterface -> ScriptCall(convertView,NULL,"findViewById","(si)o","TextViewClass", title);
// get text resource id contains in the layout.
int info = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/info");
// get textview widgets, and store the pointer to holder.
holder -> info = (void *)SRPInterface -> ScriptCall(convertView,NULL,"findViewById","(si)o","TextViewClass", info);
// get button resource id contains in the layout.
int view_btn = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","id/view_btn");
// get button widgets, and store the pointer to holder.
holder -> view_btn = (void *)SRPInterface -> ScriptCall(convertView,NULL,"findViewById","(si)o","ButtonClass", view_btn);
}else{
// if convertVew is not null, then we can fetch the holder stored in the object private buf.
holder = (struct MyHolder *)SRPInterface -> GetPrivateBuf(convertView,SRPInterface -> GetLayer(convertView),0,NULL);
}
int resid;
switch( position % 3 ){
case 0 :
// get resource id “drawable/i1” in the project
resid = SRPInterface -> ScriptCall(StarActivity,NULL,"getResource","(s)i","drawable/i1");
// set the image to image widget
SRPInterface -> ScriptCall(holder -> img,NULL,"setBackgroundResource","(i)",resid);
// set text
SRPInterface -> ScriptCall(holder -> title,NULL,"setText","(s)","G1");
// set text
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;
}
// set onClick event listener
SRPInterface -> RegEventFunction(holder -> view_btn,&VSOUTEVENTID_ViewClass_onClick,holder -> view_btn,(void *)MyButton_onClick,0);
SRPInterface -> ScriptCall(holder -> view_btn,NULL,"setOnClickListener","()");
return convertView;
}
// init function
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
class ClassOfBasicSRPInterface *BasicSRPInterface;
//--init star core
BasicSRPInterface = starcore ->GetBasicInterface();
SRPInterface = BasicSRPInterface ->GetSRPInterface(BasicSRPInterface->QueryActiveService(NULL),"","");
void *ActivityClass;
ActivityClass = SRPInterface -> GetObjectEx(NULL,"ActivityClass");
// get current activity
StarActivity = (void *)SRPInterface -> ScriptCall(ActivityClass,NULL,"getCurrent","()O");
SRPInterface -> Print("Get Main Activity = %s", SRPInterface -> GetName(StarActivity));
//--create AbsoluteLayout
void *MyLayout = SRPInterface->MallocObject(StarActivity,VSATTRINDEX_ACTIVITYCLASS_VIEWGROUPQUEUE,&VSOBJID_AbsoluteLayoutClass,0,NULL);
// create a layout inflater
mInflater = SRPInterface->MallocObjectL(&VSOBJID_LayoutInflaterClass,0,NULL);
// create an adapter
void *MyAdapter = SRPInterface->MallocObjectL(&VSOBJID_BaseAdapterClass,0,NULL);
// set getCount function of the adapter
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getCount,(void *)MyAdapter_getCount,NULL);
// set getItem function of the adapter
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItem,(void *)MyAdapter_getItem,NULL);
// set getItemId function of the adapter
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getItemId,(void *)MyAdapter_getItemId,NULL);
// set getView function of the adapter
SRPInterface -> CreateOVLFunction(MyAdapter,&VSFUNCID_BaseAdapterClass_getView,(void *)MyAdapter_getView,NULL);
// Create a listview
void *MyListView = SRPInterface->MallocObject(MyLayout,VSATTRINDEX_VIEWGROUPCLASS_VIEWQUEUE,&VSOBJID_ListViewClass,0,NULL);
// set listview layout parameter
SRPInterface -> ScriptCall(MyListView,NULL,"setAbsoluteLayoutParams","(iiii)",FILL_PARENT,FILL_PARENT,0,0);
// set listview’s adapter
SRPInterface -> ScriptCall(MyListView,NULL,"setAdapter","(o)",MyAdapter);
return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
SRPInterface -> Release();
return;
}

Examples:
download from http://wrapandroid-for-multilanguage.googlecode.com/svn/wiki/examples/cgui_listviewholder.rar
Screenshot

Examples:
download from http://wrapandroid-for-multilanguage.googlecode.com/svn/wiki/examples/cgui_listviewholder.rar
