I'm consistently receiving multi-threading issues when downloading a list of gifs from giphy.com. Each time my app crashes and logs a "I/Choreographer(15955): Skipped 104 frames! The application may be doing too much work on its main thread." type error. I haven't come across any threading solutions for flutter. Here is my code...
Future<Null> giphy() async {
var _searchterm = _searchController.text.toString().replaceAll(' ', '+');
String url = GIPHY.com;
//var httpClient = createHttpClient();
var response = await http.get(url);
Map data = json.decode(response.body);
//print(data['data']);
var gifs = new List();
for (var items in data['data']) {
var images = (items['images'] as Map);
var downsized = (images['downsized'] as Map);
var urls = downsized['url'].toString();
gifs.add(urls);
}
setState(() => giphyUrls = gifs);
_neverSatisfied();
}
giphyUrls is a public list that feeds into a gridview builder.
Related
I'm new to Xamarin. I'm trying display a list of downloaded images. I am downloading images from an APP API on Azure, where I stored the file on Azure Storage.
My server code is the following:
public HttpResponseMessage Get(string PK, string RK)
{
//Creating CloudBlockBlolb...
byte[] bytes = new byte[blockBlob.Properties.Length]
for(int i = 0; i < blockBlob.Properties.Length; i++){
bytes[i] = 0x20;
}
blockBlob.DownloadToByteArray(bytes, 0);
HttpResponseMessage resp = new HttpResponseMessage(HttpStatusCode.OK);
resp.Content = new ByteArrayContent(bytes);
resp.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpg");
return resp;
}
My Xamarin code is the following:
public MainPage ()
{
//...
List<PicturePost> list = new List<PicturePost>{
new PicturePost("title", "subtitle", "link/api/Pictures?PK=xxx&RK=yyy")
};
InitializeComponent ();
listView.ItemTemplate = new DataTemplate (typeof(CustomImageCell));
listView.HasUnevenRows = true;
listView.ItemsSource = list;
//...
}
And here is the relevant code for CustomImageCell:
var image = new Image ();
image.SetBinding (Image.SourceProperty, "image");
//...
horizontalLayout.Children.Add (image);
I know that my API call works, because when I test it on the browser, it returns the image. I also know that if I use any random links such as http://www.natureasia.com/common/img/splash/thailand.jpg the image is downloaded and displayed properly. It is only when I use the API link that it doesn't seem to be working. Can someone tell me what I am doing wrong?
so in my public MainPage(), I added the following:
listView.BeginRefresh ();
listView.EndRefresh ();
I realized at some point that the images would take some time to download. I assume that when the listView was created, the images were not finished downloading, so I added the code above... Pretty sure this is not the best way to do this (probably an await would be better, but I don't know where).
I want to post some request values alongside the multipart-formdata file contents. In the old API you could use PostFileWithRequest:
[Test]
public void Can_POST_upload_file_using_ServiceClient_with_request()
{
IServiceClient client = new JsonServiceClient(ListeningOn);
var uploadFile = new FileInfo("~/TestExistingDir/upload.html".MapProjectPath());
var request = new FileUpload{CustomerId = 123, CustomerName = "Foo"};
var response = client.PostFileWithRequest<FileUploadResponse>(ListeningOn + "/fileuploads", uploadFile, request);
var expectedContents = new StreamReader(uploadFile.OpenRead()).ReadToEnd();
Assert.That(response.FileName, Is.EqualTo(uploadFile.Name));
Assert.That(response.ContentLength, Is.EqualTo(uploadFile.Length));
Assert.That(response.Contents, Is.EqualTo(expectedContents));
Assert.That(response.CustomerName, Is.EqualTo("Foo"));
Assert.That(response.CustomerId, Is.EqualTo(123));
}
I can't find any such method in the new API, nor any overrides on client.Post() which suggest that this is still possible. Does anyone know if this is a feature that was dropped?
Update
As #Mythz points out, the feature wasn't dropped. I had made the mistake of not casting the client:
private IRestClient CreateRestClient()
{
return new JsonServiceClient(WebServiceHostUrl);
}
[Test]
public void Can_WebRequest_POST_upload_binary_file_to_save_new_file()
{
var restClient = (JsonServiceClient)CreateRestClient(); // this cast was missing
var fileToUpload = new FileInfo(#"D:/test/test.avi");
var beforeHash = this.Hash(fileToUpload);
var response = restClient.PostFileWithRequest<FilesResponse>("files/UploadedFiles/", fileToUpload, new TestRequest() { Echo = "Test"});
var uploadedFile = new FileInfo(FilesRootDir + "UploadedFiles/test.avi");
var afterHash = this.Hash(uploadedFile);
Assert.That(beforeHas, Is.EqualTo(afterHash));
}
private string Hash(FileInfo file)
{
using (var md5 = MD5.Create())
{
using (var stream = file.OpenRead())
{
var bytes = md5.ComputeHash(stream);
return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", "").ToLower();
}
}
}
None of the old API was removed from the C# Service Clients, only new API's were added.
The way you process an uploaded file inside a service also hasn't changed.
I have a list, that has three fields: Title, PublishingRollupImage and Description.
I want to upload the image to the library SiteCollectionImages and reference it on the list.
I'm able to upload the file to the folder SiteCollectionImages, and get it's url.
I'm also able to insert the item in the list "MyList", but the PublishingRolloutImage won't persist after the Update() method. I already tried to set the constructor for the ImageFieldValue, like this:
new ImageFieldValue("<img src='test.jpg' />");
but it didn't work.
Here's my code:
using (var site = new SPSite(SPContext.Current.Site.ID))
using (var web = site.OpenWeb())
{
var folder = web.GetFolder("SiteCollectionImages");
var file = folder.Files.Add(fileName, file, true);
folder.Update();
var list = web.Lists["MyList"];
var item = list.Items.Add();
item["Title"] = "MyItemTitle";
item["PublishingRollupImage"] = new ImageFieldValue { ImageUrl = file.Url };
item["Description"] = "MyDescription";
item.Update();
}
What i'm doing wrong?
After a lot of trial and error, i found out that i was doing two things wrong:
this:
item["PublishingRollupImage"] = new ImageFieldValue { ImageUrl = file.Url };
was supposed to be like this:
var image = item["PublishingRollupImage"] as ImageFieldValue ?? new ImageFieldValue();
image.ImageUrl = String.Format("/{0}", file.Url);
item["PublishingRollupImage"] = image;
and file.Url needs to start with a slash. If it doesn't start with a slash, it will break after the Update(); method. That's the reason for the String.Format up there.
When my images are being loaded from my database on my web server, I see the following error:
A generic error occurred in GDI+. at
System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder,
EncoderParameters encoderParams) at
System.Drawing.Image.Save(Stream stream, ImageFormat format) at
MyWeb.Helpers.ImageHandler.ProcessRequest(HttpContext context)
All my code is attempting to do is load the image, can anybody take a look and let me know what I'm doing wrong?
Note - This works if I test it on my local machine, but not when I deploy it to my web server.
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
if (!String.IsNullOrEmpty(context.Request.QueryString["imageid"]))
{
int imageID = Convert.ToInt32(context.Request.QueryString["imageid"]);
int isThumbnail = Convert.ToInt32(context.Request.QueryString["thumbnail"]);
// Retrieve this image from the database
Image image = GetImage(imageID);
// Make it a thumbmail if requested
if (isThumbnail == 1)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
image = image.GetThumbnailImage(200, 200, myCallback, IntPtr.Zero);
}
context.Response.ContentType = "image/png";
// Save the image to the OutputStream
image.Save(context.Response.OutputStream, ImageFormat.Png);
}
else
{
context.Response.ContentType = "text/html";
context.Response.Write("<p>Error: Image ID is not valid - image may have been deleted from the database.</p>");
}
}
The error occurs on the line:
image.Save(context.Response.OutputStream, ImageFormat.Png);
UPDATE
I've changed my code to this, bit the issue still happens:
var db = new MyWebEntities();
var screenshotData = (from screenshots in db.screenshots
where screenshots.id == imageID
select new ImageModel
{
ID = screenshots.id,
Language = screenshots.language,
ScreenshotByte = screenshots.screen_shot,
ProjectID = screenshots.projects_ID
});
foreach (ImageModel info in screenshotData)
{
using (MemoryStream ms = new MemoryStream(info.ScreenshotByte))
{
Image image = Image.FromStream(ms);
// Make it a thumbmail if requested
if (isThumbnail == 1)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
image = image.GetThumbnailImage(200, 200, myCallback, IntPtr.Zero);
}
context.Response.ContentType = "image/png";
// Save the image to the OutputStream
image.Save(context.Response.OutputStream, ImageFormat.Png);
} }
Thanks.
Probably for the same reason that this guy was having problems - because the for a lifetime of an Image constructed from a Stream, the stream must not be destroyed.
So if your GetImage function constructs the returned image from a stream (e.g. a MemoryStream) and then closes the stream before returning the image then the above will fail. My guess is that your GetImage looks a tad like this:
Image GetImage(int id)
{
byte[] data = // Get data from database
using (MemoryStream stream = new MemoryStream(data))
{
return Image.FromStream(data);
}
}
If this is the case then try having GetImage return the MemoryStream (or possibly the byte array) directrly so that you can create the Image instance in your ProcessRequest method and dispose of the stream only when the processing of that image has completed.
This is mentioned in the documentation but its kind of in the small print.
I'm playing with MonoTouch.Dialog and written some code to show some tweets. The problem is that the table cells are too small and the cells are all bunched up when I load the StyledMultilineElements asynchronously. They look absolutely perfect when I load them synchronously (i.e. without the QueueUserWorkItem/InvokeOnMainThread part)
Is there a way of getting the table cells to recalculate their height?
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window.AddSubview(navigation.View);
var tweetsSection = new Section("MonoTouch Tweets"){
new StringElement("Loading...") //placeholder
};
var menu = new RootElement("Demos"){
tweetsSection,
};
var dv = new DialogViewController(menu) { Autorotate = true };
navigation.PushViewController(dv, true);
window.MakeKeyAndVisible();
// Load tweets async
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
ThreadPool.QueueUserWorkItem(delegate {
var doc = XDocument.Load("http://search.twitter.com/search.atom?q=%23MonoTouch");
var atom = (XNamespace)"http://www.w3.org/2005/Atom";
var tweets =
from node in doc.Root.Descendants(atom + "entry")
select new {
Author = node.Element(atom + "author").Element(atom + "name").Value,
Text = node.Element(atom + "title").Value
};
var newElements =
from tweet in tweets
select new StyledMultilineElement(
tweet.Author,
tweet.Text);
InvokeOnMainThread(delegate {
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = false;
tweetsSection.Remove(0);
tweetsSection.Add(newElements.Cast<Element>().ToList());
});
});
return true;
}
Try setting the UnevenRows property on your top level Root element of your Dialog View Controller, in this case "menu":
menu.UnevenRows = true