質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.37%

  • Xamarin

    658questions

    Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Cropした画像をListViewに貼ると強制終了してしまう

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 982

otaota

score 24

前提・実現したいこと

画像の部分表示がしたい
はおかげさまで無事解決しました。ありがとうございます。

普通のImageの代わりとして表示する時は特に問題が出なかったのですが、ListViewの各セルの中に表示しようとしたときに、新たな問題が発生してしまいました。

やりたいこととしては、ListViewのCustomCellの中にCropした画像を表示したいということになります。アドバイスよろしくお願いします。

発生している問題・エラーメッセージ

iOSとAndroidで微妙に症状が異なります。
まず、ListViewを使ったページに遷移した直後はどちらも期待通りの表示がなされています。
Androidではこの状態から1セル分上にスクロールするだけ(見えていなかった最初のセルが表示されるところ?)で強制終了してしまいます。iOSの方は上方向のスクロールは一番下まで問題がなく見ることができますが、途中で下にスクロールしようとしたときに、画面上部に消えたセルが再表示されるところで同じように強制終了してしまいます。

エラーメッセージ

[Androidの場合]:
System.ObjectDisposedException
Cannot access a closed Stream.
というウィンドウが表示されますが、Stacktraceは空になっています。

アプリケーション出力の中に
The application may be doing too much work on its main thread
というメッセージが出力されています。

[iOSの場合]:
System.ArgumentNullExceptionがスローされました
Value cannot be null.
Parameter name: data

このときのStacktraceには
xxxx.iOS.Application.Main(System.String[] args)
だけ表示されています。

該当のソースコード

    public class TestPage : ContentPage
    {
        class Data
        {
            public string Image { get; set; }
        }

        public TestPage()
        {
            var ar = new List<Data>();
            foreach (var n in Enumerable.Range(0, 20))
            {
                ar.Add(new Data
                {
                    Image = "ネット上の画像のURL",//全セル同じ画像でテスト
                });
            }
            var listView = new ListView
            {
                ItemsSource = ar,
            };

            listView.ItemTemplate = new DataTemplate(() =>
            {
                var image = new Image();
                image.SetBinding(Image.SourceProperty, "Image");
////////////// ここから
                image.BindingContextChanged += (sender, e) =>
                {
                    base.OnBindingContextChanged();
                    var img = (Image)sender;
                    var imgSrc = (UriImageSource)img.Source;
                    var uri = imgSrc.Uri.ToString();
                    System.Diagnostics.Debug.WriteLine(uri);

                    var data = DependencyService.Get<IImage>().Read(uri);
                    Stream stream = new MemoryStream(data);
                    image.Source = ImageSource.FromStream(() => { return stream; });
                };
////////////// ここまで

                return new ViewCell
                {
                    View = new StackLayout
                    {
                        Padding = new Thickness(20, 10, 20, 10),
                        Spacing = 10,

                        Orientation = StackOrientation.Horizontal,

                        Children = {
                            image,
                        },
                    },
                };
            });

            Content = listView;
        }
    }


※Android/iOS個別処理のところのソースはこちらを参照

試したこと

ここから〜ここまでで挟んだ部分がCropした画像を貼り付ける処理になります。(このやり方自体もわからなかったのですが、https://forums.xamarin.com/discussion/23049/how-to-show-images-from-a-list-base64-encoded-stringを参考にしました)
問題が起こる動作をする前にここにBreakPointを仕掛けても引っかからないことは確認しています。
ここをコメントアウトした場合も問題なく動作することを確認しています。

追記:

                    var data = DependencyService.Get<IImage>().Read(uri);
                    Stream stream = new MemoryStream(data);
                    image.Source = ImageSource.FromStream(() => { return stream; });
                    image.Source = ImageSource.FromUri(new Uri(uri));


と変えた場合は問題がおきませんでした(cropはされませんが)
また、iOS版のエラーメッセージの中に
Parameter name: data
とあるので、ここのdataという変数名を別のものに書き換えたのですが、エラーメッセージは同じままでした。
あと、dataをクラスのメンバー変数にして消えないようにしても、症状は変わりませんでした。

補足情報(言語/FW/ツール等のバージョンなど)

Xamarin 6.2(build 1829)   
Mac Note Pro   
OS X Yosemite(10.10.5)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

自己解決しました。

Androidの方の
Cannot access a closed Stream. 
というエラーメッセージを手掛かりに

                    var data = DependencyService.Get<IImage>().Read(uri);
                    Stream stream = new MemoryStream(data);
                    image.Source = ImageSource.FromStream(() => { return stream; }


と書いていたところを

                    var data = DependencyService.Get<IImage>().Read(uri);
                    image.Source = ImageSource.FromStream(() => { 
                        Stream stream = new MemoryStream(data);
                        return stream;
                    }


とすることで動くようになりました。

本当に正しいかはよくわからないので、もうしばらく未解決のままにしておき、少し待って特にコメントなければ解決済みに変更しようとおもいます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

IImageの実装クラスを見てみないと何とも言いきれない部分がありますが、おそらく通信や画像処理をUIスレッドで処理されているあたりに問題がありそうです。

Androidの例外は、UIスレッドを一定時間以上待たせすぎていることが原因です。
画像の取得やクロッピングはバックグラウンドで実施して、クロップした画像ができてからUIスレッドに処理を戻して設定するという手順が必要になると思います。

iOS側も類似の問題な気がしますが、先にも書いた通りIImageの実装が見れないと、ちょっとそれ以上は分かりそうにありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/16 13:37

    回答ありがとうございます。
    IImageは「発生している問題・エラーメッセージ」の一番下のリンクから辿れるのですが、
    そちらからわかりますでしょうか?

    キャンセル

  • 2017/04/16 15:23

    iOS側は上のコードとリンク先のコードを利用して動かしたら動作はしましたよ。
    エミュレーター上でですが。ちゃんと縦が上半分だけ表示されているようです。
    Androidは試していません。
    なんにせよ、iOSもAndroidもネットワーク通信はUIスレッドで実行せずバックグラウンドでやるべきなので、まずはそれを修正してみたらどうでしょう?
    通信、画像のクロップ、表示のそれぞれは動いています。

    キャンセル

  • 2017/04/20 15:54

    すいません。コメント見落としていました。
    こちらではエミュレーターでも100%出てしまいます。

    なんとか自己解決はしたので、記載しておきました。
    iOS版はあまり気にならなかったのですが、Android版は新しい画像を読み込むときにぎこちないので、確かに改良の余地はありそうです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Xamarin

    658questions

    Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。