2017-08-06 12 views
2

シングルトンクラスを作成し、それにアプリケーションコンテキストを渡すことによって、ネットワーク要求アクティビティを独立させることについてはdocumentationを読んでいます。私はそれを同様に実装しましたが、私はまだ回転すると、アプリケーションはデータを表示する前に呼び出しが完了するのを待っています。だから私は間違っていて、それを正しく設定して、コールがアプリケーションの寿命を延ばすようにして、ドキュメンテーションごとにオリエンテーションを変更するたびに呼び出さないようにします。私はそれがローダまたは改造やokhttpを使用して行うことができます知っているが、私はボレーどのようにボレーリクエストアクティビティをアンドロイドで独立させるのですか?

を使用してMainActivity.java

package com.example.imnobody.photosearch; 

import android.content.Intent; 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.GridView; 
import android.widget.ImageView; 
import android.widget.TextView; 
import android.widget.Toast; 

import com.android.volley.Request; 
import com.android.volley.RequestQueue; 
import com.android.volley.Response; 
import com.android.volley.VolleyError; 
import com.android.volley.toolbox.StringRequest; 
import com.android.volley.toolbox.Volley; 

import java.util.ArrayList; 
import java.util.List; 

public class MainActivity extends AppCompatActivity { 

    private ImageGridAdapter imageGridAdapter; 
    private List<String> imageList; 

    public static final String URL = "API_HERE"; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     imageList = new ArrayList<>(); 
     //imageList = QueryUtils.extractImages(SAMPLE_JSON_RESPONSE); 


     GridView gridView = (GridView) findViewById(R.id.gridview); 
     final TextView emptyTextView = (TextView)findViewById(android.R.id.empty); 
     gridView.setEmptyView(emptyTextView); 

     imageGridAdapter = new ImageGridAdapter(MainActivity.this,imageList); 

     gridView.setAdapter(imageGridAdapter); 

     gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
      @Override 
      public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { 

       Intent intent = new Intent(MainActivity.this,ImageActivity.class); 
       intent.putExtra("imageuri",imageList.get(position)); 
       startActivity(intent); 

      } 
     }); 

     StringRequest stringRequest = new StringRequest(Request.Method.GET, URL, 
       new Response.Listener<String>() { 
        @Override 
        public void onResponse(String response) { 

         imageList = QueryUtils.extractImages(response); //extract needed things from json 
         imageGridAdapter.clear(); 
         imageGridAdapter.addAll(imageList); 

        } 
       }, new Response.ErrorListener() { 
      @Override 
      public void onErrorResponse(VolleyError error) { 

       emptyTextView.setText("Unknown error occured"); 
      } 
     }); 

     VolleySingleton.getInstance(this.getApplicationContext()).addToRequestQueue(stringRequest); 


    } 
} 

VolleySingleton.java

package com.example.imnobody.photosearch; 

import android.content.Context; 
import android.graphics.Bitmap; 

import com.android.volley.Request; 
import com.android.volley.RequestQueue; 
import com.android.volley.toolbox.ImageLoader; 
import com.android.volley.toolbox.Volley; 

import android.support.v4.util.LruCache; 

/** 
* Created by imnobody on 7/8/17. 
*/ 

public class VolleySingleton { 

    private static VolleySingleton mInstance; 
    private RequestQueue mRequestQueue; 
    private ImageLoader mImageLoader; 
    private static Context mCtx; 

    private VolleySingleton(Context context) { 
     mCtx = context; 
     mRequestQueue = getRequestQueue(); 

     mImageLoader = new ImageLoader(mRequestQueue, 
       new ImageLoader.ImageCache() { 
        private final LruCache<String, Bitmap> 
          cache = new LruCache<String, Bitmap>(20); 

        @Override 
        public Bitmap getBitmap(String url) { 
         return cache.get(url); 
        } 

        @Override 
        public void putBitmap(String url, Bitmap bitmap) { 
         cache.put(url, bitmap); 
        } 
       }); 
    } 

    public static synchronized VolleySingleton getInstance(Context context) { 
     if (mInstance == null) { 
      mInstance = new VolleySingleton(context); 
     } 
     return mInstance; 
    } 

    public RequestQueue getRequestQueue() { 
     if (mRequestQueue == null) { 

      mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); 
     } 
     return mRequestQueue; 
    } 

    public <T> void addToRequestQueue(Request<T> req) { 
     getRequestQueue().add(req); 
    } 

    public ImageLoader getImageLoader() { 
     return mImageLoader; 
    } 
} 

答えて

1

を、それを達成する方法を知りたいですさて、2つのポイント:

あなたはあなたのacti onCreateにvityが再作成されます。理論的にはの場合は、RequestQueuehere参照)を作成するときにVolleyが自動的にDiskBasedCacheを設定するように見えるため、データを更新する必要があります。

これは、各方向変更後に新しい要求を行っていても、Volleyはネットワークに接続する代わりに、キャッシュされた応答を取得することを意味します。冗長なロギングを有効にすることで、Volleyがネットワークまたはキャッシュを使用して要求を処理するタイミングを確認する必要があります。

ここを参照してください、詳細ログを有効にするには:https://stackoverflow.com/a/23654407/2220337

