Android JSOUP ListView Images and Texts from HTML Tables Tutorial

In this tutorial, you will learn how to extract elements from a HTML table using JSOUP Library. JSOUP provides a very convenient API for extracting and manipulating data, using DOM, CSS, and jquery-like methods. JSOUP allows you to scrape and parse HTML from a URL, file, or string and many more. We will create a ListView on the main view and populate it with extracted HTML elements from a HTML table provided. So lets begin…

Before you proceed with this tutorial, download the latest JSOUP library from here.

Create a new project in Eclipse File > New > Android Application Project. Fill in the details and name your project JsoupListViewTutorial.

Application Name : JsoupListViewTutorial

Project Name : JsoupListViewTutorial

Package Name : com.androidbegin.jsouplistviewtutorial

Open your MainActivity.java and paste the following code.

MainActivity.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

packagecom.androidbegin.jsouplistviewtutorial;

import java.io.IOException;

import java.util.ArrayList;

import java.util.HashMap;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

import android.os.AsyncTask;

import android.os.Bundle;

import android.app.Activity;

import android.app.ProgressDialog;

import android.widget.ListView;

publicclassMainActivityextendsActivity{

ListView listview;

ListViewAdapter adapter;

ProgressDialog mProgressDialog;

ArrayList<HashMap<String,String>>arraylist;

staticStringRANK="rank";

staticStringCOUNTRY="country";

staticStringPOPULATION="population";

staticStringFLAG="flag";

// URL Address

Stringurl="http://www.androidbegin.com/tutorial/jsouplistview.html";

@Override

publicvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

// Get the view from listview_main.xml

setContentView(R.layout.listview_main);

// Execute DownloadJSON AsyncTask

newJsoupListView().execute();

}

// Title AsyncTask

privateclassJsoupListView extendsAsyncTask<Void,Void,Void>{

@Override

protectedvoidonPreExecute(){

super.onPreExecute();

// Create a progressdialog

mProgressDialog=newProgressDialog(MainActivity.this);

// Set progressdialog title

mProgressDialog.setTitle("Android Jsoup ListView Tutorial");

// Set progressdialog message

mProgressDialog.setMessage("Loading...");

mProgressDialog.setIndeterminate(false);

// Show progressdialog

mProgressDialog.show();

}

@Override

protectedVoiddoInBackground(Void...params){

// Create an array

arraylist=newArrayList<HashMap<String,String>>();

try{

// Connect to the Website URL

Document doc=Jsoup.connect(url).get();

// Identify Table Class "worldpopulation"

for(Element table:doc.select("table[class=worldpopulation]")){

// Identify all the table row's(tr)

for(Element row:table.select("tr:gt(0)")){

HashMap<String,String>map=newHashMap<String,String>();

// Identify all the table cell's(td)

Elements tds=row.select("td");

// Identify all img src's

Elements imgSrc=row.select("img[src]");

// Get only src from img src

StringimgSrcStr=imgSrc.attr("src");

// Retrive Jsoup Elements

// Get the first td

map.put("rank",tds.get(0).text());

// Get the second td

map.put("country",tds.get(1).text());

// Get the third td

map.put("population",tds.get(2).text());

// Get the image src links

map.put("flag",imgSrcStr);

// Set all extracted Jsoup Elements into the array

arraylist.add(map);

}

}

}catch(IOExceptione){

// TODO Auto-generated catch block

e.printStackTrace();

}

returnnull;

}

@Override

protectedvoidonPostExecute(Voidresult){

// Locate the listview in listview_main.xml

listview=(ListView)findViewById(R.id.listview);

// Pass the results into ListViewAdapter.java

adapter=newListViewAdapter(MainActivity.this,arraylist);

// Set the adapter to the ListView

listview.setAdapter(adapter);

// Close the progressdialog

mProgressDialog.dismiss();

}

}

}

In this MainActivity, we have created an AsyncTask to connect to the website URL . Then we used the Jsoup selector to select the appropriate Table Rows and Table Cells. You can read more about Jsoup Selectors using this link. Then we map the captured results into an Array list and passed into the ListViewAdapter.

In this custom listview adapter class, string arrays are passed into the ListViewAdapter and set into the TextViews and ImageViews followed by the positions. On listview item click will pass the string arrays and position to a new activity.

