If you need to contact me for any reason, just add a comment to this post. Please include contact information if you need me to get back to you. I will not post any personal information to this thread.
Tuesday, 31 July 2012
Monday, 30 July 2012
Introducing Google Fiber: The Next Chapter of the Internet
Google Fiber starts with Internet speeds 100 times faster than what most Americans have today. In this video, we see the evolution of the Internet represented in three different stages. It started with Dial-Up, grew with Broadband -- and with Google Fiber, the possibilities are endless. Pre-register now at http://www.google.com/fiber
About the Video:
The cars and model installation were built by hand, and filmed at Agua Dolce airport in Santa Clarita, CA. The installation now resides in the Fiber Space in Kansas City. For more info about the Fiber Space, please visit http://google.com/fiber/fiberspace
JQuery Accordion Style vi Cheat Sheet
Over the weekend I was able to complete an accordion style
If I can find the time, I'll try to make a offline version of the cheat sheet using HTML5.
vi
cheat sheet using JQuery on the Tools section of my web site. It is based on a really good cheat sheet that is linked at the bottom of my page. I just added some style changes, reordered it and made it expand or collapse sections.If I can find the time, I'll try to make a offline version of the cheat sheet using HTML5.
Introduction to Android App Development for the Kindle Fire
Get Started Fast with Android App Development for Amazon�s Best-Selling Kindle Fire!
Practically overnight, the Amazon Kindle Fire has become the world�s top-selling Android-based tablet. Now, in this electronic-only mini-book, expert Android developers provide an introduction to the basics of Kindle Fire development.
Lauren Darcey and Shane Conder first introduce you to Android and walk you through installing its latest development tools. Next, you�ll learn the essential design principles you need to write Android Kindle Fire apps, discover how Android applications are structured and configured, and walk through incorporating user interfaces and other application resources into your projects.
It�s simply the fastest way to start developing apps for today�s hottest Android tablet!
Get Current Stories/News with DuckDuckGo
One thing that is not obvious with the DuckDuckGo search engine is how do I get a list of new links on a subject? It is pretty easy. Just add the following to text to the end of your query:
For example to search for the latest JQuery stories I could submit:
sort:date
For example to search for the latest JQuery stories I could submit:
jquery sort:date
.
Apply LruCache on GridView
The example "Caching Bitmaps with LruCache" provide a example to Apply LruCache on Gallery. This exercise is GridView version using LruCache.
Reference: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache
To using android.util.LruCache in the code, targetSdkVersion of "13" is needed to be specified in AndroidManifest.xml.
The layout file, refer to the post "GridView loading photos from SD Card".
Download the files.
Reference: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache
To using android.util.LruCache in the code, targetSdkVersion of "13" is needed to be specified in AndroidManifest.xml.
The layout file, refer to the post "GridView loading photos from SD Card".
package com.example.androidgridview;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
public class ImageAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> itemList = new ArrayList<String>();
public ImageAdapter(Context c) {
mContext = c;
}
void add(String path){
itemList.add(path);
}
@Override
public int getCount() {
return itemList.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
//Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220);
// Use the path as the key to LruCache
final String imageKey = itemList.get(position);
final Bitmap bm = getBitmapFromMemCache(imageKey);
if (bm == null){
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(imageKey);
};
imageView.setImageBitmap(bm);
return imageView;
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = decodeSampledBitmapFromUri(params[0], 200, 200);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
ImageAdapter myImageAdapter;
private LruCache<String, Bitmap> mMemoryCache;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = (GridView) findViewById(R.id.gridview);
myImageAdapter = new ImageAdapter(this);
gridview.setAdapter(myImageAdapter);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myImageAdapter.add(file.getAbsolutePath());
}
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass
= ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE))
.getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return (Bitmap) mMemoryCache.get(key);
}
}
Download the files.
Sunday, 29 July 2012
Factory images of Jelly Bean for Galaxy Nexus and Nexus S released
Factory Images for Nexus Devices updated with Factory images of Jelly Bean for Galaxy Nexus and Nexus S.
You will find these files useful if you have used the Android Open-Source Project, flashed custom builds on your device, and wish to return that device to its factory state.
You will find these files useful if you have used the Android Open-Source Project, flashed custom builds on your device, and wish to return that device to its factory state.
Gallery-like single column GridView
by changing android:numColumns="1", the last exercise of "GridView" can be modified to a Gallery-like single column GridView.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<GridView
android:id="@+id/gridview"
android:layout_width="130dp"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="1"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="@android:color/background_dark"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/background_light">
</LinearLayout>
</LinearLayout>
GridView loading photos from SD Card
Previous exercises described how to implement "Gallery-like HorizontalScrollView" and "Vertical Gallery-like ScrollView". Alternatively, it can be displayed in GridView.
Add a <GridView> in layout.
Main code:
Download the files.
Next:
- Gallery-like single column GridView
- Retrieve old activity state for configuration change by overriding onRetainNonConfigurationInstance() method
Add a <GridView> in layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
</LinearLayout>
Main code:
package com.example.androidgridview;
import java.io.File;
import java.util.ArrayList;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends Activity {
public class ImageAdapter extends BaseAdapter {
private Context mContext;
ArrayList<String> itemList = new ArrayList<String>();
public ImageAdapter(Context c) {
mContext = c;
}
void add(String path){
itemList.add(path);
}
@Override
public int getCount() {
return itemList.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
Bitmap bm = decodeSampledBitmapFromUri(itemList.get(position), 220, 220);
imageView.setImageBitmap(bm);
return imageView;
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
ImageAdapter myImageAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = (GridView) findViewById(R.id.gridview);
myImageAdapter = new ImageAdapter(this);
gridview.setAdapter(myImageAdapter);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myImageAdapter.add(file.getAbsolutePath());
}
}
}
Download the files.
Next:
- Gallery-like single column GridView
- Retrieve old activity state for configuration change by overriding onRetainNonConfigurationInstance() method
Wednesday, 25 July 2012
Multiple $(document).ready(function() with JQuery
Did you know you can call JQuery's
I have playing with templating systems for both Abbey Workshop and Blue Sky Workshop. With those systems, I typically have some JQuery code in the header of the template. Consequently, that code is on every page. But what if you want to add some more JavaScript that does something completely different? Well no problem, just add to the content to the page and add a <script> tag wherever you want it. Pretty cool!
$(document).ready(function()
multiple times? Well yes, you can according to the documentation.I have playing with templating systems for both Abbey Workshop and Blue Sky Workshop. With those systems, I typically have some JQuery code in the header of the template. Consequently, that code is on every page. But what if you want to add some more JavaScript that does something completely different? Well no problem, just add to the content to the page and add a <script> tag wherever you want it. Pretty cool!
Mac OS X Mountain Lion (10.8) is out
It's here! Mac OS X Mountain Lion is available on the Mac App Store. CNET has a review.A lot more iOS and iCloud integration. So apps like iMessage and Reminder will also be on your desktop, making them a lot more useful.
As always, I will be waiting for the first major patch before I start installing it.
Sea Change for Big Networks?
VMWare's $1B purchase of Nicira Networks was big news. Why? That was my question. Remember that new OpenFlow technology for managing large networks? Well Nicira is one of the first companies to build a product based on OpenFlow. This technology is aimed directly at Cisco and Juniper networks. One of the original investors explains.
Now if the big guys are smart, they will quickly embrace this technology and come out with their own products and thusly crush their smaller competitors. It will be interesting to see if that happens.
Now if the big guys are smart, they will quickly embrace this technology and come out with their own products and thusly crush their smaller competitors. It will be interesting to see if that happens.
Monday, 23 July 2012
Internet Usage by Operating System
I found this interesting so I thought I would share:
Usage share of Operating Systems
For my next project at work, I was wondering what operating system to use for any activities. The original course, which this content is based off of, was written for Solaris. But I can't imagine most potential students would have that. So one way of determining operating system usage is to look at statistics gathered by browsers. So the link shows that data for Wikipedia and some other sites that gather these sort of statistics.
Some observations:
Anyway, it looks like Windows 7 and XP are still my primary targets. But maybe I should think about Linux in the future.
Usage share of Operating Systems
For my next project at work, I was wondering what operating system to use for any activities. The original course, which this content is based off of, was written for Solaris. But I can't imagine most potential students would have that. So one way of determining operating system usage is to look at statistics gathered by browsers. So the link shows that data for Wikipedia and some other sites that gather these sort of statistics.
Some observations:
- Windows usage is still around around 70% with most users on Windows 7 and XP.
- iPhone plus iPad plus Android share is already over 10%. Smaller than I thought it would be, but if you think world wide usage it makes a lot of sense. Smart phones and tablets are just beginning to penetrate everywhere. And tablets are really gonna take off with 7" form factors and $200 list prices like the Google Nexus 7.
- Mac OS X combined with Linux is only around 10%.
Anyway, it looks like Windows 7 and XP are still my primary targets. But maybe I should think about Linux in the future.
Saturday, 21 July 2012
New Designs for the Blog
The template design has been updated as of this afternoon. Basically, the site is using the Blogger Picture Window template with the following tweeks.
- Changed the background to a picture I have been using for years. (It has more sky.)
- Added gray text shadow to the blog title and description. This makes the text pop a little more given the background has similar colors.
- Updated the Mobile template to use the Mobile version of Picture Window. So the site should look a lot beetter on a phone now.
Vertical Gallery-like ScrollView
With the custom LinearLayout (MyHorizontalLayout.java) in last exercise "Implement custom LinearLayout for Gallery-like HorizontalScrollView", it can be implement vertical Gallery-like ScrollView also.
Keep both MainActivity.java and MyHorizontalLayout.java of last exercise no change.
Modify the layout.
Related:
- GridView loading photos from SD Card
Keep both MainActivity.java and MyHorizontalLayout.java of last exercise no change.
Modify the layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="wrap_content"
android:layout_height="fill_parent" >
<com.example.androidhorizontalscrollviewgallery.MyHorizontalLayout
android:id="@+id/mygallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
/>
</ScrollView>
</LinearLayout>
Related:
- GridView loading photos from SD Card
Friday, 20 July 2012
Implement custom LinearLayout for Gallery-like HorizontalScrollView
Last exercise explain the basic to "implement Gallery-like HorizontalScrollView". In this post, we are going to implement our custom LinearLayout for Gallery-like HorizontalScrollView.
MyHorizontalLayout.java, our custom LinearLayout for Gallery-like HorizontalScrollView.
Modify layout to include MyHorizontalLayout.
See how simple is the main code:
Download the files.
Next:
- Vertical Gallery-like ScrollView
Related:
- GridView loading photos from SD Card
MyHorizontalLayout.java, our custom LinearLayout for Gallery-like HorizontalScrollView.
package com.example.androidhorizontalscrollviewgallery;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MyHorizontalLayout extends LinearLayout {
Context myContext;
ArrayList<String> itemList = new ArrayList<String>();
public MyHorizontalLayout(Context context) {
super(context);
myContext = context;
}
public MyHorizontalLayout(Context context, AttributeSet attrs) {
super(context, attrs);
myContext = context;
}
public MyHorizontalLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
myContext = context;
}
void add(String path){
int newIdx = itemList.size();
itemList.add(path);
addView(getImageView(newIdx));
}
ImageView getImageView(int i){
Bitmap bm = null;
if (i < itemList.size()){
bm = decodeSampledBitmapFromUri(itemList.get(i), 220, 220);
}
ImageView imageView = new ImageView(myContext);
imageView.setLayoutParams(new LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(bm);
return imageView;
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
Modify layout to include MyHorizontalLayout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.example.androidhorizontalscrollviewgallery.MyHorizontalLayout
android:id="@+id/mygallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
/>
</HorizontalScrollView>
</LinearLayout>
See how simple is the main code:
package com.example.androidhorizontalscrollviewgallery;
import java.io.File;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.widget.Toast;
public class MainActivity extends Activity {
MyHorizontalLayout myHorizontalLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myHorizontalLayout = (MyHorizontalLayout)findViewById(R.id.mygallery);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myHorizontalLayout.add(file.getAbsolutePath());
}
}
}
Download the files.
Next:
- Vertical Gallery-like ScrollView
Related:
- GridView loading photos from SD Card
Implement Gallery-like HorizontalScrollView
As mentioned in the post "Implement Android Gallery widget" - android.widget.Gallery is no longer supported. Other horizontally scrolling widgets include HorizontalScrollView and ViewPager from the support library.
It's a example to implement Gallery-like view using HorizontalScrollView. Please note that in this example, the bitmaps in HorizontalScrollView will not be removed even not in screen. So if too much bitmaps loaded, error of java.lang.OutOfMemoryError will be thrown!
Add HorizontalScrollView in layout:
Main Java code:
Download the files.
Next:
- Implement custom LinearLayout for Gallery-like HorizontalScrollView
It's a example to implement Gallery-like view using HorizontalScrollView. Please note that in this example, the bitmaps in HorizontalScrollView will not be removed even not in screen. So if too much bitmaps loaded, error of java.lang.OutOfMemoryError will be thrown!
Add HorizontalScrollView in layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/mygallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
/>
</HorizontalScrollView>
</LinearLayout>
Main Java code:
package com.example.androidhorizontalscrollviewgallery;
import java.io.File;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
public class MainActivity extends Activity {
LinearLayout myGallery;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myGallery = (LinearLayout)findViewById(R.id.mygallery);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
Toast.makeText(getApplicationContext(), targetPath, Toast.LENGTH_LONG).show();
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myGallery.addView(insertPhoto(file.getAbsolutePath()));
}
}
View insertPhoto(String path){
Bitmap bm = decodeSampledBitmapFromUri(path, 220, 220);
LinearLayout layout = new LinearLayout(getApplicationContext());
layout.setLayoutParams(new LayoutParams(250, 250));
layout.setGravity(Gravity.CENTER);
ImageView imageView = new ImageView(getApplicationContext());
imageView.setLayoutParams(new LayoutParams(220, 220));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(bm);
layout.addView(imageView);
return layout;
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
Download the files.
Next:
- Implement custom LinearLayout for Gallery-like HorizontalScrollView
Power Saver Button for iPad
Since getting an iPad 3 with LTE earlier this year, I have noticed that the battery runs down much faster than my old Wifi only iPad. It seems likely this is caused by the iPad's constantly checking with the cell tower, GPS, and other services. With the iPad in ready mode, the battery runs down about 10% or more per day.
So I was thinking, there must be an app I can use to save battery life. Then it struck me, what about Airplane Mode. The Airplane Mode setting turns off all communication systems on the device (Wifi, 4G, GPS). So last night, I turned on Airplane Mode and left my iPad in standby. This morning, the device only had lost 2% of its charge.
So it seems like to me, the power saver mode is built in already. :)
So I was thinking, there must be an app I can use to save battery life. Then it struck me, what about Airplane Mode. The Airplane Mode setting turns off all communication systems on the device (Wifi, 4G, GPS). So last night, I turned on Airplane Mode and left my iPad in standby. This morning, the device only had lost 2% of its charge.
So it seems like to me, the power saver mode is built in already. :)
Aurora Shootings
My thoughts and prayers go out to those affected by the shootings in Aurora last night. It is always very sobering when something like this happens 20 miles from your house.
Thursday, 19 July 2012
New Java Training Blog
After my previous post, I would be remiss in not pointing out a new blog for my team. The Java training developers at Oracle have setup the Java Training Beat blog.
The blog will include posts on new tutorials and products created by our team. In addition, we will include any other goodies that will help you get to know Java a little bit better. Feel free to bookmark the site and watch for updates.
Of course I will continue to post here with my insights such as they are. :)
The blog will include posts on new tutorials and products created by our team. In addition, we will include any other goodies that will help you get to know Java a little bit better. Feel free to bookmark the site and watch for updates.
Of course I will continue to post here with my insights such as they are. :)
Java Command Line Performance Tools
Well most of my friends don't get to see my work. My main gig is creating customer Java training for Oracle. For example, the main Java programming course: Java SE 7 Programming.
Well my current assignment is to create some free content for the Oracle Learning Library. So my first tutorial is out:
Java SE 7: Reviewing JVM Performance Command Line Tools
OLL Entry | Tutorial Link
The tutorial covers some of the built in command line tools included with Java 7. With the tools, you can query running JVMs and find out a great deal of information about them. So if this sounds interesting check it out.
Well my current assignment is to create some free content for the Oracle Learning Library. So my first tutorial is out:
Java SE 7: Reviewing JVM Performance Command Line Tools
OLL Entry | Tutorial Link
The tutorial covers some of the built in command line tools included with Java 7. With the tools, you can query running JVMs and find out a great deal of information about them. So if this sounds interesting check it out.
Dialog Animation using windowAnimations
In this exercise, we are going to apply slide-in and slide-out animation on dialog, using windowAnimations.
Create/modify /res/values/styles.xml to add animation style of DialogAnimation, using build-in animation of slide_in_left and slide_out_right.
Implement our dialog layout, /res/layout/dialoglayout.xml.
MainActivity.java
Main layout:
Download the files.
Create/modify /res/values/styles.xml to add animation style of DialogAnimation, using build-in animation of slide_in_left and slide_out_right.
<resources>
<style name="AppTheme" parent="android:Theme.Light" />
<style name="DialogAnimation">
<item name="android:windowEnterAnimation">@android:anim/slide_in_left</item>
<item name="android:windowExitAnimation">@android:anim/slide_out_right</item>
</style>
</resources>
Implement our dialog layout, /res/layout/dialoglayout.xml.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"/>
<Button
android:id="@+id/dismiss"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="dismiss"/>
</LinearLayout>
MainActivity.java
package com.example.animationdialog;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.app.Dialog;
public class MainActivity extends Activity {
Button btnOpenDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOpenDialog = (Button)findViewById(R.id.opendialog);
btnOpenDialog.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
openDialog();
}});
}
private void openDialog(){
final Dialog dialog = new Dialog(MainActivity.this);
dialog.setTitle("Animation Dialog");
dialog.setContentView(R.layout.dialoglayout);
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
Button btnDismiss = (Button)dialog.getWindow().findViewById(R.id.dismiss);
btnDismiss.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
dialog.dismiss();
}});
dialog.show();
}
}
Main layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/opendialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="@dimen/padding_medium"
android:text="Open Dialog"
tools:context=".MainActivity" />
</RelativeLayout>
Download the files.
Android SDK Tools Revision 20.0.1, NDK revision 8b, and ADT 20.0.1 released
Android SDK Tools Revision 20.0.1, full SDK for Android 4.1, released. You can now develop and publish applications against API level 16 using new Jelly Bean APIs. The new update can be downloaded through SDK Manager. Also updated are NDK revision 8b and ADT Plugin 20.0.1.
Update SDK on Eclipse:
Please note that note that the SDK Tools r20.0.1 is designed for use with ADT 20.0.1 and later. To update ADT in Eclipse, click Help -> Check for updates, to update ADT.
After updated ADT, click Window -> Android SDK Manager to install updated components.
Update SDK on Eclipse:
Please note that note that the SDK Tools r20.0.1 is designed for use with ADT 20.0.1 and later. To update ADT in Eclipse, click Help -> Check for updates, to update ADT.
After updated ADT, click Window -> Android SDK Manager to install updated components.
Wednesday, 18 July 2012
Create your own Evening Newspaper
Ever want to make your own Drudge Report or similar news site? ReadWriteWeb has a story on Mule Design, a web consulting company, that decided to do just that. They wanted to create a daily summary of news that emulated the evening additions published by newspapers. So instead of creating a super busy mess, like most news sites, they created Evening Edition.
Evening Edition is a very simple site with only a handful of stories listed. The excellent design makes the site easy to read. Definitely a concept worth emulating. And heck, anyone could come up with a similar design and start their own evening addition. Which would be kinda cool.
Now I am not convinced this is a huge break-thru that will save all newspapers. However, I think it does highlight the fact that often, less is more. I am struck at how awful most newspaper sites and newspaper apps generally are. The designs are busy with pop overs and pop unders and text everywhere. Just think how much more traffic they could get if they emulated this design.
Tuesday, 17 July 2012
Learn a Language while you Surf
Ran across this video on CNet today. It gives a pointer to this language immersion extension for Chrome.
Essentially it allows the plugin to insert foreign words and phrases into the pages you browse. The context should help you learn the language quickly. Anyway, looks like it could be very cool and well worth sharing.
Essentially it allows the plugin to insert foreign words and phrases into the pages you browse. The context should help you learn the language quickly. Anyway, looks like it could be very cool and well worth sharing.
Implement GestureDetector/OnGestureListener to detect Fling, and ObjectAnimator for ImageView
In this exercise, I will implement GestureDetector with OnGestureListener for a ImageView of icon. Once the user fling on the icon, it will be moved (animated using ObjectAnimator).
In order to use android.animation.ObjectAnimator, minSdkVersion="11" is needed.
Download the files.
package com.example.androidanimatefling;
import android.os.Bundle;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView info;
ImageView flingObj;
FrameLayout mainScreen;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
info = (TextView)findViewById(R.id.info);
flingObj = (ImageView)findViewById(R.id.flingobject);
mainScreen = (FrameLayout)findViewById(R.id.mainscreen);
final GestureDetector myGesture = new GestureDetector(this, new MyOnGestureListener());
flingObj.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
return myGesture.onTouchEvent(event);
}});
flingObj.setClickable(true);
}
class MyOnGestureListener implements OnGestureListener{
int MIN_DIST = 100;
@Override
public boolean onDown(MotionEvent arg0) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float e1X = e1.getX();
float e1Y = e1.getY();
float e2X = e2.getX();
float e2Y = e2.getY();
float distX = e2X - e1X;
float distY = e2Y - e1Y;
info.setText(
"e1X e1Y : " + String.valueOf(e1X) + " : " + String.valueOf(e1Y) + "\n" +
"e2X e2Y : " + String.valueOf(e2X) + " : " + String.valueOf(e2Y) + "\n" +
"velocityX : " + String.valueOf(velocityX) + "\n" +
"velocityY : " + String.valueOf(velocityY));
//Get the Y OFfset
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int offsetY = displayMetrics.heightPixels - mainScreen.getMeasuredHeight();
int[] location = new int[2];
flingObj.getLocationOnScreen(location);
float orgX = location[0];
float orgY = location[1] - offsetY;
float stopX = orgX + distX;
float stopY = orgY + distY;
if (distX > MIN_DIST) {
//Fling Right
ObjectAnimator flingAnimator = ObjectAnimator.ofFloat(flingObj, "translationX", orgX, stopX);
flingAnimator.setDuration(1000);
flingAnimator.start();
}else if(distX < - MIN_DIST){
//Fling Left
ObjectAnimator flingAnimator = ObjectAnimator.ofFloat(flingObj, "translationX", orgX, stopX);
flingAnimator.setDuration(1000);
flingAnimator.start();
}else if (distY > MIN_DIST) {
//Fling Down
ObjectAnimator flingAnimator = ObjectAnimator.ofFloat(flingObj, "translationY", orgY, stopY);
flingAnimator.setDuration(1000);
flingAnimator.start();
}else if(distY < - MIN_DIST){
//Fling Up
ObjectAnimator flingAnimator = ObjectAnimator.ofFloat(flingObj, "translationY", orgY, stopY);
flingAnimator.setDuration(1000);
flingAnimator.start();
}
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}};
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mainscreen">
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/flingobject"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/padding_medium"
android:src="@drawable/ic_launcher"
tools:context=".MainActivity" />
</FrameLayout>
In order to use android.animation.ObjectAnimator, minSdkVersion="11" is needed.
Download the files.
Error of getLocationInWindow() and getLocationOnScreen()
The View class provide the methods to computes the coordinates:
In my experience, the returned x location is correct, but the y location is always error with a fixed offset. The offset various depends on devices and configuration.
To correct it, we can get the offset using the code, after view displayed:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int offsetY = displayMetrics.heightPixels - mainScreen.getMeasuredHeight();
- getLocationInWindow (int[] location): Computes the coordinates of the view in its window.
- getLocationOnScreen (int[] location): Computes the coordinates of the view on the screen.
In my experience, the returned x location is correct, but the y location is always error with a fixed offset. The offset various depends on devices and configuration.
To correct it, we can get the offset using the code, after view displayed:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int offsetY = displayMetrics.heightPixels - mainScreen.getMeasuredHeight();
package com.example.androidoffsetgetlocation;
import android.os.Bundle;
import android.app.Activity;
import android.util.DisplayMetrics;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
LinearLayout mainScreen;
ImageView object;
TextView textOnCreate, textOnWindowFocusChanged;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainScreen = (LinearLayout)findViewById(R.id.mainscreen);
object = (ImageView)findViewById(R.id.object);
textOnCreate = (TextView)findViewById(R.id.textview1);
textOnWindowFocusChanged = (TextView)findViewById(R.id.textview2);
readLocation(textOnCreate, "onCreate()");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
readLocation(textOnWindowFocusChanged, "onWindowFocusChanged()");
}
private void readLocation(TextView tv, String status){
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int offsetX = displayMetrics.widthPixels - mainScreen.getMeasuredWidth();
int offsetY = displayMetrics.heightPixels - mainScreen.getMeasuredHeight();
int[] locationInWindow = new int[2];
object.getLocationInWindow(locationInWindow);
int[] locationOnScreen = new int[2];
object.getLocationOnScreen(locationOnScreen);
tv.setText(
"\n" + status +"\n"
+ "getLocationInWindow() - " + locationInWindow[0] + " : " + locationInWindow[1] + "\n"
+ "getLocationOnScreen() - " + locationOnScreen[0] + " : " + locationOnScreen[1] + "\n"
+ "Offset x: y - " + offsetX + " : " + offsetY);
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/mainscreen">
<ImageView
android:id="@+id/object"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"/>
<TextView
android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/textview2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Monday, 16 July 2012
Samsung Laptop Reviews Samsung Series 5 550 Chromebook Wi-Fi
Samsung Laptop Reviews Samsung Series 5 550 Chromebook Wi-Fi - This is a Samsung laptop with a specific brand name Samsung Series 5 550 Chromebook Wi-Fi. samsung laptop reviews is a laptop that has the advantage of features that are very sophisticated. more details can be seen below.
Samsung Laptop Reviews 2
Samsung Laptop Reviews 2
Complete list of all new features of Android 4.1 Jelly Bean
Android 4.1, Jelly Bean, is the fastest and smoothest version of Android yet. Jelly Bean improves on the simplicity and beauty of Android 4.0, and introduces a new Google search experience on Android.
To read what's new in Android 4.1 Jelly Bean, visit: http://www.android.com/about/jelly-bean/.
- Everything in Jelly Bean feels fast, fluid, and smooth. Moving between home screens and switching between apps is effortless, like turning pages in a book.
- Jelly Bean features improved performance throughout the system, including faster orientation changes, faster responses when switching between recent apps, and smoother and more consistent rendering across the system through vsync and triple buffering.
- Jelly Bean has more reactive and uniform touch responses, and makes your device even more responsive by boosting your device's CPU instantly when you touch the screen, and turns it down when you don't need it to improve battery life.
To read what's new in Android 4.1 Jelly Bean, visit: http://www.android.com/about/jelly-bean/.
Implement grouped CheckBox on Action Menu
Example of Action Menu with grouped CheckBox.
Create /res/menu/activity_main.xml to define action menu.
The checked status will not be updated automatically. We can change it in onOptionsItemSelected() callback method.
Create /res/menu/activity_main.xml to define action menu.
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_settings"
android:title="@string/menu_settings"
android:orderInCategory="100"
android:showAsAction="never" />
<group android:checkableBehavior="single">
<item android:id="@+id/selecta"
android:title="Selection A" android:checked="true"/>
<item android:id="@+id/selectb"
android:title="Selection B" />
<item android:id="@+id/selectc"
android:title="Selection C" />
</group>
</menu>
The checked status will not be updated automatically. We can change it in onOptionsItemSelected() callback method.
package com.example.androidactionbar;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.selecta:
item.setChecked(true);
Toast.makeText(getApplicationContext(),
"A Selected",
Toast.LENGTH_LONG).show();
return true;
case R.id.selectb:
item.setChecked(true);
Toast.makeText(getApplicationContext(),
"B Selected",
Toast.LENGTH_LONG).show();
return true;
case R.id.selectc:
item.setChecked(true);
Toast.makeText(getApplicationContext(),
"C Selected",
Toast.LENGTH_LONG).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Sunday, 15 July 2012
Everyone Hates Firefox Updates
WebMonkey posted this last week on some of the discussions at Mozilla around updates. The story has links to the original post by developer Jono DiCarlo as well as some links to the discussions surrounding the post. The gist of the post is this, all the constant updates to Firefox, to be more like Google Chrome, is killing Firefox.
I couldn't agree more. Chrome can do all those updates because they take place in the background and seldom make any changes to the UI. By contrast, Firefox constantly asks you to approve the updates and the changes too often include major changes to the UI.
This is a particular pet peeve of mine. Of course software needs updated, but often these updates occur too frequently. Mac OS X, gets updates too often. Just when I get to the point where I start to enjoy a version, I HAVE to upgrade again.
The latest Ubuntu UI update is really irritating. It is not that the new Unity Heads Up Display (HUD) is bad. I just really liked the old version of the UI. Why are you forcing me to switch when I don't want to?
To me a 3 to 5 year cycle on operating system UI updates make a lot more sense, than yearly or even bi-yearly cycles. Plus, can't someone come up with a way so I can keep some of the features I like? That would be truly awesome.
I couldn't agree more. Chrome can do all those updates because they take place in the background and seldom make any changes to the UI. By contrast, Firefox constantly asks you to approve the updates and the changes too often include major changes to the UI.
This is a particular pet peeve of mine. Of course software needs updated, but often these updates occur too frequently. Mac OS X, gets updates too often. Just when I get to the point where I start to enjoy a version, I HAVE to upgrade again.
The latest Ubuntu UI update is really irritating. It is not that the new Unity Heads Up Display (HUD) is bad. I just really liked the old version of the UI. Why are you forcing me to switch when I don't want to?
To me a 3 to 5 year cycle on operating system UI updates make a lot more sense, than yearly or even bi-yearly cycles. Plus, can't someone come up with a way so I can keep some of the features I like? That would be truly awesome.
LruCache with different size
Last exercise show Gallery with cached bitmaps using LruCache.
There is no specific size or formula that suits all applications, it's up to you to analyze your usage and come up with a suitable solution. A cache that is too small causes additional overhead with no benefit, a cache that is too large can once again cause java.lang.OutOfMemory exceptions and leave the rest of your app little memory to work with.
In this exercise, there are two Gallery widgets on screen, both with cached bitmaps using LruCache. The upper one with smaller cache size and the lower one with bigger cache size. There are more than 200 photos in /test/ directory. The upper small cache size gallery always re-load the cache. The lower one with bigger size of cache can keep bitmaps in cache, but when the cached memory get large, it crash the app!.
modify AndroidManifest.xml to have minSdkVersion and targetSdkVersion of "13".
Download the files.
There is no specific size or formula that suits all applications, it's up to you to analyze your usage and come up with a suitable solution. A cache that is too small causes additional overhead with no benefit, a cache that is too large can once again cause java.lang.OutOfMemory exceptions and leave the rest of your app little memory to work with.
In this exercise, there are two Gallery widgets on screen, both with cached bitmaps using LruCache. The upper one with smaller cache size and the lower one with bigger cache size. There are more than 200 photos in /test/ directory. The upper small cache size gallery always re-load the cache. The lower one with bigger size of cache can keep bitmaps in cache, but when the cached memory get large, it crash the app!.
package com.example.androidgallery;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
public abstract class CacheGalleryBaseAdapter extends BaseAdapter {
ArrayList<String> GalleryFileList;
Context context;
CacheGalleryBaseAdapter(Context cont){
context = cont;
GalleryFileList = new ArrayList<String>();
}
abstract Bitmap abstractGetBitmapFromMemCache(String key);
abstract BitmapWorkerTask abstractStartBitmapWorkerTask(ImageView imageView);
@Override
public int getCount() {
return GalleryFileList.size();
}
@Override
public Object getItem(int position) {
return GalleryFileList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
//---
// Use the path as the key to LruCache
final String imageKey = GalleryFileList.get(position);
final Bitmap bm = abstractGetBitmapFromMemCache(imageKey);
if (bm == null){
BitmapWorkerTask task = abstractStartBitmapWorkerTask(imageView);
task.execute(imageKey);
}
LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new Gallery.LayoutParams(250, 250));
layout.setGravity(Gravity.CENTER);
imageView.setLayoutParams(new Gallery.LayoutParams(200, 200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(bm);
layout.addView(imageView);
return layout;
}
public void add(String newitem){
GalleryFileList.add(newitem);
}
}
public class CacheGalleryBaseAdapter_SmallSize extends CacheGalleryBaseAdapter{
CacheGalleryBaseAdapter_SmallSize(Context cont) {
super(cont);
}
@Override
Bitmap abstractGetBitmapFromMemCache(String key) {
return getBitmapFromMemCache_SmallSize(key);
}
@Override
BitmapWorkerTask abstractStartBitmapWorkerTask(ImageView imageView) {
return (new BitmapWorkerTask_SmallSize(imageView));
}
}
public class CacheGalleryBaseAdapter_BigSize extends CacheGalleryBaseAdapter{
CacheGalleryBaseAdapter_BigSize(Context cont) {
super(cont);
}
@Override
Bitmap abstractGetBitmapFromMemCache(String key) {
return getBitmapFromMemCache_BigSize(key);
}
@Override
BitmapWorkerTask abstractStartBitmapWorkerTask(ImageView imageView) {
return(new BitmapWorkerTask_BigSize(imageView));
}
}
CacheGalleryBaseAdapter_SmallSize myFastGallery1BaseAdapter;
CacheGalleryBaseAdapter_BigSize myFastGallery2BaseAdapter;
Gallery myFastGallery1, myFastGallery2;
private LruCache<String, Bitmap> mMemoryCache_SmallSize;
private LruCache<String, Bitmap> mMemoryCache_BigSize;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myFastGallery1 = (Gallery)findViewById(R.id.fastgallery1);
myFastGallery2 = (Gallery)findViewById(R.id.fastgallery2);
myFastGallery1BaseAdapter = new CacheGalleryBaseAdapter_SmallSize(this);
myFastGallery2BaseAdapter = new CacheGalleryBaseAdapter_BigSize(this);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myFastGallery1BaseAdapter.add(file.getPath());
myFastGallery2BaseAdapter.add(file.getPath());
}
myFastGallery1.setAdapter(myFastGallery1BaseAdapter);
myFastGallery2.setAdapter(myFastGallery2BaseAdapter);
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
final int cacheSize_SmallSize = 1024 * 1024 * memClass / 12;
mMemoryCache_SmallSize = new LruCache_customSize(cacheSize_SmallSize);
final int cacheSize_BigSize = 1024 * 1024 * memClass;
mMemoryCache_BigSize = new LruCache_customSize(cacheSize_BigSize);
}
class LruCache_customSize extends LruCache<String, Bitmap>{
public LruCache_customSize(int maxSize) {
super(maxSize);
// TODO Auto-generated constructor stub
}
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
}
abstract class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public Bitmap getBitmapFromMemCache_SmallSize(String key) {
return (Bitmap) mMemoryCache_SmallSize.get(key);
}
public Bitmap getBitmapFromMemCache_BigSize(String key) {
return (Bitmap) mMemoryCache_BigSize.get(key);
}
class BitmapWorkerTask_SmallSize extends BitmapWorkerTask{
public BitmapWorkerTask_SmallSize(ImageView imageView) {
super(imageView);
// TODO Auto-generated constructor stub
}
@Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = decodeSampledBitmapFromUri(params[0], 200, 200);
if( getBitmapFromMemCache_SmallSize(String.valueOf(params[0])) == null){
mMemoryCache_SmallSize.put(String.valueOf(params[0]), bitmap);
}
return bitmap;
}
}
class BitmapWorkerTask_BigSize extends BitmapWorkerTask{
public BitmapWorkerTask_BigSize(ImageView imageView) {
super(imageView);
// TODO Auto-generated constructor stub
}
@Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = decodeSampledBitmapFromUri(params[0], 200, 200);
if( getBitmapFromMemCache_BigSize(String.valueOf(params[0])) == null){
mMemoryCache_BigSize.put(String.valueOf(params[0]), bitmap);
}
return bitmap;
}
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Gallery with Small Cache Size" />
<Gallery
android:id="@+id/fastgallery1"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Gallery with Big Cache Size" />
<Gallery
android:id="@+id/fastgallery2"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
modify AndroidManifest.xml to have minSdkVersion and targetSdkVersion of "13".
Download the files.
Saturday, 14 July 2012
Caching Bitmaps with LruCache
In the last exercise of "Implement Android Gallery widget with scale-down bitmap", the bitmap will be loaded and scaled every-time getView() of GalleryBaseAdapter called. The side-effect is the gallery widget stop a moment whenever a new a new item come-out.
The LruCache class (also available in the Support Library for use back to API Level 4) is particularly well suited to the task of caching bitmaps, keeping recently referenced objects in a strong referenced LinkedHashMap and evicting the least recently used member before the cache exceeds its designated size. ~ reference: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache.
In this exercise, two Gallery widget were implemented. In the video shown below, the upper one is original gallery, the lower one is gallery with cached bitmaps. It can be noted that the cached gallery need more time to be loaded in first loading, but swipe much more smooth.
Main activity.
Modify the layout to have two gallery.
android.util.LruCache is needed in the code, modify AndroidManifest.xml to have minSdkVersion and targetSdkVersion of "13".
Download the files.
Please note that this approach have it's own trade-off: if you request cacheSize too much, it will make your app causing java.lang.OutOfMemory exceptions, if too small, it will cause additional overhead. In my own openion, if you have predictable images (or resources) needed for caching, it's a good choice.
Read more: LruCache with different size
Related:
- Apply LruCache on GridView
The LruCache class (also available in the Support Library for use back to API Level 4) is particularly well suited to the task of caching bitmaps, keeping recently referenced objects in a strong referenced LinkedHashMap and evicting the least recently used member before the cache exceeds its designated size. ~ reference: http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#memory-cache.
In this exercise, two Gallery widget were implemented. In the video shown below, the upper one is original gallery, the lower one is gallery with cached bitmaps. It can be noted that the cached gallery need more time to be loaded in first loading, but swipe much more smooth.
Main activity.
package com.example.androidgallery;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.LruCache;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
public class GalleryBaseAdapter extends BaseAdapter {
ArrayList<String> GalleryFileList;
Context context;
GalleryBaseAdapter(Context cont){
context = cont;
GalleryFileList = new ArrayList<String>();
}
@Override
public int getCount() {
return GalleryFileList.size();
}
@Override
public Object getItem(int position) {
return GalleryFileList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Bitmap bm = decodeSampledBitmapFromUri(GalleryFileList.get(position), 200, 200);
LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new Gallery.LayoutParams(250, 250));
layout.setGravity(Gravity.CENTER);
ImageView imageView = new ImageView(context);
imageView.setLayoutParams(new Gallery.LayoutParams(200, 200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(bm);
layout.addView(imageView);
return layout;
}
public void add(String newitem){
GalleryFileList.add(newitem);
}
}
public class CacheGalleryBaseAdapter extends GalleryBaseAdapter{
CacheGalleryBaseAdapter(Context cont) {
super(cont);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(context);
//---
// Use the path as the key to LruCache
final String imageKey = GalleryFileList.get(position);
final Bitmap bm = getBitmapFromMemCache(imageKey);
if (bm == null){
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(imageKey);
}
LinearLayout layout = new LinearLayout(context);
layout.setLayoutParams(new Gallery.LayoutParams(250, 250));
layout.setGravity(Gravity.CENTER);
imageView.setLayoutParams(new Gallery.LayoutParams(200, 200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setImageBitmap(bm);
layout.addView(imageView);
return layout;
}
}
GalleryBaseAdapter myGalleryBaseAdapter;
CacheGalleryBaseAdapter myCacheGalleryBaseAdapter;
Gallery myPhotoGallery, myFastGallery;
private LruCache<String, Bitmap> mMemoryCache;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myPhotoGallery = (Gallery)findViewById(R.id.photogallery);
myFastGallery = (Gallery)findViewById(R.id.fastgallery);
myGalleryBaseAdapter = new GalleryBaseAdapter(this);
myCacheGalleryBaseAdapter = new CacheGalleryBaseAdapter(this);
String ExternalStorageDirectoryPath = Environment
.getExternalStorageDirectory()
.getAbsolutePath();
String targetPath = ExternalStorageDirectoryPath + "/test/";
File targetDirector = new File(targetPath);
File[] files = targetDirector.listFiles();
for (File file : files){
myGalleryBaseAdapter.add(file.getPath());
myCacheGalleryBaseAdapter.add(file.getPath());
}
myPhotoGallery.setAdapter(myGalleryBaseAdapter);
myFastGallery.setAdapter(myCacheGalleryBaseAdapter);
// Get memory class of this device, exceeding this amount will throw an
// OutOfMemory exception.
final int memClass = ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than number of items.
return bitmap.getByteCount();
}
};
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap>{
private final WeakReference<ImageView> imageViewReference;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String... params) {
final Bitmap bitmap = decodeSampledBitmapFromUri(params[0], 200, 200);
addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = (ImageView)imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return (Bitmap) mMemoryCache.get(key);
}
public Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
return bm;
}
public int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
Modify the layout to have two gallery.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Gallery without Cache" />
<Gallery
android:id="@+id/photogallery"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Gallery with Cache" />
<Gallery
android:id="@+id/fastgallery"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
android.util.LruCache is needed in the code, modify AndroidManifest.xml to have minSdkVersion and targetSdkVersion of "13".
Download the files.
Please note that this approach have it's own trade-off: if you request cacheSize too much, it will make your app causing java.lang.OutOfMemory exceptions, if too small, it will cause additional overhead. In my own openion, if you have predictable images (or resources) needed for caching, it's a good choice.
Read more: LruCache with different size
Related:
- Apply LruCache on GridView
Subscribe to:
Posts (Atom)