をただし、デフォルトのキャッシュはメモリ内キャッシュよりも遅くなるだけDiskキャッシュ、です。キャッシュを高速化する必要がある場合は、Cacheインターフェイスを実装し、次にRequestQueueを記述してhereとし、コンストラクタで独自のカスタムメモリ内キャッシュを提供することで、独自のインメモリキャッシュを実装できます。

オリエンテーションを変更した後では、まったく要求しないで、代わりにonSaveInstanceState/onRestoreInstanceStateに依存してデータを復元してください。このようにして、リクエストがすでに完了している場合、アクティビティが再作成されたときに新しいリクエストが発生しません。

代わりに、onSaveInstanceStateに保存したデータを表示するだけです。

public class MainActivity extends AppCompatActivity { 

public static final String URL = "API_HERE"; 
private static final String SAVED_RESPONSE = "SAVED_RESPONSE"; 
private ImageGridAdapter imageGridAdapter; 
private List<String> imageList; 
private GridView gridView; 
private String savedResponse; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    imageList = new ArrayList<>(); 
    gridView = (GridView) findViewById(R.id.gridview); 
    final TextView emptyTextView = (TextView) findViewById(android.R.id.empty); 
    gridView.setEmptyView(emptyTextView); 
    imageGridAdapter = new ImageGridAdapter(MainActivity.this, imageList); 
    gridView.setAdapter(imageGridAdapter); 

    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
     @Override 
     public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { 

      Intent intent = new Intent(MainActivity.this, ImageActivity.class); 
      intent.putExtra("imageuri", imageList.get(position)); 
      startActivity(intent); 
     } 
    }); 

    if (savedInstanceState == null) { 
     //activity was created for the first time, fetch images 
     getImages(); 
    } else { 
     //everything in this else branch can be moved in onRestoreInstanceState, this is just a matter of preference 
     savedResponse = savedInstanceState.getString(SAVED_RESPONSE); 
     if (savedResponse != null) { 
      refreshImages(savedResponse); 
     } else { 
      //an error occurred when the request was fired previously 
      ((TextView) gridView.getEmptyView()).setText("Unknown error occured"); 
     } 
    } 
} 

@Override 
protected void onSaveInstanceState(Bundle outState) { 
    super.onSaveInstanceState(outState); 
    outState.putString(SAVED_RESPONSE, savedResponse); 
} 

private void getImages() { 
    StringRequest stringRequest = new StringRequest(Request.Method.GET, URL, 
      new Response.Listener<String>() { 
       @Override 
       public void onResponse(String response) { 
        savedResponse = response; 
        refreshImages(response); 
       } 
      }, new Response.ErrorListener() { 
     @Override 
     public void onErrorResponse(VolleyError error) { 
      savedResponse = null; 
      ((TextView) gridView.getEmptyView()).setText("Unknown error occured"); 
     } 
    }); 

    VolleySingleton.getInstance(this.getApplicationContext()).addToRequestQueue(stringRequest); 
} 

private void refreshImages(String response) { 
    imageList = QueryUtils.extractImages(response); //extract needed things from json 
    imageGridAdapter.clear(); 
    imageGridAdapter.addAll(imageList); 
} 

また、以下の点について注意してください:あなたが要求を開始し、それが完了する前に姿勢の変化が発生した場合

  • 、あなたがメモリリークを持っています、そして、あなたの活動ができなくなりますガベージコレクション。これは、stringRequestが黙示的にMainActivityを参照する匿名の内部クラスインスタンスであるためです。

    これを回避するために、私はボレーのリクエスト&のレスポンスをAndroidサービスで管理しており、その応答はスティッキーブロードキャストを通じてUIに転送されていました。イベントバスもこの目的のために働いています。

    ブロードキャストは、再作成中にブロードキャスト受信者として登録されていないため、アクティビティの再作成中に完了した場合に応答を失わないようにする必要がありました。しかし、スティッキーなブロードキャストを送信することで、Androidが自分のアクティビティの再作成を完了した後も、それらは永続してデータを読み取ることができます。

  • あなたの応答文字列が、あとでダウンロードされるいくつかのオンラインイメージを指す非常に大きなJSONである場合、私が述べた2番目のアプローチはうまくいくはずです。しかし、代わりにBASE64のエンコードされたイメージが含まれている場合は、VolleyのデフォルトのDiskBasedCacheがデータをキャッシュする方が適切かもしれません。

これが役立ちます。

+0

これはちょうど1つの質問ですので、これは向きが変わったときにメモリリークにつながるので、なぜボレーのために別のシングルトンクラスが必要なのでしょうか?それとも、単にこのようなもの(https://developer.android.com/training/volley/simple.html) – Nobody

+0

を明示するのではなく、「** this **」を使うとメモリにつながりますリーク.. "、**この**は私の答えのコードフラグメント、またはコード断片の後に記載されているサービスのアプローチを参照していますか? – cjurjiu

+0

私は[前のページ](https://開発者)で言及されている通常のアプローチに対して、ドキュメントで言及されている[シングルトンアプローチ](https://developer.android.com/training/volley/requestqueue.html)を意味しませんでした。 android.com/training/volley/simple.html)を参照してください。私はちょうどシングルトンクラスのアプローチを持つことがこれと比較してどのように優れているかを知りたいだけです。 – Nobody

関連する問題