Next, create an imageloader class. Go to File > New > Class and name it ImageLoader.java. Select your package named com.androidbegin.jsouplistviewtutorialand click Finish.

Open your ImageLoader.javaand paste the following code.

ImageLoader.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

packagecom.androidbegin.jsouplistviewtutorial;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.Collections;

import java.util.Map;

import java.util.WeakHashMap;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import android.os.Handler;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.widget.ImageView;

publicclassImageLoader{

MemoryCache memoryCache=newMemoryCache();

FileCache fileCache;

privateMap<ImageView,String>imageViews=Collections

.synchronizedMap(newWeakHashMap<ImageView,String>());

ExecutorService executorService;

// Handler to display images in UI thread

Handler handler=newHandler();

publicImageLoader(Context context){

fileCache=newFileCache(context);

executorService=Executors.newFixedThreadPool(5);

}

finalintstub_id=R.drawable.temp_img;

publicvoidDisplayImage(Stringurl,ImageView imageView){

imageViews.put(imageView,url);

Bitmap bitmap=memoryCache.get(url);

if(bitmap!=null)

imageView.setImageBitmap(bitmap);

else{

queuePhoto(url,imageView);

imageView.setImageResource(stub_id);

}

}

privatevoidqueuePhoto(Stringurl,ImageView imageView){

PhotoToLoadp=newPhotoToLoad(url,imageView);

executorService.submit(newPhotosLoader(p));

}

privateBitmap getBitmap(Stringurl){

Filef=fileCache.getFile(url);

Bitmapb=decodeFile(f);

if(b!=null)

returnb;

// Download Images from the Internet

try{

Bitmap bitmap=null;

URL imageUrl=newURL(url);

HttpURLConnection conn=(HttpURLConnection)imageUrl

.openConnection();

conn.setConnectTimeout(30000);

conn.setReadTimeout(30000);

conn.setInstanceFollowRedirects(true);

InputStream is=conn.getInputStream();

OutputStream os=newFileOutputStream(f);

Utils.CopyStream(is,os);

os.close();

conn.disconnect();

bitmap=decodeFile(f);

returnbitmap;

}catch(Throwable ex){

ex.printStackTrace();

if(ex instanceofOutOfMemoryError)

memoryCache.clear();

returnnull;

}

}

// Decodes image and scales it to reduce memory consumption

privateBitmap decodeFile(Filef){

try{

// Decode image size

BitmapFactory.Optionso=newBitmapFactory.Options();

o.inJustDecodeBounds=true;

FileInputStream stream1=newFileInputStream(f);

BitmapFactory.decodeStream(stream1,null,o);

stream1.close();

// Find the correct scale value. It should be the power of 2.

// Recommended Size 512

finalintREQUIRED_SIZE=70;

intwidth_tmp=o.outWidth,height_tmp=o.outHeight;

intscale=1;

while(true){

if(width_tmp/2<REQUIRED_SIZE

||height_tmp/2<REQUIRED_SIZE)

break;

width_tmp/=2;

height_tmp/=2;

scale *=2;

}

// Decode with inSampleSize

BitmapFactory.Options o2=newBitmapFactory.Options();

o2.inSampleSize=scale;

FileInputStream stream2=newFileInputStream(f);

Bitmap bitmap=BitmapFactory.decodeStream(stream2,null,o2);

stream2.close();

returnbitmap;

}catch(FileNotFoundExceptione){

}catch(IOExceptione){

e.printStackTrace();

}

returnnull;

}

// Task for the queue

privateclassPhotoToLoad{

publicStringurl;

publicImageView imageView;

publicPhotoToLoad(Stringu,ImageViewi){

url=u;

imageView=i;

}

}

classPhotosLoaderimplementsRunnable{

PhotoToLoad photoToLoad;

PhotosLoader(PhotoToLoad photoToLoad){

this.photoToLoad=photoToLoad;

}

@Override

publicvoidrun(){

try{

if(imageViewReused(photoToLoad))

return;

Bitmap bmp=getBitmap(photoToLoad.url);

memoryCache.put(photoToLoad.url,bmp);

if(imageViewReused(photoToLoad))

return;

BitmapDisplayer bd=newBitmapDisplayer(bmp,photoToLoad);

handler.post(bd);

}catch(Throwable th){

th.printStackTrace();

}

}

}

booleanimageViewReused(PhotoToLoad photoToLoad){

Stringtag=imageViews.get(photoToLoad.imageView);

if(tag==null||!tag.equals(photoToLoad.url))

returntrue;

returnfalse;

}

// Used to display bitmap in the UI thread

classBitmapDisplayerimplementsRunnable{

Bitmap bitmap;

PhotoToLoad photoToLoad;

publicBitmapDisplayer(Bitmapb,PhotoToLoadp){

bitmap=b;

photoToLoad=p;

}

publicvoidrun(){

if(imageViewReused(photoToLoad))

return;

if(bitmap!=null)

photoToLoad.imageView.setImageBitmap(bitmap);

else

photoToLoad.imageView.setImageResource(stub_id);

}

}

publicvoidclearCache(){

memoryCache.clear();

fileCache.clear();

}

}

