Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="8" android:versionName="TEST_RELEASE" package="pl.polidea.coverflow">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:label="@string/app_name" android:name=".testingactivity.CoverFlowTestingActivity">
<intent-filter>
Expand Down
168 changes: 168 additions & 0 deletions assets/faces.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
{
"people":[
{
"gravatar":"http://www.gravatar.com/avatar/feb86e26302b2efd0f937afa72a16fc6?d=monsterid&s=240",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's better to just keep gravatar id and build the URL from it (in single method). If we want to change resolution (for example) we'd have to change it in single place only.

"id":"0"
},
{
"gravatar":"http://www.gravatar.com/avatar/487bb9d69c8795b5dd1e67332cfb8221?d=monsterid&s=240",
"id":"1"
},
{
"gravatar":"http://www.gravatar.com/avatar/f31e2458313b36730a066ec703e51b11?d=monsterid&s=240",
"id":"2"
},
{
"gravatar":"http://www.gravatar.com/avatar/7f8727786f6bb1a0c352acc4e4419a83?d=monsterid&s=240",
"id":"3"
},
{
"gravatar":"http://www.gravatar.com/avatar/2dc3eab78ab131cc3a8acbc972c92b73?d=monsterid&s=240",
"id":"4"
},
{
"gravatar":"http://www.gravatar.com/avatar/705da853dcc90e5aca80b4d085c1d214?d=monsterid&s=240",
"id":"5"
},
{
"gravatar":"http://www.gravatar.com/avatar/28be0f28848e9b280845436bf3fad6ca?d=monsterid&s=240",
"id":"6"
},
{
"gravatar":"http://www.gravatar.com/avatar/1c364f4cad4f61aa08dc8f112931e39f?d=monsterid&s=240",
"id":"7"
},
{
"gravatar":"http://www.gravatar.com/avatar/bb03b2dafcda985bbeb52a4f446cc754?d=monsterid&s=240",
"id":"8"
},
{
"gravatar":"http://www.gravatar.com/avatar/ec43363ba46bdb76aae3999edf692871?d=monsterid&s=240",
"id":"9"
},
{
"gravatar":"http://www.gravatar.com/avatar/e32aee082c585f111fe3405d470112b0?d=monsterid&s=240",
"id":"10"
},
{
"gravatar":"http://www.gravatar.com/avatar/c770015076fd08e56be5cfd4ca387298?d=monsterid&s=240",
"id":"11"
},
{
"gravatar":"http://www.gravatar.com/avatar/53abc38c639a22f80174261df7f35f0d?d=monsterid&s=240",
"id":"12"
},
{
"gravatar":"http://www.gravatar.com/avatar/cd68c5cafec543474541a2211dc7444f?d=monsterid&s=240",
"id":"13"
},
{
"gravatar":"http://www.gravatar.com/avatar/2b7031546b140aa0612e4d2ce8f922c0?d=monsterid&s=240",
"id":"14"
},
{
"gravatar":"http://www.gravatar.com/avatar/bcb735972933b10b1eb269886c7c799a?d=monsterid&s=240",
"id":"15"
},
{
"gravatar":"http://www.gravatar.com/avatar/ab7fa42a14263894835ba1e5be031111?d=monsterid&s=240",
"id":"16"
},
{
"gravatar":"http://www.gravatar.com/avatar/35287768ccb0b3c68067a511c4c3503f?d=monsterid&s=240",
"id":"17"
},
{
"gravatar":"http://www.gravatar.com/avatar/45bba01ac921f96e49059da127800d6d?d=monsterid&s=240",
"id":"18"
},
{
"gravatar":"http://www.gravatar.com/avatar/289040ff9f5916ba6d88c660334660ec?d=monsterid&s=240",
"id":"19"
},
{
"gravatar":"http://www.gravatar.com/avatar/0808d58e098c64a5e9a1a411bce8d0d8?d=monsterid&s=240",
"id":"20"
},
{
"gravatar":"http://www.gravatar.com/avatar/81801d4f62de321a0bd6903fe9459a5a?d=monsterid&s=240",
"id":"21"
},
{
"gravatar":"http://www.gravatar.com/avatar/0cbc8aace3690ac2288754bfb12ef43c?d=monsterid&s=240",
"id":"22"
},
{
"gravatar":"http://www.gravatar.com/avatar/dae071222608e84f665fdfd4678e8f2e?d=monsterid&s=240",
"id":"23"
},
{
"gravatar":"http://www.gravatar.com/avatar/9b14143dfed8f4fa57428ad3e547bc0e?d=monsterid&s=240",
"id":"24"
},
{
"gravatar":"http://www.gravatar.com/avatar/e0a27844ea90b44bcebfa3bec7a583bd?d=monsterid&s=240",
"id":"25"
},
{
"gravatar":"http://www.gravatar.com/avatar/e60ecae6d42227896b877fe5ae80dcbf?d=monsterid&s=240",
"id":"26"
},
{
"gravatar":"http://www.gravatar.com/avatar/cb8004fd244c846ef07902d30be3d584?d=monsterid&s=240",
"id":"27"
},
{
"gravatar":"http://www.gravatar.com/avatar/5f68d5e3481bbd4e143454820f33d9b6?d=monsterid&s=240",
"id":"28"
},
{
"gravatar":"http://www.gravatar.com/avatar/eae907f53220bbcaabfe0cda31be29d8?d=monsterid&s=240",
"id":"29"
},
{
"gravatar":"http://www.gravatar.com/avatar/cd26f838cf344a14b8a1add418f8f2b8?d=monsterid&s=240",
"id":"30"
},
{
"gravatar":"http://www.gravatar.com/avatar/35bbb9b6fbad099dcbb2901d281a8d8e?d=monsterid&s=240",
"id":"31"
},
{
"gravatar":"http://www.gravatar.com/avatar/335ee931be900e9d28e769e5c9537084?d=monsterid&s=240",
"id":"32"
},
{
"gravatar":"http://www.gravatar.com/avatar/547db7c434e8a83737d99f0f4eab2290?d=monsterid&s=240",
"id":"33"
},
{
"gravatar":"http://www.gravatar.com/avatar/96dbb97764ca7f5d56073ccf401a9753?d=monsterid&s=240",
"id":"34"
},
{
"gravatar":"http://www.gravatar.com/avatar/fedd24fdaae013b925eff616ad55fee8?d=monsterid&s=240",
"id":"35"
},
{
"gravatar":"http://www.gravatar.com/avatar/fa0a22c3463a9ee3cb1acd6bc05b9a3e?d=monsterid&s=240",
"id":"36"
},
{
"gravatar":"http://www.gravatar.com/avatar/674f1d9793c903baeb7607655cd0f787?d=monsterid&s=240",
"id":"37"
},
{
"gravatar":"http://www.gravatar.com/avatar/ee5179d5ce0b3172b6b34c5ec94a61c0?d=monsterid&s=240",
"id":"38"
},
{
"gravatar":"http://www.gravatar.com/avatar/fde11b1d20465b0dcb7c9879aca299a3?d=monsterid&s=240",
"id":"39"
},
{
"gravatar":"http://www.gravatar.com/avatar/e6f6d95ae0cad8073ccac961c3c9e9d7?d=monsterid&s=240",
"id":"40"
}
]
}
9 changes: 9 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,19 @@ repositories {
}
}

