Getting a URL or file pointer to a Couchbase Lite attachment in Android

243 views
Skip to first unread message

Suresh Joshi

unread,
Sep 9, 2014, 2:44:13 PM9/9/14
to mobile-c...@googlegroups.com
Hi all, I noticed in iOS, there is a contentUrl for an attachment and there doesn't seem to be a publicly used analogy in the Android world. In the CBL code, I see there is a database table used to store the attachment blob location with the SHA-1 key, but it's not publicly accessible. 

Basically, my use case is the same as with many people, which is I have documents with images as attachments (whether this is the best idea or not, it's how everything is set up for the next few months). I want to use Picasso to load these images and handle all my caching, but Picasso and OkHttp require a URL to hit with cache-control values set.

I noticed that I can hit Sync Gateway + docId + key, and see my image attachment, however, this doesn't seem to show up with a cache-control header - can this be modded? Otherwise, if I go offline, I can no longer see images.

Alternatively, what I would like to do, is that since I already have all the images on my phone, I wanted to write a custom 'downloader' for Picasso, where I would just pull an inputSteam from a file pointer, however, the .blob file and the attachment it represents aren't publicly linked. I have a rooted phone, and found the CBL database file, as well as the associated attachments directory, but I have no idea which blob file represents which attachment.

Am I missing something simple here? Or has anyone done something similar before? 

Thanks!
-SJ

Jens Alfke

unread,
Sep 9, 2014, 3:01:59 PM9/9/14
to mobile-c...@googlegroups.com
On Sep 9, 2014, at 11:44 AM, Suresh Joshi <sur...@gmail.com> wrote:

Hi all, I noticed in iOS, there is a contentUrl for an attachment and there doesn't seem to be a publicly used analogy in the Android world. In the CBL code, I see there is a database table used to store the attachment blob location with the SHA-1 key, but it's not publicly accessible. 

Yes, and I don't recall the reason that the URL accessor wasn't made part of the cross-platform API. I think it was because there are Cocoa APIs for media playback that require a file path for streaming.

 I want to use Picasso to load these images and handle all my caching, but Picasso and OkHttp require a URL to hit with cache-control values set.

I don't develop for Android so I don't know what Picasso or OkHttp are. Are these for downloading over HTTP? The attachments in your local database are already on the filesystem so they don't need to be downloaded.

I wanted to write a custom 'downloader' for Picasso, where I would just pull an inputSteam from a file pointer

There's already an Attachment method to get an InputStream; will that do?

—Jens

Suresh Joshi

unread,
Sep 9, 2014, 3:25:44 PM9/9/14
to mobile-c...@googlegroups.com
Hi Jens


On Tuesday, September 9, 2014 3:01:59 PM UTC-4, Jens Alfke wrote:

On Sep 9, 2014, at 11:44 AM, Suresh Joshi <sur...@gmail.com> wrote:

Hi all, I noticed in iOS, there is a contentUrl for an attachment and there doesn't seem to be a publicly used analogy in the Android world. In the CBL code, I see there is a database table used to store the attachment blob location with the SHA-1 key, but it's not publicly accessible. 

Yes, and I don't recall the reason that the URL accessor wasn't made part of the cross-platform API. I think it was because there are Cocoa APIs for media playback that require a file path for streaming.

 
 I want to use Picasso to load these images and handle all my caching, but Picasso and OkHttp require a URL to hit with cache-control values set.

I don't develop for Android so I don't know what Picasso or OkHttp are. Are these for downloading over HTTP? The attachments in your local database are already on the filesystem so they don't need to be downloaded.

Picasso is an image loading/smart caching library (something like FastImageCache for iOS). OkHttp is a HTTP protocol library, that Picasso uses internally. I'm trying to override OkHttp to point at the filesystem instead of a web URL (there aren't too many other ways to customize how Picasso works)


I wanted to write a custom 'downloader' for Picasso, where I would just pull an inputSteam from a file pointer

There's already an Attachment method to get an InputStream; will that do?

I tried doing something like this in the past, however, it means having my HTTP protocol know about my Couchbase database, and I was having dependency injection issues with this, because of how the rest of the app is set-up. I could probably hack something together again, but it really is a hack. That's why I wanted to go the route of pulling file blobs, as I think that would be a lot cleaner in the app's sense (this all stems from having to alter several 3rd party libraries, and trying to stay within each's paradigms).
 

—Jens

Jens Alfke

unread,
Sep 9, 2014, 3:35:50 PM9/9/14
to mobile-c...@googlegroups.com

On Sep 9, 2014, at 12:25 PM, Suresh Joshi <sur...@gmail.com> wrote:

Picasso is an image loading/smart caching library (something like FastImageCache for iOS). OkHttp is a HTTP protocol library, that Picasso uses internally. I'm trying to override OkHttp to point at the filesystem instead of a web URL (there aren't too many other ways to customize how Picasso works)

Hm. But the images are already downloaded. Are you trying to get them into Picasso just because the rest of your app is hardwired to go through Picasso to access resources? If so, could you abstract that to a custom interface, and have the implementation call either Picasso or CBL?

—Jens

Suresh Joshi

unread,
Sep 9, 2014, 3:41:54 PM9/9/14
to mobile-c...@googlegroups.com
I was debating using a custom interface that routes appropriately, however, that might mean I would need a separate image caching handler (this all stems from possible memory issues of our app when handling images, Picasso deals with images really well, which is why I want all my images loaded into memory through Picasso). 

From what I've read, ideally Picasso is a singleton, and now I'm just determining if you can change 'downloaders' on the fly. If so, then this whole thread might become moot! (I really hope)

Suresh Joshi

unread,
Sep 15, 2014, 6:41:00 PM9/15/14
to mobile-c...@googlegroups.com
Hey Jens, I came up with a little workaround. 

It's not great, but I'll put it up here in case anyone else runs into this kind of problem on CBAndroid and Picasso. For any other users, they would need to inject any more information about their setup (e.g. in my actual code, I retro-fitted the Uri to actually contain docId and attachment name, but I'm ignoring that code for now).


public class CouchbaseDownloader implements Downloader {

  private Database database;

  public CouchbaseDownloader(Database database) {
    this.database = database;
  }

  @Override
  public Response load(Uri uri, boolean localCacheOnly) throws IOException {
    try {
      Attachment image = database.getDocument(uri.toString()).getCurrentRevision().getAttachment("image");
      InputStream stream = image.getContent();
      return new Response(stream, true, image.getLength());
    } catch (CouchbaseLiteException e) {
      e.printStackTrace();
    }
    return null;
  }
}


I also created a singleton wrapper for Picasso - this is strictly due to how this app is currently structured, and where the Database becomes available. Ideally, using Dagger, you could inject this in a base module, but I'm stuck with this wrapper solution until I can get around to a re-factoring...

public class CBPicasso {

  private static Picasso singleton = null;

  // Using the same fluent API call as Picasso proper
  public static Picasso with(Context context, Database database) {
    if (singleton == null) {
      synchronized (CBPicasso.class) {
        if (singleton == null) {
          singleton = new Picasso
                  .Builder(context)
                  .downloader(new CouchbaseDownloader(database))
                  .build();
        }
      }
    }
    return singleton;
  }
}
Reply all
Reply to author
Forward
0 new messages