An imageloader is class that helps you download, display and cache images. By using an imageloader, images will be unloaded automatically if the device memory is low and it makes sure that the images are sized appropriately, and cached in the memory. Insert a temporary image for the imageloader to display when an image is unavailable or its still loading. For this tutorial, we have prepared a sample temporary image. Insert your downloaded sample image into your res > drawable-hdpi.

Temporary Image

Temp Img (1.3 KiB, 2350 downloads)

Next, create a memory cache class. Go to File > New > Class and name it MemoryCache.java. Select your package named com.androidbegin.jsouplistviewtutorial and click Finish.

Open your MemoryCache.javaand paste the following code.

MemoryCache.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

packagecom.androidbegin.jsouplistviewtutorial;

import java.util.Collections;

import java.util.Iterator;

import java.util.LinkedHashMap;

import java.util.Map;

import java.util.Map.Entry;

import android.graphics.Bitmap;

import android.util.Log;

publicclassMemoryCache{

privatestaticfinalStringTAG="MemoryCache";

// Last argument true for LRU ordering

privateMap<String,Bitmap>cache=Collections

.synchronizedMap(newLinkedHashMap<String,Bitmap>(10,1.5f,true));

// Current allocated size

privatelongsize=0;

// Max memory in bytes

privatelonglimit=1000000;

publicMemoryCache(){

// Use 25% of available heap size

setLimit(Runtime.getRuntime().maxMemory()/4);

}

publicvoidsetLimit(longnew_limit){

limit=new_limit;

Log.i(TAG,"MemoryCache will use up to "+limit/1024./1024.+"MB");

}

publicBitmap get(Stringid){

try{

if(!cache.containsKey(id))

returnnull;

returncache.get(id);

}catch(NullPointerException ex){

ex.printStackTrace();

returnnull;

}

}

publicvoidput(Stringid,Bitmap bitmap){

try{

if(cache.containsKey(id))

size-=getSizeInBytes(cache.get(id));

cache.put(id,bitmap);

size+=getSizeInBytes(bitmap);

checkSize();

}catch(Throwable th){

th.printStackTrace();

}

}

privatevoidcheckSize(){

Log.i(TAG,"cache size="+size+" length="+cache.size());

if(size>limit){

// Least recently accessed item will be the first one iterated

Iterator<Entry<String,Bitmap>>iter=cache.entrySet().iterator();

while(iter.hasNext()){

Entry<String,Bitmap>entry=iter.next();

size-=getSizeInBytes(entry.getValue());

iter.remove();

if(size<=limit)

break;

}

Log.i(TAG,"Clean cache. New size "+cache.size());

}

}

publicvoidclear(){

try{

cache.clear();

size=0;

}catch(NullPointerException ex){

ex.printStackTrace();

}

}

longgetSizeInBytes(Bitmap bitmap){

if(bitmap==null)

return0;

returnbitmap.getRowBytes()*bitmap.getHeight();

}

}

This memory cache class will limit the memory usage when loading images. Which means, the images will be removed if not shown within the content view.

Next, create a file cache class. Go to File > New > Class and name it FileCache.java. Select your package named com.androidbegin.jsouplistviewtutorial and click Finish.

Open your FileCache.javaand paste the following code.

