Are you over 18 and want to see adult content?
More Annotations
A complete backup of 4deprimariaip.blogspot.com
Are you over 18 and want to see adult content?
A complete backup of renewalsa.sa.gov.au
Are you over 18 and want to see adult content?
A complete backup of precisionraceworks.com
Are you over 18 and want to see adult content?
A complete backup of photoshop-bootcamp.com
Are you over 18 and want to see adult content?
A complete backup of newyorkmonamour.fr
Are you over 18 and want to see adult content?
A complete backup of goodlivingandmore.com
Are you over 18 and want to see adult content?
A complete backup of currencyrate.today
Are you over 18 and want to see adult content?
Favourite Annotations
A complete backup of lifestylebyps.com
Are you over 18 and want to see adult content?
A complete backup of echineselearning.com
Are you over 18 and want to see adult content?
A complete backup of saltasultreno.wordpress.com
Are you over 18 and want to see adult content?
A complete backup of inventandohistoria.com
Are you over 18 and want to see adult content?
A complete backup of igrice-tigrice.com
Are you over 18 and want to see adult content?
Text
Skip to content
THINK ANDROID
EXAMPLES, CODE, AND TUTORIALS // JWEI* Home
* Links
* Requests
* Android Database Programming: FAQ* About
WELCOME!
Search the categories on the right for examples. If you can\'t find what you need, then leave a comment on the Requestspage!
Happy coding everyone. New Add me on Twitter to get tweets on Think Android\'s latest posts! CONGRATS TO PACKT PUBLISHING! 1000 TITLES AND COUNTING!September 27, 2012
tags: android , ebook, packt
Hey everyone,
Just got an email from Packt Publishing with the exciting news that they’ve published their 1000th title! Pretty impressive no? Any ways, to celebrate: ————————————————————————————————————————————————————-Dear Customer,
Packt Publishing has come a long way since it published its first book in 2004, and is now one of the leading technical publishers, renowned among developers for its focused and practical books on a wide range of tools and technologies. Packt has just published its 1000th book. YOU ARE INVITED TO JOIN US IN CELEBRATING THIS MILESTONE WITH A GIFT. ACCESS OUR LIBRARY, PACKTLIB, FOR FREE FOR A WEEK, AND CHOOSE ANY OF OUR EBOOKS TODOWNLOAD AND KEEP.
To make use of this offer, you simply need to go to www.packtpub.com and log into your account, or register for an account, between the 28th and 30th September. At Packt, we really appreciate your support in helping us get this far, and hope that you will continue to enjoy our range of books.Kind regards,
Packt Publishing
————————————————————————————————————————————————————- So yes – check out the resources they have and go get your free e-book! I’m definitely going to redeem mine =) And PS, for those who don’t know, I happened to publish my book with Packt so if you’re interested feel free to download my e-book at Android Database Programming . Happy coding as usual!– jwei
Advertisements
Report this ad
Advertisements
Report this ad
Leave a comment
from → News and Announcements PASSING OBJECTS IN INTENTS: PARCELABLES AND MORESeptember 25, 2012
tags: android ,
bundles , intents
, parcels
, tutorials
Hey everyone,
For this post, I thought I’d revisit the topic of Intents. In the past I’ve talked about passing Intents in between classes with simple, primitive data (see Passing Information between Activities ) – turns out it’s a relatively easy task, and a core concept within the Android framework. However, the much harder task is passing your own classes (objects) in between Activities, and moreover, potentially passing _lists_ of objects. In this post, I’ll go through an example of writing an object that implements the Parcelableinterface.
Consider a scenario where you have a list of VENUES (i.e. Restaurants, Hotels, Clubs, anything with fields for lat, long, name, address, etc). Your user makes a request and gets back a list of these Venues. You then want to pass these results to a new Activity – maybe it’s a mapping Activity (as it was in my case), but regardless the goal is to pass this list of Venues from Activity A to Activity B without having to make the same request twice. The first step is defining your object. The object must implement the Parcelable interface. Why you might ask? Well let’s step back and think about what’s happening here. Within Android, much of the inter-process (inter-Activity) communication is done through light weight data structures known as PARCELS. In fact, both Intents and Bundles (two objects you’ve probably encountered before…) implement this Parcelable interface. But how does this inter-process communication work? An Android process first converts an object into a byte stream which is then sent to another process (i.e. another Activity). This second process then reads in the byte stream and converts it back into an object: this exchange is more commonly known as _serialization_ or _marshalling_. But how do the two Activities know what to do to serialize and de-serialize your object? For primitives like ints, doubles, even Strings, serialization is trivial as these primitives are already in byte form. And so this is where the Parcelable interface comes in. By implementing the Parcelable interface, you are essentially giving the OS instructions on how to serialize and de-serialize your object. Conceptually this may be difficult to picture, but luckily Android has made the code for this super simply – in fact you are only required to override a few methods. With that, let’s take a look at what exactly needs to be done in the implementation: public class ParcelableVenue implements Parcelable { private double lat, lon; private String name, address; public ParcelableVenue(double lat, double lon, String name, String address) {this.lat = lat;
this.lon = lon;
this.name = name;
this.address = address;}
public ParcelableVenue(Parcel source) {// TODO implement
}
public GeoPoint getGeoPoint() { return new GeoPoint((int) (lat * 1e6), (int) (lon * 1e6));}
public String getName() {return name;
}
public String getAddress() {return address;
}
@Override
public int describeContents() { // OVERRIDE METHOD #1return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) { // OVERRIDE METHOD #2 dest.writeDouble(this.lat); dest.writeDouble(this.lon); dest.writeString(this.name); dest.writeString(this.address);}
public static final Parcelable.Creator// TODO implement
};
}
So far we have the basic structure of our ParcelableVenue object – it has a few simple fields as well as some standard getters; nothing special there. You’ll then notice that there are two methods we need to override. The first is the _describeContents()_ method. Typically returning 0 suffices unless you have numerous parcelable objects and require special serialization for some. The method itself is meant to return a bit mask that identifies the serialized object. In my case, Ijust return 0.
The second method is the _writeToParcel(Parcel dest, int flags)_ method. The meat of the conversion happens here. In this method you are passed a destination Parcel which is eventually serialized and sent to the end process. Thus you simply need to write your object’s data into this parcel. Luckily, some simple write methods are given to you, such as writeDouble(), writeString(), writeInt(), writeIntArray(), etc. The flags parameter simply tells the writeToParcel() method how the object should be written. Once these two methods are overridden, every class that implements the Parcelable interface then needs to have a static Parcelable.Creator object named _CREATOR_. Let’s step back one more time – where are we at this point? Well so far we’ve flattened the object and written it to a Parcel object. Our object is in essence nothing but a byte stream now, so the only thing that’s left to do is un-flatten it and convert it back into an object using this CREATOR object! Our creator object is pretty simple and need only look like: public class ParcelableVenue implements Parcelable { private double lat, lon; private String name, address; public ParcelableVenue(double lat, double lon, String name, String address) {this.lat = lat;
this.lon = lon;
this.name = name;
this.address = address;}
public ParcelableVenue(Parcel source) {// TODO implement
}
// ...
@Override
public void writeToParcel(Parcel dest, int flags) { dest.writeDouble(this.lat); dest.writeDouble(this.lon); dest.writeString(this.name); dest.writeString(this.address);}
public static final Parcelable.Creator@Override
public ParcelableVenue createFromParcel(Parcel source) { return new ParcelableVenue(source); // RECREATE VENUE GIVEN SOURCE}
@Override
public ParcelableVenue newArray(int size) { return new ParcelableVenue; // CREATING AN ARRAY OF VENUES}
};
}
And so we see that the very last step is simply to write another constructor for our ParcelableVenue class which initializes an object given a Parcel. This can be done with: public class ParcelableVenue implements Parcelable { private double lat, lon; private String name, address;// ...
public ParcelableVenue(Parcel source) { this.lat = source.readDouble(); this.lon = source.readDouble(); this.name = source.readString(); this.address = source.readString();}
// ...
}
THE ORDER HERE IS IMPORTANT – the first double read will be the first double written as, again, it is a byte stream. And that’s it! Once we have our ParcelableVenue, we can then dothings like:
public class ClubsListActivity extends ListActivity { private List@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.club_list); mapViewButton = (Button) findViewById(R.id.switch_map_view); mapViewButton.setOnClickListener(new OnClickListener() {@Override
public void onClick(View v) { // PREPARE NEW INTENT TO SEND TO MAP ACTIVITY Intent i = new Intent(ClubsListActivity.this, VenueMapView.class); // INITIALIZE NEW ARRAYLIST AND POPULATE ArrayList}
// EMBED INTO INTENT i.putParcelableArrayListExtra("venues", overlays);startActivity(i);
}
});
SharedPreferences sp = getSharedPreferences(Constants.DB, Context.MODE_PRIVATE); double lat = (double) sp.getFloat(Constants.SP_PREV_LAT, (float) Constants.DEFAULT_LAT); double lon = (double) sp.getFloat(Constants.SP_PREV_LON, (float) Constants.DEFAULT_LON); // GET CLUBS NEAR YOU WITH LAT LON}
}
The receiving side then looks like: public class VenueMapView extends MapActivity { private MapView map; private List@Override
protected void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.mapview); SharedPreferences sp = getSharedPreferences(Constants.DB, Context.MODE_PRIVATE); double lat = (double) sp.getFloat(Constants.SP_PREV_LAT, (float) Constants.DEFAULT_LAT); double lon = (double) sp.getFloat(Constants.SP_PREV_LON, (float) Constants.DEFAULT_LON); map = (MapView) findViewById(R.id.venue_map); // INIT MAP map.setBuiltInZoomControls(true); // SET MAP CONFIGURATIONS map.getController().setCenter(new GeoPoint((int) (lat * 1e6), (int) (lon * 1e6))); int maxZoom = map.getMaxZoomLevel(); map.getController().setZoom(maxZoom - 3); Intent i = getIntent(); // RETRIEVE OUR INTENT venues = i.getParcelableArrayListExtra("venues"); // GET PARCELABLE VENUES Listpoints.add(o);
}
vo.addOverlayList(points); // ADD VENUE OVERLAYS TO MAP mapOverlays.add(vo);}
}
I won’t say too much about what I’m doing with my Maps Activity – maybe I’ll save this for a future tutorial. The important thing to see is how I send a list of ParcelableVenue objects, and then retrieve them on the other side. As you can probably see by now, there’s nothing hard code wise when implementing a Parcelable object. The difficulty typically stems from an incomplete understanding of how Android sends data from process to process – and this is understandable as almost all of this is abstracted away so that we only need to put simple values into Bundles and Parcels and voila things magically appear on the other side. But once you dig a little more into what’s happening behind the scenes, then all of this serialization and Parcelable implementation makes much moresense.
And with that I send you off again! Happy coding and hope this helped.– jwei
1 Comment
from → Android Examples,
Intents
PARSING JSON ON ANDROIDSeptember 10, 2012
tags: android , data, JSON
, parsing
, XML
Hey everyone,
Now a days when people talk about transferring data through HTTP requests, two popular data formats come to mind: JSON and XML. In earlier posts, I’ve written a little about XML (see),
but in this post I’m going to use another friendly library to show you guys a simple, efficient way to parse JSON. I’ll also talk a little about the merits of each data format, but the hope is by the end of this short post, you’ll have what you need to parse both XMLand JSON.
The “library” I’m going to take advantage of is the JSON-Java library. It’s a really nice, self-contained library, which allows you to easily parse JSON. More recently, the library has even included methods that allow you to convert XML to JSON and vice versa – allowing you to better reuse your data parsers. Anyways, before reading this post, go ahead and download the library and add the source to your project. For me, I just add a new package (i.e. jwei.apps.json) and put the files inthere.
Once you have that, the rest is quite simple. Recently I worked on a project where I had to make an HTTP request to get a list of clubs in NY. Each Club was simply an object that contained fields like name, address, lat/long, phone number, etc. The JSON structure of the HTTP response looked like: To see for yourself, feel free to hit this URL: http://djs-corner.appspot.com/getClosestClubs?lat=40.7600624&lon=-73.98558 Then, subsequently my JSON club parser looked like: import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import jwei.apps.helpers.ConnectionManager; import jwei.apps.json.JSONArray; import jwei.apps.json.JSONObject; import jwei.apps.types.Club; import jwei.apps.types.Constants; public class JsonParser { private static DefaultHttpClient httpClient = ConnectionManager.getClient(); public static Listtry {
response = httpClient.execute(getMethod); // CONVERT RESPONSE TO STRING String result = EntityUtils.toString(response.getEntity()); // CONVERT RESPONSE STRING TO JSON ARRAY JSONArray ja = new JSONArray(result); // ITERATE THROUGH AND RETRIEVE CLUB FIELDS int n = ja.length(); for (int i = 0; i < n; i++) { // GET INDIVIDUAL JSON OBJECT FROM JSON ARRAY JSONObject jo = ja.getJSONObject(i); // RETRIEVE EACH JSON OBJECT'S FIELDS long id = jo.getLong("id"); String name = jo.getString("name"); String address = jo.getString("address"); String country = jo.getString("country"); String zip = jo.getString("zip"); double clat = jo.getDouble("lat"); double clon = jo.getDouble("lon"); String url = jo.getString("url"); String number = jo.getString("number"); // CONVERT DATA FIELDS TO CLUB OBJECT Club c = new Club(id, name, address, country, zip, clat, clon, url, number);ret.add(c);
}
} catch (Exception e) { e.printStackTrace();}
// RETURN LIST OF CLUBSreturn ret;
}
}
Again, it’s relatively straight forward, but the methods I’ll make special note of are: JSONArray ja = new JSONArray(result); JSONObject jo = ja.getJSONObject(i); long id = jo.getLong("id"); String name = jo.getString("name"); double clat = jo.getDouble("lat"); In the first method, we pass in a String which has JSON format. The constructor of JSONArray expects a String that has valid JSON array formatting and parses it accordingly – throwing a _JSONException_ otherwise. Once we have our JSON array, it works similarly to a vector (ArrayList) and we can pass it an index and retrieve a single JSONObject. For each JSONObject, we can then retrieve various fields by type (i.e. _getLong, getDouble, getString_, etc). Pretty simple no? As mentioned before, to allow for better re-usability of data parsers, the writers of JSON-Java extended the library’s functionality to include XML conversion, which is simply: String xml = ""; // YOUR XML STRING JSONObject jo = XML.toJSONObject(xml); String name = jo.getString("name");...
Thus, if we wanted to ensure maximum compatibility, we could have extended our parser to look like: public class JsonParser { private static DefaultHttpClient httpClient = ConnectionManager.getClient(); public static Listtry {
response = httpClient.execute(getMethod); // CONVERT RESPONSE TO STRING String result = EntityUtils.toString(response.getEntity()); // CONVERT RESPONSE STRING TO JSON ARRAYJSONArray ja;
if(format.equalsIgnoreCase("xml")) { JSONObject xjo = XML.toJSONObject(result); ja = xjo.getJSONArray("clubs"); } else if (format.equalsIgnoreCase("json")) { ja = new JSONArray(result);}
// ITERATE THROUGH AND RETRIEVE CLUB FIELDS...
} catch (Exception e) { e.printStackTrace();}
// RETURN LIST OF CLUBSreturn ret;
}
}
And voila!
Now, as for a brief discussion on JSON vs. XML, I’ll note threepoints:
1) PERFORMANCE – in terms of performance, JSON is the better option. This is true for both the actual transferring of your data, and also for the parsing of the data. This is due to the lower overhead needed for JSON formatting, which doesn’t require the rigid tree/nodestructure of XML.
2) READABILITY – this is a more subjective point and I’ve seen arguments for both sides. I personally think XML is the cleaner format for reading, but most browsers now a days (i.e. Chrome, Firefox) have JSON and XML display built in and both are nicely laid out. However, I will mention that for more “complex” data structures, XML tends to display it in a more intuitive fashion, which leads me to my thirdpoint.
3) COMPLEXITY – while JSON is designed for quick and lean data structures, XML is built to handle data structures of varying complexity and depth. Consider a data structure that has fields which are several layers deep (i.e. a University object which has a list of Class objects which each have a list of Student objects which each have a list of …). When this is the case, it can quickly become a parsing headache when you’re wading through JSONArray after JSONArray trying to access the correct JSONObject. Here, having an XML parser, especially one that is equipped with tree traversing languages like XPATH, can be an extremely powerful tool for pinpointing the precise nodes you want. And so I’ll end the post with that. Hope this was comprehensive andhelpful!
As always – happy coding.– jwei
9 Comments
from → Android Examples, Web
Examples
GRANTING CONTENT PROVIDER URI PERMISSIONSAugust 7, 2012
tags: android ,
content providers
, database
, example
, intents
Hey everyone,
The goal of this short example is to show you how you can further protect your application’s data by enforcing permissions upon your custom content provider. For those who have never seen a custom content provider implementation, I invite you to check out my post Writing Your own Content Providerbefore reading on.
The purpose of giving your content provider the ability to grant access to its data should be pretty clear. Suppose you want to protect the integrity of your content provider’s data. Then, for some users/applications you may want to give them both read and write permissions, while for others you may only want to give them read permission. A simple example of this is attachments in a mailapplication :
> Access to the mail should be protected by permissions, since this is > sensitive user data. However, if a URI to an image attachment is > given to an image viewer, that image viewer will not have permission > to open the attachment since it has no reason to hold a permission > to access all e-mail. These permissions are for a specific content URI, and will last until the Activity that receives them is finished. In other words, when an application grants read and/or write permissions to another Activity, these permissions are _temporary_. Before moving on to some code, let me note that this implementation is _different_ than declaring the android:readPermission and android:writePermission attributes as these tags specify specific applications and give those applications permanent read/write access. In this way, the method below which uses the android:grantUriPermissions tag a.k.a the sub-tag grant-uri-permission is much more dynamic and flexible. So let’s see how all this is done. Adding permission requirements to your content provider is actually quite simple. Let’s extend my Notes ContentProvider from the above example and give it the ability to grant URI permissions. Say you want to give the user the ability to share his/her notes through various mail/social-media applications, but you want to protect the content of the note. Then, you’ll want to add the following to your AndroidManifest.xml file:URIs with pattern:
_“jason.wei.apps.notes.providers.NotesContentProvider/notes/{id}”_ can grant URI permissions (for those struggling with the concept of URIs, just think of this as giving your entire hard drive some desired property, versus only giving one directory in your hard drive that same property). Finally, as for how you actually go about granting such permissions through Intents, the below shows it done in a genericActivity:
public class NoteUriGrantActivity extends Activity { public static final String NOTE_ACTION_VIEW = "jason.wei.custom.intent.action.NOTE_VIEW";@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);// ... code ...
// IMPLICIT INTENT EXAMPLE Uri uri = Uri.parse("content://jason.wei.apps.notes.providers.NotesContentProvider/notes/1"); Intent intent = new Intent(); intent.setAction(NOTE_ACTION_VIEW); // SET CUSTOM INTENT ACTION intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // GRANT TEMPORARY READ PERMISSION intent.setData(uri); startActivity(intent); // SEND INTENT TO BE RESOLVED // EXPLICIT INTENT EXAMPLE grantUriPermission("jason.wei.apps.NotesReader", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);}
}
And with that, in order to resolve our custom Intent, we simply need to write a separate Activity (note this Activity need not be defined within the same application as the ContentProvider) with correctly specified intent filter:– jwei
2 Comments
from → Android Examples,
ContentProvider Tutorials,
Intents
BOOK: ANDROID DATABASE PROGRAMMINGJune 19, 2012
tags: android , book, database
, SQL
, SQLite
Hey everyone!
First off – I just wanted to thank you all for making this blog what it is. It’s been great getting your feedback through comments and emails, and I hope this blog has helped you guys in your development ambitions as much as it has helped me! I’m pleased to announce the publication of my first book, ANDROID DATABASE PROGRAMMING. It was actually through this blog that publishing company Packt contacted me and asked me to write on the topic. As for what the book covers, I’ll briefly summarize here: * Learn about lighter forms of local data storage such asSharedPreferences
* Dive into SQLite databases and learn how to customize and extendthem
* Examine various SQLite queries to efficiently query for your data * Learn to safely expose your SQLite database to externalapplications
* Understand how to bind your SQLite database to the user interface * Explore various external databases such as Google App Engine and learn how to store/query data on these external platforms * Learn to make network requests to both post and get data from yourexternal data store
* Learn to retrieve, parse, and/or cache the incoming web data on the Android application It’s currently available for purchase in both print and eBook/Kindle, and can be purchased through the publisher’s website as well as through Amazon.
A sample copy of Chapter 2 is also available for free. Hope you guys like it and thanks again for all the support. As always,happy coding.
– jwei
5 Comments
from → Android Examples,
Android Tutorials
,
Google App Engine Series LAZY LOADING IMAGES: FROM URLS TO LISTVIEWSJune 13, 2012
tags: asynctask ,
images , lazy loading, listview
, parallelize
Hey everyone!
Recently while working on a project I was asked to lazy load a list of images (bitmaps) into a ListView. What made the task even trickier was the fact that each image had to be streamed from a given URL. I thought about downloading all of the images at the application’s startup Activity, and then dumping them into some kind of external SD card as a cache, but I was told that the images were subject to frequent change and that true caching would be difficult. The result is how I chose to implement the feature, and I thought I’d share itwith everyone.
Now there’s no guarantee that the way I’m doing this is the “correct” or optimal way – in fact if you DO know the best way to lazy load images from URLs then please share – but the solution below works and uses a handful of Android classes and concepts, all of which I’ll note as I walk you through the solution. Before I move onto the code, let’s _conceptually_ think about how we’re going to make this feature work. In this example, let’s say we’re making an HTTP request to some external server that returns a list of Students. Each Student has a name and an image URL which is to be streamed, converted into a Bitmap, and then displayed in a ListView. Getting the list of Student objects is the easy part – but what’s the next step? One option is to loop through each Student, grab each Student’s image URL, convert the URL into a Bitmap,
and then allow each Student to hold a reference to their Bitmap; at which point we can load the list like we normally would. A very feasible solution – but depending on the size of your Student list. Let’s assume that each image takes between 0.5 to 1 seconds to load. Now, if your database only has 5-10 Students in it, then maybe this iterative solution may work. However, consider a database with 100s of Students – clearly this iterative solution won’t hold up in that case. What’s the better solution? Wouldn’t it be nice if we could _parallelize_ the loading process? That’s STEP ONE – thinking of a way to parallelize the process. STEP TWO is to do all this loading and processing on separate background threads. This way the user can interact with the application, even while the images are loading. The last step, STEP THREE, is to make sure that each background thread can somehow communicate with the original ListAdapter and make sure that the list gets updated each time an image is successfully streamed. With that, here’s the code. First, let’s start with a basic Student object. Each Student has a picture that needs to be loaded, and each student holds a reference to both their image’s URL as well as their Bitmap (to be downloaded): public class Student { private String name; private String imgUrl; private Bitmap image; private StudentAdapter sta; public Student(String name, String imgUrl) {this.name = name;
this.imgUrl = imgUrl; // TO BE LOADED LATER - OR CAN SET TO A DEFAULT IMAGE this.image = null;}
public String getName() {return name;
}
public void setName(String name) {this.name = name;
}
public String getImgUrl() {return imgUrl;
}
public void setImgUrl(String imgUrl) { this.imgUrl = imgUrl;}
public Bitmap getImage() {return image;
}
public StudentAdapter getAdapter() {return sta;
}
public void setAdapter(StudentAdapter sta) {this.sta = sta;
}
public void loadImage(StudentAdapter sta) { // HOLD A REFERENCE TO THE ADAPTERthis.sta = sta;
if (imgUrl != null && !imgUrl.equals("")) { new ImageLoadTask().execute(imgUrl);}
}
// ASYNC TASK TO AVOID CHOKING UP UI THREAD private class ImageLoadTask extends AsyncTask@Override
protected void onPreExecute() { Log.i("ImageLoadTask", "Loading image...");}
// param is img url protected Bitmap doInBackground(String... param) { Log.i("ImageLoadTask", "Attempting to load image URL: " + param);try {
Bitmap b = ImageService.getBitmapFromURLWithScale(param);return b;
} catch (Exception e) { e.printStackTrace();return null;
}
}
protected void onProgressUpdate(String... progress) {// NO OP
}
protected void onPostExecute(Bitmap ret) { if (ret != null) { Log.i("ImageLoadTask", "Successfully loaded " + name + " image");image = ret;
if (sta != null) { // WHEN IMAGE IS LOADED NOTIFY THE ADAPTER sta.notifyDataSetChanged();}
} else {
Log.e("ImageLoadTask", "Failed to load " + name + " image");}
}
}
}
Alright so what’s going on here? Again, the Student object we have here is very simple – it has only a name, image URL, and Bitmap image associated with it. For now, the image will be null (or a default image can be used) but we choose to hold a reference to it so that once it is loaded, we can “cache” it and only have to load itonce.
Then, let’s note two things. First, we see that each Student has a _loadImage()_ method which initiates an AsyncTask that we created called _ImageLoadTask_. By containing the loading process within the Student object, we’ve found a natural way to address step one and parallelize the process. Now, each Student can INDEPENDENTLY kick off their image loading processes and INDEPENDENTLY handle the resulting Bitmap. Why do we use an AsyncTask? Well that’s to address step two above and make sure that each process is loaded in a background thread. By doing this, we guarantee that each Student manages their own image Bitmap, and without disturbing the main UI thread! Furthermore, we see that each Student object holds a reference to a StudentAdapter, whose code will be shown next. This is our solution to step three from above. By holding a reference to the Adapter, we can make sure that once the Student’s image is loaded (through the ImageLoadTask), the Student can then tell the adapter to update itself using the Adapter’s _notifyDataSetChanged()_ method. Let’s take a quick look at how the StudentAdapter is defined: public class StudentAdapter extends BaseAdapter { private LayoutInflater mInflater; private List items = new ArrayList(); public StudentAdapter(Context context, List items) { mInflater = LayoutInflater.from(context); this.items = items;}
public int getCount() { return items.size();}
public Student getItem(int position) { return items.get(position);}
public long getItemId(int position) {return position;
}
public View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;
Student s = items.get(position); if (convertView == null) { convertView = mInflater.inflate(R.layout.row_layout, null); holder = new ViewHolder(); holder.name = (TextView) convertView.findViewById(R.id.name); holder.image = (ImageView) convertView.findViewById(R.id.image); convertView.setTag(holder);} else {
holder = (ViewHolder) convertView.getTag();}
holder.name.setText(s.getName()); if (s.getImage() != null) { holder.pic.setImageBitmap(s.getImage());} else {
// MY DEFAULT IMAGE holder.pic.setImageResource(R.drawable.generic_profile_man);}
return convertView;}
static class ViewHolder {TextView name;
ImageView pic;
}
}
Pretty simple really and nothing much to say. Really you just have to note that in the getView() method, if the Student’s image is null (implying that the Student’s image hasn’t been loaded yet) then I set the image to be a default generic profile picture. And so let’s bring this all together by looking at how we’d set this up in anActivity class:
public class StudentListActivity extends ListActivity { private List students; private StudentAdapter sta;@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.list); // GET YOUR STUDENTSstudents = //...
// CREATE BASE ADAPTER sta = new StudentAdapter(StudentListActivity.this, students); // SET AS CURRENT LIST setListAdapter(sta); for (Student s : students) { // START LOADING IMAGES FOR EACH STUDENTs.loadImage(sta);
}
}
}
And voila! That’s it! We look through our list of Students, and for each Student we call their loadImage() method, making sure we pass in the instantiated ListAdapter. Then, each _loadImage()_ method will kick off an AsyncTask that will stream the image, cache it as a Bitmap, and then notify the ListAdapter to update itself. How this is going to look at the end will be a list that the user can scroll through, where each row is loading itself behind the scenes, and displaying its image as soon as the loading is done. Hopefully this all makes sense – and again happy to hear other solutions as well! Best of luck and as usual, happy coding.– jwei
33 Comments
from → Android Examples,
CursorAdapter Tutorials,
Web Examples
,
Working with Images
2011 IN REVIEW
December 31, 2011
The WordPress.com stats helper monkeys prepared a 2011 annual reportfor this blog.
Here’s an excerpt: > London Olympic Stadium holds 80,000 people. This blog was viewed > about 530,000 times in 2011. If it were competing at London Olympic > Stadium, it would take about 7 sold-out events for that many people> to see it.
Click here to see the complete report.1 Comment
from → UncategorizedOlder Entries
*
CHECKOUT MY NEW BOOK! Android Database Programming*
SUBSCRIBE TO THINK ANDROID Enter your email address to subscribe to this blog and receive the latest examples, code snippets, and tutorials from Think Android. Join 987 other followersLet's Think Android
*
SEARCH FOR EXAMPLES
*
CATEGORIES
* Android Examples
* Activity and Layout Examples * Android 1.6 Examples * Android 2.0 Examples* Intents
* Misc Examples
* Web Examples
* Working with Images* Android Tutorials
* ContentProvider Tutorials * CursorAdapter Tutorials* Layout Tutorials
* Media Tutorial
* Receiver Tutorial
* Google App Engine Series * News and Announcements* Uncategorized
*
TOP POSTS
* How to Position Views Properly in Layouts * Handling Screen OFF and Screen ON Intents * Converting Image URL to Bitmap*
WHAT I’M THINKING
* Check out my new post on JSON parsing! wp.me/pKB6B-58#android
#json
7 years ago
* Just published a book! "Android Database Programming" link.packtpub.com/Cs4hK9 Check it out! #android #androiddev7 years ago
* New Post! Lazy Loading Images: From URLs to ListViews wp.me/pKB6B-4p #android#androiddev
7 years ago
* Some final thoughts on my GAE series - wp.me/pKB6B-4d#Android
7 years ago
* My 40th Tutorial and the last of my GAE series - wp.me/pKB6B-45- enjoy! #Android
7 years ago
*
DEL.ICIO.US
Report this ad
Details
Copyright © 2024 ArchiveBay.com. All rights reserved. Terms of Use | Privacy Policy | DMCA | 2021 | Feedback | Advertising | RSS 2.0