27590


Androidアプリを制作しています。  
やろうとしていることは、Androidアプリからサーバー(PHP)にアクセスして、そこからConoHaのオブジェクトストレージにアクセスして画像を読み込むという流れになります。

AndroidではGridViewを使用し、写真を格子状に複数枚並べる仕様です。  
本来でしたらGridViewを開くと、写真がある分だけ読み込み表示されるはずなのですが、例えば10枚写真があるとすれば6枚くらいしかダウンロードがされません。

Android側では下記のようなエラーが表示されています。

[code]

    error: cz.msebera.android.httpclient.client.HttpResponseException: Content-Type (text/html; charset=UTF-8) not allowed!
    binaryData: null
    statusCode: 500
    
[/code]

以下がPHPファイルになります。  
※簡潔に書いています。

[code]

    if(isset($_POST['USER_ID']) && isset($_POST['FILE_NAME'])){
    
        $user_id = $_POST['USER_ID'];
        $file_name = $_POST['FILE_NAME'];
    
        $client = new OpenStack(
                'https://*******',
                array(
                    'tenantName' => TENANT_NAME,
                    'username' => USERNAME,
                    'password' => PASSWORD
                )
            );
    
         $client->authenticate();
         $service = $client->objectStoreService('Object Storage Service', 'tyo1');
         $container = $service->getContainer($user_id);
         $object = $container->getObject($file_name);
         $object_content = $object->getContent();
         $object_content->rewind();
         $stream = $object_content->getStream();
         $photo = stream_get_contents($stream);
    
         header('Content-Type: image/jpeg');
         echo $photo;
    }
    
[/code]

下記はAndroid側になります。  
※簡潔に書いています。