FileCache.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

packagecom.androidbegin.jsouplistviewtutorial;

import java.io.File;

import android.content.Context;

publicclassFileCache{

privateFile cacheDir;

publicFileCache(Context context){

// Find the dir to save cached images

if(android.os.Environment.getExternalStorageState().equals(

android.os.Environment.MEDIA_MOUNTED))

cacheDir=newFile(

android.os.Environment.getExternalStorageDirectory(),

"JsonParseTutorialCache");

else

cacheDir=context.getCacheDir();

if(!cacheDir.exists())

cacheDir.mkdirs();

}

publicFile getFile(Stringurl){

Stringfilename=String.valueOf(url.hashCode());

// String filename = URLEncoder.encode(url);

Filef=newFile(cacheDir,filename);

returnf;

}

publicvoidclear(){

File[]files=cacheDir.listFiles();

if(files==null)

return;

for(Filef:files)

f.delete();

}

}

This file cache class saves temporary images into the device internal storage to prevent the images to be downloaded repeatedly.

Next, create an utility class. Go to File > New > Class and name it Utils.java. Select your package named com.androidbegin.jsouplistviewtutorial and click Finish.

Open your Utils.javaand paste the following code.

Utils.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

packagecom.androidbegin.jsouplistviewtutorial;

import java.io.InputStream;

import java.io.OutputStream;

publicclassUtils{

publicstaticvoidCopyStream(InputStream is,OutputStream os)

{

finalintbuffer_size=1024;

try

{

byte[]bytes=newbyte[buffer_size];

for(;;)

{

intcount=is.read(bytes,0,buffer_size);

if(count==-1)

break;

os.write(bytes,0,count);

}

}

catch(Exception ex){}

}

}

Next, create an activity to display results. Go to File > New > Class and name it SingleItemView.java. Select your package named com.androidbegin.jsouplistviewtutorial and click Finish.

Open your SingleItemView.javaand paste the following code.

SingleItemView.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

packagecom.androidbegin.jsouplistviewtutorial;

import android.app.Activity;

import android.content.Intent;

import android.os.Bundle;

import android.widget.ImageView;

import android.widget.TextView;

publicclassSingleItemViewextendsActivity{

// Declare Variables

Stringrank;

Stringcountry;

Stringpopulation;

Stringflag;

Stringposition;

ImageLoader imageLoader=newImageLoader(this);

@Override

publicvoidonCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

// Get the view from singleitemview.xml

setContentView(R.layout.singleitemview);

Intenti=getIntent();

// Get the result of rank

rank=i.getStringExtra("rank");

// Get the result of country

country=i.getStringExtra("country");

// Get the result of population

population=i.getStringExtra("population");

// Get the result of flag

flag=i.getStringExtra("flag");

// Locate the TextViews in singleitemview.xml

TextView txtrank=(TextView)findViewById(R.id.rank);

TextView txtcountry=(TextView)findViewById(R.id.country);

TextView txtpopulation=(TextView)findViewById(R.id.population);

// Locate the ImageView in singleitemview.xml

ImageView imgflag=(ImageView)findViewById(R.id.flag);

// Set results to the TextViews

txtrank.setText(rank);

txtcountry.setText(country);

txtpopulation.setText(population);

// Capture position and set results to the ImageView

// Passes flag images URL into ImageLoader.class

imageLoader.DisplayImage(flag,imgflag);

}

}

In this activity, strings are retrieved from the ListViewAdapter by using Intent and sets into the TextViews and an image URL into ImageLoader class to load images into the ImageView.

Next, change the application name and texts. Open your strings.xml in your res > values folder and paste the following code.

strings.xml

1

2

3

4

5

6

7

8

9

10

<?xml version="1.0"encoding="utf-8"?>

<resources>

<stringname="app_name">Jsoup ListView Tutorial</string>

<stringname="action_settings">Settings</string>

<stringname="hello_world">Hello world!</string>

<stringname="ranklabel">"Rank : "</string>

<stringname="countrylabel">"Country : "</string>

<stringname="populationlabel">"Population : "</string>

</resources>

In your AndroidManifest.xml, we need to declare permissions to allow the application to write an external storage and connect to the Internet. Open your AndroidManifest.xml and paste the following code.