diff --git a/briar-android/res/layout/fragment_blogs_my.xml b/briar-android/res/layout/fragment_blogs_my.xml
index a552dc0fce49e2a0f2c2ca14340ab4c38ae51fff..288adfaa3937ea3d0b242b6c7177007b3e994d67 100644
--- a/briar-android/res/layout/fragment_blogs_my.xml
+++ b/briar-android/res/layout/fragment_blogs_my.xml
@@ -1,26 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- This is just a placeholder to be replaced by the real My Blogs list -->
-<LinearLayout
+<org.briarproject.android.util.BriarRecyclerView
 	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:id="@+id/num"
-		android:layout_width="match_parent"
-		android:layout_height="wrap_content"
-		android:gravity="center_horizontal"
-		android:padding="@dimen/margin_activity_horizontal"
-		android:textSize="128sp"
-		tools:text="1"/>
-
-	<TextView
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"
-		android:padding="@dimen/margin_activity_horizontal"
-		android:text="There is nothing for you to see here.\n\nMove along and come back later."
-		android:textSize="@dimen/text_size_large"/>
-
-</LinearLayout>
\ No newline at end of file
+	tools:listitem="@layout/list_item_blog"/>
diff --git a/briar-android/res/layout/list_item_blog.xml b/briar-android/res/layout/list_item_blog.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1fe1f22db024383b68baea541fbfea8e11eb88e3
--- /dev/null
+++ b/briar-android/res/layout/list_item_blog.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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="wrap_content"
+	android:layout_marginLeft="@dimen/listitem_horizontal_margin"
+	android:layout_marginStart="@dimen/listitem_horizontal_margin"
+	android:background="?attr/selectableItemBackground">
+
+	<org.briarproject.android.util.TextAvatarView
+		android:id="@+id/avatarView"
+		android:layout_width="@dimen/listitem_picture_frame_size"
+		android:layout_height="@dimen/listitem_picture_frame_size"
+		android:layout_alignParentLeft="true"
+		android:layout_alignParentStart="true"
+		android:layout_marginEnd="@dimen/listitem_horizontal_margin"
+		android:layout_marginRight="@dimen/listitem_horizontal_margin"
+		android:layout_marginTop="@dimen/margin_medium"/>
+
+	<TextView
+		android:id="@+id/nameView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_alignParentTop="true"
+		android:layout_marginTop="@dimen/listitem_horizontal_margin"
+		android:layout_toEndOf="@+id/avatarView"
+		android:layout_toRightOf="@+id/avatarView"
+		android:maxLines="2"
+		android:textColor="@color/briar_text_primary"
+		android:textSize="@dimen/text_size_medium"
+		tools:text="This is a name of a blog"/>
+
+	<TextView
+		android:id="@+id/postCountView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@+id/nameView"
+		android:layout_marginBottom="@dimen/margin_small"
+		android:layout_toEndOf="@+id/avatarView"
+		android:layout_toRightOf="@+id/avatarView"
+		android:paddingTop="@dimen/margin_small"
+		android:textColor="@color/briar_text_secondary"
+		android:textSize="@dimen/text_size_small"
+		tools:text="1337 posts"/>
+
+	<TextView
+		android:id="@+id/dateView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_alignParentEnd="true"
+		android:layout_alignParentRight="true"
+		android:layout_below="@+id/nameView"
+		android:layout_marginEnd="@dimen/listitem_horizontal_margin"
+		android:layout_marginRight="@dimen/listitem_horizontal_margin"
+		android:paddingTop="@dimen/margin_small"
+		android:textColor="@color/briar_text_secondary"
+		android:textSize="@dimen/text_size_small"
+		tools:text="Dec 24"/>
+
+	<TextView
+		android:id="@+id/statusView"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_below="@+id/postCountView"
+		android:layout_toEndOf="@+id/avatarView"
+		android:layout_toRightOf="@+id/avatarView"
+		android:textColor="@color/briar_text_tertiary"
+		tools:text="@string/blogs_blog_is_empty"/>
+
+	<View
+		style="@style/Divider.ForumList"
+		android:layout_alignParentLeft="true"
+		android:layout_alignParentStart="true"
+		android:layout_below="@+id/statusView"
+		android:layout_marginTop="@dimen/listitem_horizontal_margin"/>
+
+</RelativeLayout>
+
diff --git a/briar-android/res/layout/list_item_forum.xml b/briar-android/res/layout/list_item_forum.xml
index 171a40859c67555455afbe89f7e902882c39ac6b..0652bec6b01927253e4bbe35986de7a1ace3cb24 100644
--- a/briar-android/res/layout/list_item_forum.xml
+++ b/briar-android/res/layout/list_item_forum.xml
@@ -31,7 +31,7 @@
 		tools:text="This is a name of a forum"/>
 
 	<TextView
