Xamarin Android Async Crash(无日志记录)

时间:2018-12-21 06:10:16

标签: c# xamarin xamarin.forms xamarin.android async-await

我有一个异步下载程序,该下载程序从网络上将大量资源下载到Xamarin Android表单应用程序。我要下载的代码如下:

public interface IAnimationDownloadCallbacks
    {
        void DidFinishDownload(StoreItemAnimation itemAnimation, string downloadedUrl, bool downloadResult);
    }


    public async Task<bool> DownloadAnimationFromUrl(string url, StoreItemAnimation storeItem = null, IAnimationDownloadCallbacks callbacks = null)
    {
        App.Log("Downloading : " + url);

        if (String.IsNullOrEmpty(url) || url.Contains("/") == false)
        {
            if (callbacks != null)
                callbacks.DidFinishDownload(storeItem, url, false);
            return false;
        }

        IFolder folder = FileSystem.Current.LocalStorage;

        var filename = GetFileName(url);

        folder = await folder.CreateFolderAsync("Cache", CreationCollisionOption.OpenIfExists);

        ExistenceCheckResult fileExists = await folder.CheckExistsAsync(filename);

        if (fileExists == ExistenceCheckResult.FileExists)
        {
            App.Log("Skipping, already downloaded.");
            if (callbacks != null)
                callbacks.DidFinishDownload(storeItem, url, true);
            return true;
        }
        else
        {
            try
            {
                App.Log("waiting to download... " + url);

                App.Log("started... " + url);
                bool didCopy = false;
                if (Device.RuntimePlatform == Device.iOS)
                {
                    using (var wc = new HttpClient(new HttpClientHandler()))
                    {
                        var imageData = await wc.GetStreamAsync(url);
                        App.Log("Length: " + imageData.Length.ToString());
                        IFile file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
                        using (Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
                        {
                             await imageData.CopyToAsync(stream);
                            //stream.TryDispose();

                            App.Log("Done writing : " + filename + " url: " + url);
                            if(callbacks!=null)
                            callbacks.DidFinishDownload(storeItem, url, true);
                            return true;
                        }
                    }
                }
                else
                {

                    using (var stream = await ImageService.Instance.LoadUrl(url).AsPNGStreamAsync())
                    {
                        App.Log("Length: " + stream.Length.ToString());
                        IFile file = await folder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
                        using (Stream streams = await file.OpenAsync(FileAccess.ReadAndWrite))
                        {
                            await stream.CopyToAsync(streams);
                            didCopy = true;
                            //streams.TryDispose();
                        }
                        //stream.TryDispose();
                    }
                }

                App.Log("(DidCopy: "+didCopy+")Done writing : " + filename + " url: " + url);
                if (callbacks != null)
                    callbacks.DidFinishDownload(storeItem, url, true);
                return true;
            }
            catch (Exception error)
            {
                App.Log(error.Message);
                App.Log("Delete file");

                ExistenceCheckResult isFileExists = await folder.CheckExistsAsync(filename);
                if (isFileExists == ExistenceCheckResult.FileExists)
                {
                    App.Log("File found");
                    IFile file = await folder.GetFileAsync(filename);
                    await file.DeleteAsync();
                }
                if (callbacks != null)
                    callbacks.DidFinishDownload(storeItem, url, false);
                return false;
            }
        }
    }

现在,我想一次下载多个资源(我尝试同时进行所有下载),所以我一次创建了八个资源的批量下载。现在,我不知道为什么我的应用程序崩溃而没有日志,异常或任何其他原因。我研究发现,这可能是由于ANR引起的,但我似乎找不到它在我的应用程序中造成瓶颈。这是批量下载的代码:

public class BatchQueueAnimationDownload: ImageCache.IAnimationDownloadCallbacks
{

    /*
     * 
     * Declare Batch download callbacks 
     * that will be used to reference the calling class
     * of this instance        
     */
    public interface BatchQueueDownloadCallbacks
    {
        void OnNewItemDownloaded(StoreItemAnimation itemAnimation, string downloadedUrl, bool downloadResult);
        void OnAllQueueCompleted(int queueSize);
    }
    /*
     * Size of maximum simultaneous downloads
     */
    private readonly int BATCH_SIZE = 8;

    /*
     * Counter for current simultaneous downloads
     */
    private int currentDownloadsCount = 0;

    /*
     * Counter for currently completed downloads
     */
    private int completedDownloadsCount = 0;

    /*
     *  Indexer to keep track of last queued download
     */
    private int lastQueuedIndex = 0;

    /*
     * Batch download callback declaration, this will be assigned 
     * when an instance of this class is invoked or if a queue
     * of downloads are added see #{AddDownload(...) method}
     */
    BatchQueueDownloadCallbacks callbacks;

    /*
     *  Flag to switch when all queued downloads are completed.
     * true = all downloads are completed
     * false = when a new queue is initiated {see #Reset() method}
     */
    bool isCompleted = false;

    /*
     *  List collection of all downloads in queue. All downloads/downloadables 
     *  are in this list.        
     */
    ObservableCollection<DownloadQueue> downloadQueue = new ObservableCollection<DownloadQueue>();

    /*
     *  static reference of this class. Only one instance of this class
     *  would be running.        
     */
    static BatchQueueAnimationDownload instance;

    /*
     *  Instance property, initialize an instance if not yet
     *  otherwise, return the current instance to invoking class
     * 
     */
    public static BatchQueueAnimationDownload GetInstance {
      get  {
            if (instance == null)
                instance = new BatchQueueAnimationDownload();
            return instance;
        }
    }

    /*
     *  Method that will accept addition to the 
     *  download queue. Once added, that queue becomes available for
     *  download.
     * 
     *  item = The reference to the StoreItemAnimation object so
     *          that we'll be able to determine which StoreAnimationItem
     *          is being downloaded.
     *  downloadUrl = the url that will be called for download. It can be 
     *          either url_android or url_android2 of the StoreItemAnimation instance.
     *  callbacks = Implementing class which invokes this instance, by default 
     *          it is this class itself.
     */
    public void AddDownload(StoreItemAnimation item, string downloadUrl, BatchQueueDownloadCallbacks callbacks)
    {
        DownloadQueue q = new DownloadQueue(item, downloadUrl, this);
        downloadQueue.Add(q);
        this.callbacks = callbacks;

        //StartDownload(q);

    }
    /*
     *  Invoke this class once all queues have been added. 
     *  This starts the actual batch downloads itself.        
     */
    public void Start()
    {
        Reset();
        if(downloadQueue.Count>0){

            /*
             * Download 1st batch
             */
            while(currentDownloadsCount < BATCH_SIZE && downloadQueue.Count > lastQueuedIndex){
                StartDownload(downloadQueue[lastQueuedIndex]);
            }
        }
    }

    /*
     *  Individual downloads for each
     *  queued download items. 
     * 
     *  queue = the queue item that will be downloaded        
     */

    void StartDownload(DownloadQueue queue)
    {

        App.Log("Current Simultaneous Download: " + currentDownloadsCount + " of " + BATCH_SIZE + " Complete:" + completedDownloadsCount);

        if ((callbacks != null) && (queue == null))
        {
            callbacks.OnAllQueueCompleted(downloadQueue.Count);
            isCompleted = true;
            return;
        }
        /*
         * Check if current simultaneous download is already maxed out (BATCH_SIZE)
         * and if the download queue is already started downloading
         */           
        if (currentDownloadsCount < BATCH_SIZE )
        {


            /*
             *  Check if downloads already completed entire queue
             */
            if (completedDownloadsCount >= downloadQueue.Count )
            {
                /*
                 *  If so, invoke the invoking class' <i>completed<i> callback
                 */
                if(callbacks != null)
                    callbacks.OnAllQueueCompleted(downloadQueue.Count);

                return;

            }

            /*
             *  Check if the queue counter is greater than the
             *  actual size of the queue. Not doing so will fire
             *  IndexOutOfBoundsException or Exception in general.
             */
            if (lastQueuedIndex < downloadQueue.Count)
            {
                ImageCache.GetInstance.DownloadAnimationFromUrl(queue.url, queue.item, queue.callbacks);

                /*
                 *  Increment the current simultanous downloads.
                 *  This is decremented on completion of each download.                    
                 */
                currentDownloadsCount++;

                /*
                 * Increment the counter for the queued downloads.                   
                 */                   
                lastQueuedIndex++;
            }
            /*
             *  When the queue counter is equal to the
             *  queue size, it means that all queues have 
             *  been downloaded.
             */
            else
            {
                if (callbacks != null)
                    callbacks.OnAllQueueCompleted(downloadQueue.Count);
            }
        }
    }

    public void DidFinishDownload(StoreItemAnimation itemAnimation, string downloadedUrl, bool downloadResult)
    {
        if (this.callbacks != null)
            this.callbacks.OnNewItemDownloaded(itemAnimation, downloadedUrl, downloadResult);

        //GC.Collect(0, GCCollectionMode.Optimized, false);
        /*
         * Empty Batch slot, available for download use
         */
        currentDownloadsCount--;

        /*
         * Increment completed download 
         */
        completedDownloadsCount++;

        /*
         * Start download for next in queue if any
         */
        if (lastQueuedIndex < downloadQueue.Count)
        {
            StartDownload(downloadQueue[lastQueuedIndex]);
        }
        else
        {
            if (!isCompleted)
            {
                isCompleted = true;
                callbacks.OnAllQueueCompleted(downloadQueue.Count);
            }
        }
    }

    public void Reset()
    {

        App.Log("RESET! "+currentDownloadsCount+"/"+completedDownloadsCount+"/"+lastQueuedIndex+"/"+instance);
        currentDownloadsCount = 0;
        completedDownloadsCount = 0;
        lastQueuedIndex = 0;
        isCompleted = false;

    }

}

class DownloadQueue
{
    public StoreItemAnimation item;
    public string url;
    public ImageCache.IAnimationDownloadCallbacks callbacks;
    public DownloadQueue(StoreItemAnimation item, string url, ImageCache.IAnimationDownloadCallbacks callbacks)
    {
        this.item = item;
        this.url = url;
        this.callbacks = callbacks;
    }
}

任何帮助将不胜感激。预先谢谢你。

更新 这仅在Android API 23上发生(据我测试)。

如果有帮助的话,这是崩溃时的日志,我认为没有什么帮助。device log

0 个答案:

没有答案