[code]

    RequestParams params = new RequestParams();
    params.put("USER_ID", id);
    params.put("FILE_NAME", fileName);
    
    String[] allowedContentTypes = new String[] { "image/jpeg" };
    client.post("http://*******", params, new BinaryHttpResponseHandler(allowedContentTypes) {
        @Override
        public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {
    
            Bitmap bmp = getDecodeByteToBitmap(binaryData);
            mImageView.setImageBitmap(bmp);
        }
    
        @Override
        public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {
            Log.v(TAG, "error: " + error + " binaryData: " + binaryData);
            Log.v(TAG,"statusCode: " + statusCode");
        }
    });
    
[/code]

ちなみにPHP内だけで実行してみますと、ちゃんとすべての写真データを取得できています。  
これはGridViewに表示される枚数分に連続アクセスして、バイナリデータの通信処理が間に合わなくてエラーとかになっているのでしょうか？

どなたか解決策などありましたらぜひご教授お願いいたします。

CentOS7.2  
PHP 5.6

ーーーー追記ですーーーー  
ちなみにConoHaオブジェクトストレージを使用する前は、ふつうにサーバーにフォルダを置いてそこに画像を保存していました。そのときは問題なくすべてダウンロードできていました。  
これが直接的に関係するのか分かりませんが、思い出しましたので追記しておきます。  
それと画像読み込みはBaseAdapter内で行っています。

ーーーー追記ですーーーー  
Android側の画像読み込むところに「onStart」を追加して、「onSuccess」「onFailure」と各場所にデバッグしてみました。結果は下記になります。

[code]

    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.531 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.532 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.533 19134-19134/com.roid.*****  D/GridAdapter: start
    07-12 19:30:46.860 19134-19134/com.roid.*****  D/GridAdapter: Failure-finish
    07-12 19:30:46.926 19134-19134/com.roid.*****  D/GridAdapter: Failure-finish
    07-12 19:30:46.943 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:47.017 19134-19134/com.roid.*****  D/GridAdapter: Failure-finish
    07-12 19:30:47.059 19134-19134/com.roid.*****  D/GridAdapter: Failure-finish
    07-12 19:30:47.204 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:47.617 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:47.863 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:48.311 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:48.552 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:48.868 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:49.200 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:49.577 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    07-12 19:30:49.912 19134-19134/com.roid.*****  D/GridAdapter: Success-finish
    
[/code]


CC BY-SA 3.0
2016-07-12T03:53:31.813
27552
2016-07-13T03:37:22.773
2016-07-12T10:45:23.810
16955
16955
question
android php
Androidからサーバー(PHP)にアクセスし複数画像をリクエストすると全部返ってこない

[code]

    String[] allowedContentTypes = new String[] { "image/jpeg" };
    
[/code]

の部分でダウンロードする情報の対象をJPEGファイルのみに制限していますね。  
エラーメッセージを見たところ、ダウンロードされたコンテンツのコンテントタイプが「text/html」だからダウンロード出来なかったと言っているようです。  
text/htmlも許可して、ダウンロードされたHTMLの内容を見るとさらにヒントがあるかもしれません。

あと、通信は非同期通信で一気にコネクションオープンしたりしていませんか？  
もしそうであれば、一つオープンしてダウンロードが終わったら次をオープンするようにしてみてください。  
もしかするとAndroidのSDK固有か、ハードウェア固有の同時コネクションのオープンの限界数を超えているのかもしれません。

最近のWEBブラウザは、同時にダウンロードできるリクエスト数が6個であることが多いそうなので、HTTPの制限なのかもしれませんね。


CC BY-SA 3.0
2016-07-12T04:47:15.273
27554
2016-07-12T04:47:15.273
17014
27552
answer


問題の切り分けのために要素番号×0.1秒くらいのディレイを置いて試してもらってもいいですね。  
ただそれだと、通信に長時間かかると同じ事が起こります。

私がやるとすると以下のようにするかと思います。  
Android Javaのコードは久しぶりに書くので、細かい間違いがあると思います。  
ポイントは、一つダウンロードが終わったらコールバックでイベントを返し、nextDownloadで次のダウンロードを開始する点です。  
現状のコードよりダウンロードには時間がかかると思うので、初期表示は読み込み中表示にしておくのも、ユーザーに対してわかりやすいと思います。

[code]

    public interface IDownloadCollback
    {
        virtual void finishDownload(bool isSuccess);
    }
    
    public class AClass extends (mImageViewのクラス)
    {
        private String targetUri;
    
        public AClass(String uri)
        {
            this.targetUri = uri;
    
            (画像の上にくるくる回るローディングを表示);
        }
    
    
        public void downloadStart(IDownloadCollback collBackInstance)
        {
            RequestParams params = new RequestParams();
            params.put("USER_ID", id);
            params.put("FILE_NAME", fileName);
    
            String[] allowedContentTypes = new String[] { "image/jpeg" };
            client.post(this.targetUri, params, new BinaryHttpResponseHandler(allowedContentTypes) {
                @Override
                public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {
    
                    Bitmap bmp = getDecodeByteToBitmap(binaryData);
                    this.setImageBitmap(bmp);
                    collBackInstance.finishDownload(true);
                }
    
                @Override
                public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {
                    Log.v(TAG, "error: " + error + " binaryData: " + binaryData);
                    Log.v(TAG,"statusCode: " + statusCode);
                    (ダウンロード失敗画像を表示するなど);
                    collBackInstance.finishDownload(false);
                }
            });
        }
    }
    
    public class GridAdapter extends BaseAdapter implements IDownloadCollback
    {
        private String[] uriArray;
        private Aclass[] imageShowerArray;
        private int downloadIndex = 0;
    
    
        public GridAdapter()
        {
            uriArray = new String[xx];
            imageShowerArray = new Aclass[xx];
            uriArray[0] = "画像のURI";
            .
            .
            .
        }
    
        public View getView(int position, View convertView, ViewGroup parent)
        {
            AClass oneImage = new AClass(uriArray[position]);
    
            imageShowerArray[position] = oneImage;
    
            (グリッド上にoneImageを表示);
        }
    
        public void downloadStartAll()
        {
            nextDownloadStart();
        }
    
        public void nextDownloadStart()
        {
            if(imageShowerArray.length <= downloadIndex)//全てダウンロードが終わったら終了
            {
                return;
            }
    
            Aclass oneImage = imageShowerArray[downloadIndex];
            oneImage.downloadStart(this);
            downloadIndex++;
        }
    
        public finishDownload(bool isSuccess)
        {
            //次のダウンロードを開始する
            nextDownloadStart();//Point
        }
    }
    
    public class OneActivity extends Activity 
    {
        private GridAdapter adapter;
    
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
    
            this.adapter = new GridAdapter();
    
            (グリッドの初期化など);
        }
    
        protected void onStart()
        {
            this.adapter.downloadStartAll();
        }
    }
    
[/code]

画像の数があまりに多いとコールスタックがオーバーフローするかもしれません。  
100枚程度では落ちないとは思いますので、よほどじゃないと大丈夫でしょう。

こんなことするのめんどくさい！もっと楽に！と思われるのでしたら、onFailureが発生したらちょっと待ってから数回リトライでもいいと思います。  
ただし電池は浪費するでしょう。  
リトライ数に制限を設けないと、404やサーバーがダウンした際に無限ループに陥る可能性もあるので注意してください。


CC BY-SA 3.0
2016-07-13T02:52:16.840
27590
2016-07-13T03:37:22.773
2016-07-13T03:37:22.773
17014
17014
27552
answer