-		android:id="@+id/unreadView"
+		android:id="@+id/postCountView"
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
 		android:layout_below="@+id/forumNameView"
@@ -62,7 +62,7 @@
 		style="@style/Divider.ForumList"
 		android:layout_alignParentLeft="true"
 		android:layout_alignParentStart="true"
-		android:layout_below="@+id/unreadView"/>
+		android:layout_below="@+id/postCountView"/>
 
 </RelativeLayout>
 
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 3447cf1ec3a3b136b7f7841edcc5fca35bad4cd1..e3793a54638e9f83418dacf23af35e3f961b918b 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -81,12 +81,12 @@
 	<string name="forum_leave">Leave Forum</string>
 	<string name="forum_left_toast">Left Forum</string>
 	<string name="forum_sharing_status">Sharing Status</string>
-	<string name="forum_no_posts">No posts</string>
+	<string name="no_posts">No posts</string>
 	<plurals name="unread_posts">
 		<item quantity="one">%d unread post</item>
 		<item quantity="other">%d unread posts</item>
 	</plurals>
-	<plurals name="forum_posts">
+	<plurals name="posts">
 		<item quantity="one">%d post</item>
 		<item quantity="other">%d posts</item>
 	</plurals>
@@ -256,7 +256,9 @@
 	<string name="blogs_my_blogs_create_hint_title">Blog title (cannot be changed later)</string>
 	<string name="blogs_my_blogs_create_hint_desc">A short description of your new blog</string>
 	<string name="blogs_my_blogs_create_hint_desc_explanation">Potential readers may or may not subscribe to your blog based on the content of the description.</string>
+	<string name="blogs_my_blogs_empty_state">You don\'t have any blogs.\n\nWhy don\'t you create one now by clicking the plus in the top right screen corner?</string>
 	<string name="blogs_my_blogs_created">Blog created</string>
