The code below, which can be found in the last example here (https://kb.itextpdf.com/home/it7kb/examples/creating-form-fields) uses a class called TextFormFieldBuilder. This class doesn't seem to exist in the API though (at least not for c#). I just downloaded the latest nuget package, and the link has "it7kb" so I assume this documentation is for itext 7.
What am I missing? What do I need to do to make the example work?
namespace iText.Samples.Sandbox.Events
{
public class GenericFields
{
public static readonly String DEST = "results/sandbox/events/generic_fields.pdf";
public static void Main(String[] args)
{
FileInfo file = new FileInfo(DEST);
file.Directory.Create();
new GenericFields().ManipulatePdf(DEST);
}
protected void ManipulatePdf(String dest)
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc);
Paragraph p = new Paragraph();
p.Add("The Effective Date is ");
Text day = new Text(" ");
day.SetNextRenderer(new FieldTextRenderer(day, "day"));
p.Add(day);
p.Add(" day of ");
Text month = new Text(" ");
month.SetNextRenderer(new FieldTextRenderer(month, "month"));
p.Add(month);
p.Add(", ");
Text year = new Text(" ");
year.SetNextRenderer(new FieldTextRenderer(year, "year"));
p.Add(year);
p.Add(" that this will begin.");
doc.Add(p);
doc.Close();
}
private class FieldTextRenderer : TextRenderer
{
protected String fieldName;
public FieldTextRenderer(Text textElement, String fieldName) : base(textElement)
{
this.fieldName = fieldName;
}
// If renderer overflows on the next area, iText uses getNextRender() method to create a renderer for the overflow part.
// If getNextRenderer isn't overriden, the default method will be used and thus a default rather than custom
// renderer will be created
public override IRenderer GetNextRenderer()
{
return new FieldTextRenderer((Text) modelElement, fieldName);
}
public override void Draw(DrawContext drawContext)
{
PdfTextFormField field = new TextFormFieldBuilder(drawContext.GetDocument(), fieldName)
.SetWidgetRectangle(GetOccupiedAreaBBox()).CreateText();
PdfAcroForm.GetAcroForm(drawContext.GetDocument(), true)
.AddField(field);
}
}
}
}
EDIT: I tried the following as it seems to be equivalent logic, but when I run it I get a null reference object on the following line. Specifically, the null reference error happens on the .AddField(field) method call on the last line of the Draw method, but on inspection there is nothing that is null on that line so the error must be coming within that method so I can't tell what the issue is.
PdfTextFormField field = PdfTextFormField.CreateText(drawContext.GetDocument(), GetOccupiedAreaBBox());
I have a little issue with an editable TableView. I want to display data from the database and also be able to edit then which saves it back to the DB.
Now, I can edit it. I have an if statement which checks whether the value is blank (empty or white space) and it works properly, the item in DB doesn't get updated if the value is blank.
My issue is that the blank value still gets displayed. If I click to edit it again, it displays the proper value. Here is a picture of the issue.
Here is the method which creats the table in my view class.
private TableView<Teacher> createTable(){
TableView table = new TableView();
table.setEditable(true);
table.setPrefWidth(500);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
nameColumn = new TableColumn<>("Jméno");
surnameColumn = new TableColumn<>("Příjmení");
nickColumn = new TableColumn<>("Nick");
table.getColumns().addAll(nameColumn, surnameColumn, nickColumn);
int columnCount = table.getColumns().size();
double columnSize = Math.floor(table.getPrefWidth() / columnCount);
nameColumn.setPrefWidth(columnSize);
surnameColumn.setPrefWidth(columnSize);
nickColumn.setPrefWidth(columnSize);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
surnameColumn.setCellValueFactory(new PropertyValueFactory<>("surname"));
nickColumn.setCellValueFactory(new PropertyValueFactory<>("nick"));
List<Teacher> list = new TeacherDao().getAllTeachers();
ObservableList<Teacher> observableList = FXCollections.observableArrayList(list);
table.setItems(observableList);
return table;
}
Here is the part of the controller class to handle the edits.
private void onEditAction(){
view.getNameColumn().setCellFactory(TextFieldTableCell.forTableColumn());
view.getNameColumn().setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Teacher, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Teacher, String> col) {
String newValue = col.getNewValue();
if(!(CheckString.isBlank(newValue))) {
(col.getTableView().getItems().get(
col.getTablePosition().getRow())
).setName(col.getNewValue());
Teacher teacher = view.getTeacherTableView().getSelectionModel().getSelectedItem();
int id = teacher.getUser_id();
new TeacherDao().updateTeacherNick(id, newValue);
}
}
}
);
view.getSurnameColumn().setCellFactory(TextFieldTableCell.forTableColumn());
view.getSurnameColumn().setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Teacher, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Teacher, String> col) {
String newValue = col.getNewValue();
if(!(CheckString.isBlank(newValue))) {
(col.getTableView().getItems().get(
col.getTablePosition().getRow())
).setName(col.getNewValue());
Teacher teacher = view.getTeacherTableView().getSelectionModel().getSelectedItem();
int id = teacher.getUser_id();
new TeacherDao().updateTeacherNick(id, newValue);
}
}
}
);
view.getNickColumn().setCellFactory(TextFieldTableCell.forTableColumn());
view.getNickColumn().setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Teacher, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Teacher, String> col) {
String newValue = col.getNewValue();
if(!(CheckString.isBlank(newValue))) {
(col.getTableView().getItems().get(
col.getTablePosition().getRow())
).setName(col.getNewValue());
Teacher teacher = view.getTeacherTableView().getSelectionModel().getSelectedItem();
int id = teacher.getUser_id();
new TeacherDao().updateTeacherNick(id, newValue);
}
}
}
);
}
I also tried adding, it didn't help though.
else
(col.getTableView().getItems().get(
col.getTablePosition().getRow())
).setName(col.getOldValue());
Well, I managed to solve it, here is how if anyone is curious
public class TeacherTableView extends TableView {
private TableColumn<Teacher, String> nameColumn, surnameColumn, nickColumn;
TeacherTableView() {
createTable();
onEditAction();
}
private void createTable(){
setEditable(true);
setPrefWidth(500);
getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
nameColumn = new TableColumn<>("Jméno");
surnameColumn = new TableColumn<>("Příjmení");
nickColumn = new TableColumn<>("Nick");
getColumns().addAll(nameColumn, surnameColumn, nickColumn);
int columnCount = getColumns().size();
double columnSize = Math.floor(getPrefWidth() / columnCount);
nameColumn.setPrefWidth(columnSize);
nameColumn.setCellValueFactory(cdf -> cdf.getValue().nameProperty());
nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
nameColumn.setEditable(true);
surnameColumn.setPrefWidth(columnSize);
surnameColumn.setCellValueFactory(cdf -> cdf.getValue().surnameProperty());
surnameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
surnameColumn.setEditable(true);
nickColumn.setPrefWidth(columnSize);
nickColumn.setCellValueFactory(cdf -> cdf.getValue().nickProperty());
nickColumn.setCellFactory(TextFieldTableCell.forTableColumn());
nickColumn.setEditable(true);
List<Teacher> list = new TeacherDao().getAllTeachers();
ObservableList<Teacher> observableList = FXCollections.observableArrayList(list);
setItems(observableList);
}
private void onEditAction(){
nameColumn.setOnEditCommit(this::updateCol);
surnameColumn.setOnEditCommit(this::updateCol);
nickColumn.setOnEditCommit(this::updateCol);
}
private void updateCol(TableColumn.CellEditEvent<Teacher, String> col) {
String newValue = col.getNewValue();
if (CheckString.isNotBlank(newValue)) {
(col.getTableView().getItems().get(
col.getTablePosition().getRow())
).setName(col.getNewValue());
Teacher teacher = (Teacher) getSelectionModel().getSelectedItem();
int id = teacher.getUser_id();
new TeacherDao().updateTeacherNick(id, newValue);
} else {
col.getTableView().refresh();
}
}
}
I have a radEditor control with the ImageManager enabled. this feature worked fine within our last version we had (2011 version) but now with the version we have, the image manager does not insert the image selected. Below is my radEditor html tag:
<telerik:RadEditor ID="txtRTE"
SpellCheckSettings-AllowAddCustom="false"
ToolsFile="~/SimpleRTEEditorTools.xml"
OnClientLoad="HandleRTEClientLoad"
ExternalDialogsPath="~/RadControls/EditorDialogs/"
runat="server"
Height="200"
Skin="Default"
EditModes="Design"
AllowScripts="false"
StripFormattingOptions="All">
<ImageManager ViewPaths=".." UploadPaths=".." SearchPatterns="*.jpg,*.gif,*.png" EnableImageEditor="False" ViewMode="Grid" />
I am editing the ViewPaths and uploadPaths within the code behind's page_load method:
txtRTE.ImageManager.ViewPaths = paths;
txtRTE.ImageManager.UploadPaths = paths;
txtRTE.ImageManager.ContentProviderTypeName = typeof(FolderContentProvider).AssemblyQualifiedName;
We implemented our own content provider as seen below:
public class FolderContentProvider : FileBrowserContentProvider
{
private string ROOT_DIRECTORY_FULL_PATH =
//Path to record documents folder
System.Configuration.ConfigurationManager.AppSettings[Constants.RECORD_DOC_ROOT_FOLDER_APP_KEY].ToString() +
//folder containing images
Constants.Record_DOC_FORM_TEXT_IMAGE_FOLDER + "\\" +
//to get Record ID
((MyAppPrincipal)System.Threading.Thread.CurrentPrincipal).Record.ID;
public string RootDirectory
{
get
{
return ROOT_DIRECTORY_FULL_PATH;
}
private set
{
}
}
private PathPermissions fullPermissions = PathPermissions.Read | PathPermissions.Upload;
private DirectoryItem[] GetSubDirectories(string path)
{
//we have only one directory no sub directories
//no need to go to file system to find that out
return new DirectoryItem[0];
}
private string GetDirectoryFullPath(string path)
{
return RootDirectory;
}
private FileItem[] GetFiles(string path)
{
string[] filesFullName = Directory.GetFiles(RootDirectory);
ArrayList files = new ArrayList();
for (int i = 0; i < filesFullName.Length; i++)
{
string fullPath = filesFullName[i];
System.IO.FileInfo currentFile = new System.IO.FileInfo(fullPath);
if (IsAlowedFileExtension(currentFile.Extension))
{
string url = string.Format("{0}?path={1}", HttpContext.Current.Request.ApplicationPath + "/app/FormTextImageHandler.ashx", currentFile.Name);
files.Add(new FileItem(
currentFile.Name, //file name
currentFile.Extension, //extension
currentFile.Length, //size
string.Empty,//currentFile.FullName, //location
url, //url
string.Empty,//tag
fullPermissions//permissions
));
}
}
return (FileItem[])files.ToArray(typeof(FileItem));
}
private bool IsAlowedFileExtension(string Extension)
{
if (Extension.Equals(".gif", StringComparison.InvariantCultureIgnoreCase))
return true;
if (Extension.Equals(".jpg", StringComparison.InvariantCultureIgnoreCase))
return true;
if (Extension.Equals(".png", StringComparison.InvariantCultureIgnoreCase))
return true;
return false;
}
public FolderContentProvider(HttpContext context, string[] searchPatterns, string[] viewPaths, string[] uploadPaths, string[] deletePaths, string selectedUrl, string selectedItemTag)
: base(context, searchPatterns, viewPaths, uploadPaths, deletePaths, selectedUrl, selectedItemTag)
{
}
public override string DeleteFile(string path)
{
//we do not allow removing files
return null;
}
public override string DeleteDirectory(string path)
{
//we don't have any sub directories
//and moreover we don't give delete rights
return null;
}
public override string StoreFile(Telerik.Web.UI.UploadedFile file, string path, string name, params string[] arguments)
{
int fileLength = (int)file.InputStream.Length;
byte[] content = new byte[fileLength];
file.InputStream.Read(content, 0, fileLength);
string fullPath = RootDirectory +"\\"+ name;
FileStream fileStream = new FileStream(fullPath, FileMode.OpenOrCreate);
fileStream.Write(content, 0, content.Length);
fileStream.Flush();
fileStream.Close();
return string.Empty;
}
public override DirectoryItem ResolveDirectory(string path)
{
DirectoryItem[] directories = new DirectoryItem[0];
FileItem[] files = this.GetFiles(RootDirectory);
DirectoryItem dir = new DirectoryItem("Images", string.Empty, RootDirectory, string.Empty, fullPermissions, files, directories);
return dir;
}
public override DirectoryItem ResolveRootDirectoryAsTree(string path)
{
//we don't have any subdirectories - everythinng is in the same folder
DirectoryItem[] directories = new DirectoryItem[0];
FileItem[] files = this.GetFiles(RootDirectory);
DirectoryItem root = new DirectoryItem("Images", string.Empty, "Images\\", string.Empty, fullPermissions, files, directories);
return root;
}
public override bool CanCreateDirectory
{
get
{
return false;
}
}
public override string CreateDirectory(string path, string name)
{
return null;
}
public override string StoreBitmap(Bitmap bitmap, string url, ImageFormat format)
{
return null;
}
public override Stream GetFile(string url)
{
return null;
}
public override string GetPath(string url)
{
return RootDirectory;
}
public override string GetFileName(string url)
{
return null;
}
[Obsolete]
public override DirectoryItem[] ResolveRootDirectoryAsList(string path)
{
return null;
}
public override bool CheckWritePermissions(string folderPath) {
return true;
}
}
Any idea's why the old version was able to insert into the field, but the new version is not?
The FileBrowserProvider API could be changed between the old and new versions. That why my suggestion is to examine the code of the following demo http://demos.telerik.com/aspnet-ajax/editor/examples/dbfilebrowsercontentprovider/defaultcs.aspx that works as expected and compare it with the code of your custom solution.
If you have any customized dialogs you may need to copy the EditorDialogs folder from the new installation that you are using and customize them from scratch.
Best regards,
Rumen
I found some examples for how to extract images from PDF using iText. But what I am looking for is to get the images from PDF by coordinates.
Is it possible? If yes then how it can be done.
Along the lines of the iText example ExtractImages you can extract code like this:
PdfReader reader = new PdfReader(resourceStream);
PdfReaderContentParser parser = new PdfReaderContentParser(reader);
ImageRenderListener listener = new ImageRenderListener("testpdf");
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
parser.processContent(i, listener);
}
The ImageRenderListener is defined like this:
class ImageRenderListener implements RenderListener
{
final String name;
int counter = 100000;
public ImageRenderListener(String name)
{
this.name = name;
}
public void beginTextBlock() { }
public void renderText(TextRenderInfo renderInfo) { }
public void endTextBlock() { }
public void renderImage(ImageRenderInfo renderInfo)
{
try
{
PdfImageObject image = renderInfo.getImage();
if (image == null) return;
int number = renderInfo.getRef() != null ? renderInfo.getRef().getNumber() : counter++;
String filename = String.format("%s-%s.%s", name, number, image.getFileType());
FileOutputStream os = new FileOutputStream(filename);
os.write(image.getImageAsBytes());
os.flush();
os.close();
PdfDictionary imageDictionary = image.getDictionary();
PRStream maskStream = (PRStream) imageDictionary.getAsStream(PdfName.SMASK);
if (maskStream != null)
{
PdfImageObject maskImage = new PdfImageObject(maskStream);
filename = String.format("%s-%s-mask.%s", name, number, maskImage.getFileType());
os = new FileOutputStream(filename);
os.write(maskImage.getImageAsBytes());
os.flush();
os.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
As you see the ImageRenderListener method renderImage retrieves an argument ImageRenderInfo. This arguments has methods
getStartPoint giving you a vector in User space representing the start point of the xobject and
getImageCTM giving you the coordinate transformation matrix active when this image was rendered. Coordinates are in User space.
The latter gives you the information which exact manipulation on a 1x1 user space unit square are used to actually draw the image. As you are aware, an image may be rotated, stretched, skewed, and moved (the former method actually extracts its result from the matrix from the "moved" information).
I have a screen which call a listfield.
public class Main_AllLatestNews extends MainScreen {
private Database_Webservice webservice;
private String[] title, category, date, imagepath = {"no picture", "no picture", "no picture", "no picture","no picture","no picture","no picture","no picture","no picture", "no picture"};
private int[] newsid;
private List_News newslist;
public Main_AllLatestNews(final boolean needdownload) {
super(USE_ALL_WIDTH);
webservice = new Database_Webservice();
add(new Custom_TopField(this, 0, -1, "", 1, 1));
add(new Custom_BottomField(this, 0));
add(new Custom_HeaderField(Config_GlobalFunction.latest));
if (needdownload){
Main.getUiApplication().pushScreen(
new Custom_LoadingScreen(30));
webservice.UpdateAllCatNews();
}else {
webservice.LoadtodayNews();
newsid = new int[webservice.news.size()];
title = new String[webservice.news.size()];
category = new String[webservice.news.size()];
date = new String[webservice.news.size()];
//imagepath = new String[webservice.news.size()];
for (int i = 0; i < webservice.news.size(); i++) {
newslist = (List_News) webservice.news.elementAt(i);
newsid[i] = newslist.getID();
title[i] = newslist.getNtitle();
category[i] = newslist.getNewCatName();
date[i] = newslist.getNArticalD();
//imagepath[i] = newslist.getImagePath();
}
add(new Custom_ListField(newsid, title, date, category, imagepath, true));
}
}
}
When I add custom_listfield then I get:
Failed to allocate timer 0: no slots left
Here is my listfield
public Custom_ListField(int newsid[], String title[], String date[],
String category[], String imagepath[], boolean islatest) {
super(0, ListField.MULTI_SELECT);
this.newsid = newsid;
setCallback(this);
setBackground(Config_GlobalFunction.loadbackground("background.png"));
this.islatest = islatest;
rows = new Vector();
for (int x = 0; x < title.length; x++) {
TableRowManager row = new TableRowManager();
titlelabel = new Custom_LabelField(title[x],
LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
titlelabel.setFont(Font.getDefault().derive(Font.BOLD, 23));
row.add(titlelabel);
datelabel = new Custom_LabelField(date[x], DrawStyle.ELLIPSIS
| LabelField.USE_ALL_WIDTH | DrawStyle.LEFT);
datelabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
datelabel.setFontColor(Color.GRAY);
row.add(datelabel);
categorylabel = new Custom_LabelField(category[x],
DrawStyle.ELLIPSIS | LabelField.USE_ALL_WIDTH
| DrawStyle.LEFT);
categorylabel.setFont(Font.getDefault().derive(Font.BOLD, 18));
categorylabel.setFontColor(Color.RED);
row.add(categorylabel);
/*Bitmap imagebitmap = null;
if (!imagepath[x].toString().equals("no picture")) {
imagebitmap = Util_ImageLoader.loadImage(imagepath[x]);
} else {
imagepath[x] = "image_base.png";
imagebitmap = Bitmap.getBitmapResource(imagepath[x]);
}
image = new BitmapField(imagebitmap, Field.FIELD_HCENTER
| Field.FIELD_VCENTER);
row.add(image);*/
//setRowHeight(image.getBitmapHeight() + 10);
setRowHeight(70);
rows.addElement(row);
}
setSize(rows.size());
}
In this list, it will call 10 images or more. First I will check got link send to it else load local images. So the row height must be not same, however, it does not auto set row height for each row but set a same height to all row. I think out of memory because i call too many images? but I call in android also no problem.
This is my imageloader.
public class Util_ImageLoader {
public static Bitmap loadImage(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
// can use this for BlackBerry 5.0+ :
// connection = (HttpConnection) (new
// ConnectionFactory()).getConnection(url).getConnection();
connection = (HttpConnection) Connector
.open(url + Util_GetInternet.getConnParam(),
Connector.READ, true);
int responseCode = connection.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
inputStream = connection.openDataInputStream();
dataArray = IOUtilities.streamToBytes(inputStream);
}
} catch (Exception ex) {
} finally {
try {
inputStream.close();
connection.close();
} catch (Exception e) {
}
}
if (dataArray != null) {
bitmap = EncodedImage.createEncodedImage(dataArray, 0,
dataArray.length);
return bitmap.getBitmap();
} else {
return null;
}
}
}
1) What can I do to reduce the use of memory?
2) How to set different row height? I am set bitmap.getbitmapheight() but different bitmap will have different height.
//Updated//
I am running on simulator 9930 OS 7.0 and 8520 OS 5.0. Both also same result. Real Device cannot run because after signing the key also prompt the warning message try to Secure APi. I am completely commented all the images also same. I did not call neither online nor local image. I think is the data problem?
#AlanLai, can you tell us which device this is being run on, and which OS? Is it a simulator, or real hardware? Why don't you try commenting out the image completely. Don't show any images (network images, or local images). See if you still get the problem. Let's try to narrow down where exactly the code is that's causing your problem. Note: please post the information about which device you're testing on above, in the question, not as a comment response here. Thanks
How about to have only one TableRowManager and every drawRow set values with layout with specific values?
There's a lot of things you can do to reduce memory usage. For one, try to avoid keeping objects in memory longer than you really need them. One way this happens is if you keep member variables in your class, that could really be local variables in a method. Keeping member variables may lead to objects living longer than they need to, preventing the release of the memory they occupy.
Util_ImageLoader
For example, in Util_ImageLoader, you do almost all the work in the constructor. But then, you keep the result around (the Bitmap) in a static member variable (_bmap), which keeps it in memory. I know you do this so that you can call getBitmap(). But, you could change the class to be like this:
public class Util_ImageLoader {
public static Bitmap loadImage(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
// can use this for BlackBerry 5.0+ :
// connection = (HttpConnection) (new ConnectionFactory()).getConnection(url).getConnection();
connection = (HttpConnection) Connector.open(url + Util_GetInternet.getConnParam(), Connector.READ,
true);
int responseCode = connection.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
inputStream = connection.openDataInputStream();
dataArray = IOUtilities.streamToBytes(inputStream);
}
} catch (Exception ex) {
}
finally {
try {
inputStream.close();
connection.close();
} catch (Exception e) {
}
}
if (dataArray != null) {
bitmap = EncodedImage.createEncodedImage(dataArray, 0, dataArray.length);
return bitmap.getBitmap();
} else {
return null;
}
}
}
Because your Util_ImageLoader class doesn't really have any state associated with it, you can probably make it a class with just one static method. The static method does not require you to create an instance of Util_ImageLoader to use it. Just do this:
Bitmap img = Util_ImageLoader.loadImage("http://domain.com/path/image.png");
This allows the image that's loaded to be released as soon as the UI is done with it. The existing code keeps that image in memory for the life of the program.
Also, I replaced your custom code that uses a byte[] buffer, with the useful IOUtilities.streamtoBytes() method. Let the built-in libraries do the work of optimizing for you. Most of the time, they will do a pretty good job of that.
You also had some fixed point scaling code in your Util_ImageLoader class that wasn't doing anything. It was creating a scaled image of the same size as the original. So, I just removed that code. That can only help your memory usage. Image manipulation can be expensive.
Finally, I checked the web server return code (HTTP_OK) before I created any of the large objects needed for this method. If the network request fails, you certainly don't want to waste memory for no reason.
Custom_ListField
Again, you are keeping some objects around, possibly longer than needed. Let's go through your member variables:
private Bitmap bg = Bitmap.getBitmapResource("background.png"),
imagebitmap;
I don't know how many instances of Custom_ListField you will have in your app, but if you are going to assign bg to a constant app resource image, you should at least make it a static member variable, so that if there are 10 instances of Custom_ListField, you will only be keeping one bg variable in memory:
private static Bitmap bg = Bitmap.getBitmapResource("background.png"),
imagebitmap;
But, in your case, I don't think you need to keep that member variable at all. You can simply replace it where it's used, like this:
Background background = BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("background.png"));
Then, the imagebitmap member can also be replaced with a local variable:
Bitmap imageBitmap = null;
if (!imagepath[x].toString().equals("no picture")) {
imageBitmap = Util_ImageLoader.loadImage(imagepath[x]);
imageBitmap = loader.getbitmap();
} else {
imagepath[x] = "image_base.png";
imageBitmap = Bitmap.getBitmapResource(imagepath[x]);
}
image = new BitmapField(imageBitmap, Field.FIELD_HCENTER | Field.FIELD_VCENTER);
imageBitmap only needs to be a local variable, not a member variable.
Debugging memory usage usually requires having the whole program, running, and profiling it. With only some of your code, I can't see all the other code that uses it. How many of each class is created is important? Which images are the large ones, and which are small? These are all questions you need to ask yourself to get your memory usage down.
But, hopefully, the general techniques I showed example of above can help you get started.
The problem was the Custom_ListField. This should extends listfield
instead of custom extends manager
public class Custom_ListField extends ListField {
private String[] title, category, date, imagepath;
private int[] newsid, catsid;
private List_News newslist;
private Bitmap imagebitmap[], localimage = Bitmap
.getBitmapResource("image_base.png");
private BrowserField webpage;
private Custom_BrowserFieldListener listener;
private boolean islatest;
private Vector content = null;
private ListCallback callback = null;
private int currentPosition = 0;
public Custom_ListField(Vector content, boolean islatest) {
this.content = content;
this.islatest = islatest;
newsid = new int[content.size()];
title = new String[content.size()];
category = new String[content.size()];
date = new String[content.size()];
imagepath = new String[content.size()];
catsid = new int[content.size()];
imagebitmap = new Bitmap[content.size()];
for (int i = 0; i < content.size(); i++) {
newslist = (List_News) content.elementAt(i);
newsid[i] = newslist.getID();
title[i] = newslist.getNtitle();
category[i] = newslist.getNewCatName();
date[i] = newslist.getNArticalD();
imagepath[i] = newslist.getImagePath();
if (!imagepath[i].toString().equals("no picture")) {
imagebitmap[i] = Util_ImageLoader.loadImage(imagepath[i]);
} else {
imagebitmap[i] = localimage;
}
catsid[i] = newslist.getCatID();
}
initCallbackListening();
this.setRowHeight(localimage.getHeight() + 10);
}
private void initCallbackListening() {
callback = new ListCallback();
this.setCallback(callback);
}
private class ListCallback implements ListFieldCallback {
public ListCallback() {
setBackground(Config_GlobalFunction
.loadbackground("background.png"));
}
public void drawListRow(ListField listField, Graphics graphics,
int index, int y, int width) {
currentPosition = index;
graphics.drawBitmap(
Display.getWidth() - imagebitmap[index].getWidth() - 5,
y + 3, imagebitmap[index].getWidth(),
imagebitmap[index].getHeight(), imagebitmap[index], 0, 0);
graphics.setColor(Color.WHITE);
graphics.drawRect(0, y, width, imagebitmap[index].getHeight() + 10);
graphics.setColor(Color.BLACK);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 20));
graphics.drawText(title[index], 5, y + 3, 0, Display.getWidth()
- imagebitmap[index].getWidth() - 10);
System.out.println(Display.getWidth()
- imagebitmap[index].getWidth() - 10);
graphics.setColor(Color.GRAY);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
graphics.drawText(date[index], 5, y + 6
+ Font.getDefault().getHeight() + 3);
if (islatest) {
graphics.setColor(Color.RED);
graphics.setFont(Font.getDefault().derive(Font.BOLD, 15));
graphics.drawText(category[index], Font.getDefault()
.getAdvance(date[index]) + 3, y + 6
+ Font.getDefault().getHeight() + 3);
}
}
public Object get(ListField listField, int index) {
return content.elementAt(index);
}
public int getPreferredWidth(ListField listField) {
return Display.getWidth();
}
public int indexOfList(ListField listField, String prefix, int start) {
return content.indexOf(prefix, start);
}
}
public int getCurrentPosition() {
return currentPosition;
}
protected boolean navigationClick(int status, int time) {
int index = getCurrentPosition();
if (catsid[index] == 9) {
if (Config_GlobalFunction.isConnected()) {
webpage = new BrowserField();
listener = new Custom_BrowserFieldListener();
webpage.addListener(listener);
MainScreen aboutus = new Menu_Aboutus();
aboutus.add(webpage);
Main.getUiApplication().pushScreen(aboutus);
webpage.requestContent("http://www.orientaldaily.com.my/index.php?option=com_k2&view=item&id="
+ newsid[index] + ":&Itemid=223");
} else
Config_GlobalFunction.Message(Config_GlobalFunction.nowifi, 1);
} else
Main.getUiApplication().pushScreen(
new Main_NewsDetail(newsid[index]));
return true;
}
}