dependencies {
compile 'com.squareup.picasso:picasso:2.3.3'
}

android {
compileSdkVersion 19
buildToolsVersion "19.1.0"

defaultConfig {
minSdkVersion 5
targetSdkVersion 18
}

sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
Expand Down
10 changes: 5 additions & 5 deletions src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package pl.polidea.coverflow;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
Expand All @@ -12,6 +8,10 @@
import android.widget.BaseAdapter;
import android.widget.ImageView;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

/**
* This class is an adapter that provides base, abstract class for images
* adapter.
Expand Down Expand Up @@ -100,7 +100,7 @@ public final synchronized long getItemId(final int position) {
* android.view.ViewGroup)
*/
@Override
public final synchronized ImageView getView(final int position, final View convertView, final ViewGroup parent) {
public synchronized ImageView getView(final int position, final View convertView, final ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
final Context context = parent.getContext();
Expand Down
145 changes: 145 additions & 0 deletions src/pl/polidea/coverflow/NetworkImageAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package pl.polidea.coverflow;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.squareup.picasso.Picasso;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import pl.polidea.coverflow.testingactivity.Result;

/**
* This class is an adapter that provides images from a fixed set of resource
* ids. Bitmaps and ImageViews are kept as weak references so that they can be
* cleared by garbage collection when not needed.
*
*/
public class NetworkImageAdapter extends AbstractCoverFlowImageAdapter {
/** The Constant TAG. */
private static final String TAG = NetworkImageAdapter.class.getSimpleName();

/** The bitmap map. */
private final Map<Integer, WeakReference<Bitmap>> bitmapMap = new HashMap<Integer, WeakReference<Bitmap>>();

private final Context context;

private static final LinkedList<Result> RESULTS = new LinkedList<Result>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use Result [] here rather than list. The usage pattern is that we never actually add anything to the list. We have "setResources" with list of results and there effectively we replace the whole "list" (clear(), for() { add} ). What we really wanted to achieve here (capital RESULTS suggest that) is that the RESULTS is immutable. We cannot fully achieve that (We cannot have immutable array in java, final does not make it immutable). Alternatively we could use guava's ImmutableList or Collections.unmodifiableList() - if we really wanted a "constant" - i.e. immutable results here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


public NetworkImageAdapter(final Context context)
{
super();

this.context = context;
try {
setResources(parseJSONResult(readStringFromInputStream(context.getAssets().open("faces.txt"))));
}
catch (IOException e)
{
e.printStackTrace();
}
}

public final synchronized void setResources(List<Result> results)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems odd to me that we are copying one list into another and in a loop at that (results.clone() could do the work easily. I know we wanted to have final RESULTS, but probably that's not what we really wanted to have. What we have now is RESULTS which is really MUTABLE (clear(), add()) only the container (List) is immutable. This is quite the opposite to what we would like to achieve. In this case we can really easily get an exception when we are getting element and someone else does "clear()". See also my comment about using array instead of list.

{
RESULTS.clear();

for (Result r : results)
{
RESULTS.add(r);
}

notifyDataSetChanged();
}

/*
* (non-Javadoc)
*
* @see android.widget.Adapter#getCount()
*/
@Override
public synchronized int getCount()
{
return RESULTS.size();
}

/*
* (non-Javadoc)
*
* @see pl.polidea.coverflow.AbstractCoverFlowImageAdapter#createBitmap(int)
*/
@Override
protected Bitmap createBitmap(final int position) {
return ((BitmapDrawable) context.getResources().getDrawable(R.drawable.image01)).getBitmap();
}

private String readStringFromInputStream(InputStream inputStream) throws IOException
{
StringBuilder builder = new StringBuilder();

int c;

while((c = inputStream.read()) != -1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reading from stream byte by byte is very slow usually. It only gets really fast if you wrap the inputStream into BufferedInputStream (with appropriate buffer size ideally). I believe that we are not getting a buffered input stream here ( http://developer.android.com/reference/android/content/res/AssetManager.html#open(java.lang.String) is silent about what kind of stream we get) so it would be great to wrap it in buffered input stream.

{
builder.append((char)c);
}

return builder.toString();
}

private LinkedList<Result> parseJSONResult(String result)
{
LinkedList<Result> results = new LinkedList<Result>();

try
{
JSONObject outerItem = new JSONObject(result);
JSONArray jArray = outerItem.getJSONArray("people");

for (int i = 0; i < jArray.length(); i++)
{
JSONObject employee = jArray.getJSONObject(i);
String id = employee.getString("id");

String url = employee.getString("gravatar");

Result employeeResult = new Result(url, id);
results.add(employeeResult);
}
}
catch (JSONException e)
{
Log.e("CoverFlowTestingActivity", "JSONException in parseJSONResult");
e.printStackTrace();
}

return results;
}

@Override
public synchronized ImageView getView(int position, View convertView, ViewGroup parent)
{
ImageView view = super.getView(position, convertView, parent);

Log.d(TAG, "getView: " + RESULTS.get(position));

Picasso.with(context).load(RESULTS.get(position).getAvatarURL()).into(view);

return view;
}
}
10 changes: 5 additions & 5 deletions src/pl/polidea/coverflow/ResourceImageAdapter.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package pl.polidea.coverflow;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;

/**
* This class is an adapter that provides images from a fixed set of resource
* ids. Bitmaps and ImageViews are kept as weak references so that they can be
Expand Down
Loading