+	<string name="blogs_blog_is_empty">This blog is empty</string>
 
 	<string name="blogs_blog_list">Blog List</string>
 	<string name="blogs_available_blogs">Available Blogs</string>
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java b/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..be0ff5e12ffc478be447035692ac00687486e397
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/blogs/BlogListAdapter.java
@@ -0,0 +1,197 @@
+package org.briarproject.android.blogs;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.util.SortedList;
+import android.support.v7.widget.RecyclerView;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.briarproject.R;
+import org.briarproject.android.util.TextAvatarView;
+import org.briarproject.api.sync.GroupId;
+
+import java.util.Collection;
+
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+class BlogListAdapter extends
+		RecyclerView.Adapter<BlogListAdapter.BlogViewHolder> {
+
+	private SortedList<BlogListItem> blogs = new SortedList<>(
+			BlogListItem.class, new SortedList.Callback<BlogListItem>() {
+
+		@Override
+		public int compare(BlogListItem a, BlogListItem b) {
+			if (a == b) return 0;
+			// The blog with the newest message comes first
+			long aTime = a.getTimestamp(), bTime = b.getTimestamp();
+			if (aTime > bTime) return -1;
+			if (aTime < bTime) return 1;
+			// Break ties by blog name
+			String aName = a.getName();
+			String bName = b.getName();
+			return String.CASE_INSENSITIVE_ORDER.compare(aName, bName);
+		}
+
+		@Override
+		public void onInserted(int position, int count) {
+			notifyItemRangeInserted(position, count);
+		}
+
+		@Override
+		public void onRemoved(int position, int count) {
+			notifyItemRangeRemoved(position, count);
+		}
+
+		@Override
+		public void onMoved(int fromPosition, int toPosition) {
+			notifyItemMoved(fromPosition, toPosition);
+		}
+
+		@Override
+		public void onChanged(int position, int count) {
+			notifyItemRangeChanged(position, count);
+		}
+
+		@Override
+		public boolean areContentsTheSame(BlogListItem a, BlogListItem b) {
+			return a.getBlog().equals(b.getBlog()) &&
+					a.getTimestamp() == b.getTimestamp() &&
+					a.getUnreadCount() == b.getUnreadCount();
+		}
+
+		@Override
+		public boolean areItemsTheSame(BlogListItem a, BlogListItem b) {
+			return a.getBlog().equals(b.getBlog());
+		}
+	});
+
+	private final Context ctx;
+
+	BlogListAdapter(Context ctx) {
+		this.ctx = ctx;
+	}
+
+	@Override
+	public BlogViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+		View v = LayoutInflater.from(ctx).inflate(
+				R.layout.list_item_blog, parent, false);
+		return new BlogViewHolder(v);
+	}
+
+	@Override
+	public void onBindViewHolder(BlogViewHolder ui, int position) {
+		final BlogListItem item = getItem(position);
+
+		// Avatar
+		ui.avatar.setText(item.getName().substring(0, 1));
+		ui.avatar.setBackgroundBytes(item.getBlog().getId().getBytes());
+		ui.avatar.setUnreadCount(item.getUnreadCount());
+
+		// Blog Name
+		ui.name.setText(item.getName());
+
+		// Post Count
+		int postCount = item.getPostCount();
+		ui.postCount.setText(ctx.getResources()
+				.getQuantityString(R.plurals.posts, postCount, postCount));
+		ui.postCount.setTextColor(
+				ContextCompat.getColor(ctx, R.color.briar_text_secondary));
+
+		// Date and Status
+		if (item.isEmpty()) {
+			ui.date.setVisibility(GONE);
+			ui.avatar.setProblem(true);
+			ui.status.setText(ctx.getString(R.string.blogs_blog_is_empty));
+			ui.status.setVisibility(VISIBLE);
+		} else {
+			long timestamp = item.getTimestamp();
+			ui.date.setText(
+					DateUtils.getRelativeTimeSpanString(ctx, timestamp));
+			ui.date.setVisibility(VISIBLE);
+			ui.status.setVisibility(GONE);
+		}
+
+		// Open Blog on Click
+		ui.layout.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				// TODO #415
+/*				Intent i = new Intent(ctx, BlogActivity.class);
+				Blog b = item.getBlog();
+				i.putExtra(GROUP_ID, b.getId().getBytes());
+				i.putExtra(BLOG_NAME, b.getName());
+				ctx.startActivity(i);
+*/			}
+		});
+	}
+
+	@Override
+	public int getItemCount() {
+		return blogs.size();
+	}
+
+	public BlogListItem getItem(int position) {
+		return blogs.get(position);
+	}
+
+	@Nullable
+	public BlogListItem getItem(GroupId g) {
+		for (int i = 0; i < blogs.size(); i++) {
+			BlogListItem item = blogs.get(i);
+			if (item.getBlog().getGroup().getId().equals(g)) {
+				return item;
+			}
+		}
+		return null;
+	}
+
+	public void addAll(Collection<BlogListItem> items) {
+		blogs.addAll(items);
+	}
+
+	void updateItem(BlogListItem item) {
+		BlogListItem oldItem = getItem(item.getBlog().getGroup().getId());
+		int position = blogs.indexOf(oldItem);
+		blogs.updateItemAt(position, item);
+	}
+
+	public void remove(BlogListItem item) {
+		blogs.remove(item);
+	}
+
+	public void clear() {
+		blogs.clear();
+	}
+
+	public boolean isEmpty() {
+		return blogs.size() == 0;
+	}
+
+	static class BlogViewHolder extends RecyclerView.ViewHolder {
+
+		private final ViewGroup layout;
+		private final TextAvatarView avatar;
+		private final TextView name;
+		private final TextView postCount;
+		private final TextView date;
+		private final TextView status;
+
+		BlogViewHolder(View v) {
+			super(v);
+
+			layout = (ViewGroup) v;
+			avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
+			name = (TextView) v.findViewById(R.id.nameView);
+			postCount = (TextView) v.findViewById(R.id.postCountView);
+			date = (TextView) v.findViewById(R.id.dateView);
+			status = (TextView) v.findViewById(R.id.statusView);
+		}
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/blogs/BlogListItem.java b/briar-android/src/org/briarproject/android/blogs/BlogListItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..681dac42f5859f5af9f55d712ec407a770dedaf2
--- /dev/null
+++ b/briar-android/src/org/briarproject/android/blogs/BlogListItem.java
@@ -0,0 +1,61 @@
+package org.briarproject.android.blogs;
+
+import org.briarproject.api.blogs.Blog;
+import org.briarproject.api.blogs.BlogPostHeader;
+
+import java.util.Collection;
+
+class BlogListItem {
+
+	private final Blog blog;
+	private final int postCount;
+	private final long timestamp;
+	private final int unread;
+
+	BlogListItem(Blog blog, Collection<BlogPostHeader> headers) {
+		this.blog = blog;
+		if (headers.isEmpty()) {
+			postCount = 0;
+			timestamp = 0;
+			unread = 0;
+		} else {
+			BlogPostHeader newest = null;
+			long timestamp = -1;
+			int unread = 0;
+			for (BlogPostHeader h : headers) {
+				if (h.getTimestamp() > timestamp) {
+					timestamp = h.getTimestamp();
+					newest = h;
+				}
+				if (!h.isRead()) unread++;
+			}
+			this.postCount = headers.size();
+			this.timestamp = newest.getTimestamp();
+			this.unread = unread;
+		}
+	}
+
+	Blog getBlog() {
+		return blog;
+	}
+
+	String getName() {
+		return blog.getName();
+	}
+
+	boolean isEmpty() {
+		return postCount == 0;
+	}
+
+	int getPostCount() {
+		return postCount;
+	}
+
+	long getTimestamp() {
+		return timestamp;
+	}
+
+	int getUnreadCount() {
+		return unread;
+	}
+}
diff --git a/briar-android/src/org/briarproject/android/blogs/MyBlogsFragment.java b/briar-android/src/org/briarproject/android/blogs/MyBlogsFragment.java
index cb28dd0ea5500b8afe442b063616b5a57b7bc1d0..d6ef76ae31e889a13001800da7dd8bf34fe13cca 100644
--- a/briar-android/src/org/briarproject/android/blogs/MyBlogsFragment.java
+++ b/briar-android/src/org/briarproject/android/blogs/MyBlogsFragment.java
@@ -5,26 +5,50 @@ import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v7.widget.LinearLayoutManager;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.TextView;
 
 import org.briarproject.R;
 import org.briarproject.android.ActivityComponent;
 import org.briarproject.android.fragment.BaseFragment;
+import org.briarproject.android.util.BriarRecyclerView;
+import org.briarproject.api.blogs.Blog;
+import org.briarproject.api.blogs.BlogManager;
+import org.briarproject.api.blogs.BlogPostHeader;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.NoSuchGroupException;
+import org.briarproject.api.identity.IdentityManager;
+import org.briarproject.api.identity.LocalAuthor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
 import static android.support.v4.app.ActivityOptionsCompat.makeCustomAnimation;
+import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
 
 public class MyBlogsFragment extends BaseFragment {
 
 	public final static String TAG = MyBlogsFragment.class.getName();
 
+	private static final Logger LOG = Logger.getLogger(TAG);
+	private BriarRecyclerView list;
+	private BlogListAdapter adapter;
+
+	// Fields that are accessed from background threads must be volatile
+	@Inject
+	protected volatile IdentityManager identityManager;
+	@Inject
+	volatile BlogManager blogManager;
+
 	@Inject
 	public MyBlogsFragment() {
 	}
@@ -35,19 +59,30 @@ public class MyBlogsFragment extends BaseFragment {
 			Bundle savedInstanceState) {
 
 		setHasOptionsMenu(true);
-		View v = inflater.inflate(R.layout.fragment_blogs_my, container,
-				false);
 
-		TextView numView = (TextView) v.findViewById(R.id.num);
-		numView.setText("My Blogs");
+		adapter = new BlogListAdapter(getActivity());
+
+		list = (BriarRecyclerView) inflater
+				.inflate(R.layout.fragment_blogs_my, container, false);
+		list.setLayoutManager(new LinearLayoutManager(getActivity()));
+		list.setAdapter(adapter);
+		list.setEmptyText(getString(R.string.blogs_my_blogs_empty_state));
 
-		return v;
+		return list;
 	}
 
 	@Override
 	public void onActivityCreated(Bundle savedInstanceState) {
 		super.onActivityCreated(savedInstanceState);
 		listener.getActivityComponent().inject(this);
+		// Starting from here, we can use injected objects
+	}
+
+	@Override
+	public void onResume() {
+		super.onResume();
+		adapter.clear();
+		loadBlogs();
 	}
 
 	@Override
@@ -85,4 +120,49 @@ public class MyBlogsFragment extends BaseFragment {
 		component.inject(this);
 	}
 
+	private void loadBlogs() {
+		listener.runOnDbThread(new Runnable() {
+			@Override
+			public void run() {
+				try {
+					// load blogs
+					long now = System.currentTimeMillis();
+					Collection<BlogListItem> blogs = new ArrayList<>();
+					Collection<LocalAuthor> authors =
+							identityManager.getLocalAuthors();
+					LocalAuthor a = authors.iterator().next();
+					for (Blog b : blogManager.getBlogs(a)) {
+						try {
+							Collection<BlogPostHeader> headers =
+									blogManager.getPostHeaders(b.getId());
+							blogs.add(new BlogListItem(b, headers));
+						} catch (NoSuchGroupException e) {
+							// Continue
+						}
+					}
+					displayBlogs(blogs);
+					long duration = System.currentTimeMillis() - now;
+					if (LOG.isLoggable(INFO))
+						LOG.info("Full blog load took " + duration + " ms");
+				} catch (DbException e) {
+					if (LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				}
+			}
+		});
+	}
+
+	private void displayBlogs(final Collection<BlogListItem> items) {
+		listener.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				if (items.size() == 0) {
+					list.showData();
+				} else {
+					adapter.addAll(items);
+				}
+			}
+		});
+	}
+
 }
diff --git a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
index 17fd01346b17fbedbcf58567a430987c9c77d209..2051eadffdb8c7eb0f0b7e60e7f97a8b27510719 100644
--- a/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
+++ b/briar-android/src/org/briarproject/android/forum/ForumListAdapter.java
@@ -104,16 +104,16 @@ class ForumListAdapter extends
 		// Post Count
 		int postCount = item.getPostCount();
 		if (postCount > 0) {
-			ui.unread.setText(ctx.getResources()
-					.getQuantityString(R.plurals.forum_posts, postCount,
+			ui.postCount.setText(ctx.getResources()
+					.getQuantityString(R.plurals.posts, postCount,
 							postCount));
-			ui.unread.setTextColor(
+			ui.postCount.setTextColor(
 					ContextCompat
 							.getColor(ctx, R.color.briar_text_secondary));
 		} else {
 			ui.avatar.setProblem(true);
-			ui.unread.setText(ctx.getString(R.string.forum_no_posts));
-			ui.unread.setTextColor(
+			ui.postCount.setText(ctx.getString(R.string.no_posts));
+			ui.postCount.setTextColor(
 					ContextCompat
 							.getColor(ctx, R.color.briar_text_tertiary));
 		}
@@ -187,7 +187,7 @@ class ForumListAdapter extends
 		private final ViewGroup layout;
 		private final TextAvatarView avatar;
 		private final TextView name;
-		private final TextView unread;
+		private final TextView postCount;
 		private final TextView date;
 
 		ForumViewHolder(View v) {
@@ -196,7 +196,7 @@ class ForumListAdapter extends
 			layout = (ViewGroup) v;
 			avatar = (TextAvatarView) v.findViewById(R.id.avatarView);
 			name = (TextView) v.findViewById(R.id.forumNameView);
-			unread = (TextView) v.findViewById(R.id.unreadView);
+			postCount = (TextView) v.findViewById(R.id.postCountView);
 			date = (TextView) v.findViewById(R.id.dateView);
 		}
 	}