2015-01-04 19 views
11

Tôi đã tìm kiếm các chuỗi SO để trả lời nhưng không thể tìm ra vấn đề của tôi từ cuộc thảo luận trước. Tôi có một listview tải khoảng 50 hình ảnh (nó được sử dụng để được khoảng 100 nhưng điều này hầu như không tải bất kỳ hình ảnh ở tất cả). Sau khi lấy nội dung JSON của tôi (bao gồm cả URL hình ảnh) từ một điểm cuối api, thông qua một bộ điều hợp, mã của tôi đặt nó bên trong listview.Picasso giữ tải lại hình ảnh trong khi di chuyển lên trên trong chế độ xem danh sách, tải chậm

Hiện tại, với 50 hình ảnh, picasso sẽ tải một hình ảnh tại một thời điểm khi tôi cuộn xuống trên nguồn cấp dữ liệu. Tôi cảm thấy như thể giữ cuộn cố định trên một mục trong listview sẽ làm cho hình ảnh đó tải nhanh hơn. Tuy nhiên, khi tôi cuộn lên, nó sẽ đặt trình giữ chỗ trở lại và tải lại hình ảnh. Có cách nào để giải quyết vấn đề này không?

public class MainActivity extends Activity { 
    private List<Post> myPosts = new ArrayList<Post>(); 
    protected String[] mBlogPostTitles; 
    public static final String TAG = MainActivity.class.getSimpleName();//prints name of class without package name 

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

     if(isNetworkAvailable()) { 
      GetBlogPostsTask getBlogPostsTask = new GetBlogPostsTask(); // new thread 
      getBlogPostsTask.execute();// don't call do in background directly 
     }else{ 
      Toast.makeText(this, "Network is unavailable", Toast.LENGTH_LONG).show(); 
     } 
    } 
    public boolean isNetworkAvailable() { 
     ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo networkInfo = manager.getActiveNetworkInfo(); 

     boolean isAvailable = false; 

     if(networkInfo != null && networkInfo.isConnected()){ 
      isAvailable = true; 
     } 

     return isAvailable; 
    } 
    private void populateListView() { 
     ArrayAdapter<Post> adapter = new MyListAdapter(); 
     ListView list = (ListView) findViewById(R.id.postsListView); 
     list.setAdapter(adapter); 
    } 

    private class MyListAdapter extends ArrayAdapter<Post>{ 
     public MyListAdapter() { 
      super(MainActivity.this, R.layout.item_view, myPosts); 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 

      // make sure we have a view to work with 
      View itemView = convertView; 
      if (itemView == null) { 
       itemView = getLayoutInflater().inflate(R.layout.item_view, parent,false); 
      } 
      //find the post to work with 
      Post currentPost = myPosts.get(position); 
      Context context = itemView.getContext(); 

      String imageURL = currentPost.getImage(); 
      if(imageURL == null || imageURL.isEmpty()){ 
       ImageView imageView = (ImageView) itemView.findViewById(R.id.item_image); 
       imageView.setVisibility(View.GONE); 
      }else{ 
       ImageView imageView = (ImageView) itemView.findViewById(R.id.item_image); 
       Picasso.with(context) 
         .load(imageURL) 
         .tag(context) 
         .placeholder(R.drawable.kanye8080s) 
         .error(R.drawable.stadiumarcadium) 
         .into(imageView); 
       imageView.setVisibility(View.VISIBLE); 
      } 

      //Username 
      TextView userText = (TextView) itemView.findViewById(R.id.item_txtUser); 
      userText.setText(currentPost.getUser()); 

      //Time of post 
      TextView timeText = (TextView) itemView.findViewById(R.id.item_txtTime); 
      timeText.setText("" + currentPost.getTime()); 

      //The actual post 
      TextView postText = (TextView) itemView.findViewById(R.id.item_txtPost); 
      postText.setText("" + currentPost.getPost()); 

      //The actual post 
      TextView likesText = (TextView) itemView.findViewById(R.id.item_txtLikes); 
      likesText.setText("" + currentPost.getLikes()); 

      return itemView; 
     } 
    } 

    private class GetBlogPostsTask extends AsyncTask<Object, Void, List> { 

     @Override 
     protected List doInBackground(Object[] params) { 

      int responseCode = -1;//need to have this variable outside scope of try/catch block 
      JSONObject jsonResponse = null; 
      StringBuilder builder = new StringBuilder(); 
      HttpClient client = new DefaultHttpClient(); 
      HttpGet httpget = new HttpGet(""); /// api endpoint redacted 

      try { 

       HttpResponse response = client.execute(httpget); 
       StatusLine statusLine = response.getStatusLine(); 
       responseCode = statusLine.getStatusCode(); 

       if(responseCode == HttpURLConnection.HTTP_OK){ //could have used just 200 value 
        HttpEntity entity = response.getEntity(); 
        InputStream content = entity.getContent(); 
        BufferedReader reader = new BufferedReader(new InputStreamReader(content)); 
        String line; 
        while((line = reader.readLine()) != null){ 
         builder.append(line); 
        } 

        jsonResponse = new JSONObject(builder.toString()); 

        JSONArray jsonPosts = jsonResponse.getJSONArray("posts"); 
        for(int i=0; i < jsonPosts.length(); i++){ 
         JSONObject jsonPost = jsonPosts.getJSONObject(i); 

         int post_id = Integer.parseInt(jsonPost.getString("id")); 
         String post_user = jsonPost.getString("user"); 
         String post_account = jsonPost.getString("account"); 
         int post_time = Integer.parseInt(jsonPost.getString("time")); 
         String post_post = jsonPost.getString("post"); 
         String post_image = jsonPost.getString("image"); 
         int post_likes = Integer.parseInt(jsonPost.getString("likes")); 

         myPosts.add(new Post(post_id, post_user, post_account, post_time, post_post, post_image, "profile picture here", post_likes)); 
        } 
       }else{ 
        Log.i(TAG, "Unsuccessful HTTP Response Code: " + responseCode); 
       } 
      } 
      catch (MalformedURLException e){ 
       Log.e(TAG, "Exception caught"); 
      } 
      catch (IOException e){ 
       Log.e(TAG, "Exception caught"); 
      } 
      catch (Exception e){//must be in this order, this is the last, general catch 
       Log.e(TAG, "Exception caught", e); 
      } 

      return null; 
     } 
     @Override 
     protected void onPostExecute(List result) { 
      // call populateListView method here 
      populateListView(); 
      super.onPostExecute(result); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.menu_main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      return true; 
     } 

     return super.onOptionsItemSelected(item); 
    } 
} 

bất kỳ trợ giúp sẽ được đánh giá cao,

Cảm ơn bạn !!

EDIT:

Hi tất cả mọi người,

Tôi đã cập nhật mã của tôi vào một mô hình quan điểm chủ sở hữu, tạo ra hai quan điểm riêng biệt (một cho một bài đăng với một hình ảnh, một cho một bài đăng chỉ với văn bản) và cũng bao gồm scroll detection capabilities mới của Picasso.

Tôi đã thấy cải thiện trong một số hình ảnh tải nhanh hơn, ít nhất là khi chế độ xem được lấy nét trong khi cuộn, hình ảnh có nhiều khả năng tải ngay bây giờ. Tuy nhiên, khi cuộn lên những hình ảnh tương tự đã từng được tải, biến mất. Nó cảm thấy như Picasso chỉ tải 4-5 hình ảnh tại một thời điểm và thay thế những hình ảnh đã được nạp để nhường chỗ. Mã được cập nhật của tôi là bên dưới:

public class MainActivity extends Activity { 
    private List<Post> myPosts = new ArrayList<Post>(); 
    protected String[] mBlogPostTitles; 
    public static final String TAG = MainActivity.class.getSimpleName();//prints name of class without package name 

    ... 

    private void populateListView() { 
     Activity activity = MainActivity.this; 

     ArrayAdapter<Post> adapter = new MyListAdapter(); 
     ListView list = (ListView) findViewById(R.id.postsListView); 
     list.setAdapter(adapter); 
     list.setOnScrollListener(new SampleScrollListener(activity)); 
    } 

    private class MyListAdapter extends ArrayAdapter<Post>{ 
     public MyListAdapter() { 
      super(MainActivity.this, R.layout.item_view, myPosts); 
     } 

     @Override 
     public int getViewTypeCount() { 
      return 2; 
     } 

     @Override 
     public int getItemViewType(int position) { 
      String imageURL = myPosts.get(position).getImage(); 
      if(imageURL == null || imageURL.isEmpty()){ 
       return 1; // text based 
      }else{ 
       return 0; // image based 
      } 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 

      PostViewHolder holder; 

      int type = getItemViewType(position); 

      View itemView = convertView; 

      // make sure we have a view to work with 
      if (itemView == null) { 
       holder = new PostViewHolder(); 
       if(type == 1) { 
        itemView = getLayoutInflater().inflate(R.layout.item_view, parent, false); 
       }else { 
        itemView = getLayoutInflater().inflate(R.layout.image_post_view, parent, false); 
        holder.image = (ImageView) itemView.findViewById(R.id.item_image); 
       } 
       holder.user = (TextView) itemView.findViewById(R.id.item_txtUser); 
       holder.time = (TextView) itemView.findViewById(R.id.item_txtTime); 
       holder.post = (TextView) itemView.findViewById(R.id.item_txtPost); 
       holder.likes = (TextView) itemView.findViewById(R.id.item_txtLikes); 

       itemView.setTag(holder); 
      } else { 
       holder = (PostViewHolder) itemView.getTag(); 
      } 

      //find the post to work with 
      Post currentPost = myPosts.get(position); 

      if(type != 1) { 
       Context context = itemView.getContext(); 
       String imageURL = currentPost.getImage(); 

       Picasso.with(context).setIndicatorsEnabled(true); 
       //Picasso.with(context).setLoggingEnabled(true); 
       Picasso.with(context) 
         .load(imageURL) 
         .tag(context) 
         .placeholder(R.drawable.kanye8080s) 
         //.skipMemoryCache() 
         .error(R.drawable.stadiumarcadium) 
         .fit() 
         .into(holder.image); 
      } 
      //Username 
      holder.user.setText(currentPost.getUser()); 

      //Time of post 
      holder.time.setText("" + currentPost.getTime()); 

      //The actual post 
      holder.post.setText(currentPost.getPost()); 

      //Likes for the post 
      holder.likes.setText("" + currentPost.getLikes()); 

      return itemView; 
     } 
    } 
    public class SampleScrollListener implements AbsListView.OnScrollListener { 
     private final Context context; 

     public SampleScrollListener(Context context) { 
      this.context = context; 
     } 

     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
      final Picasso picasso = Picasso.with(context); 
      if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) { 
       picasso.resumeTag(context); 
      } else { 
       picasso.pauseTag(context); 
      } 
     } 

     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
          int totalItemCount) { 
      // Do nothing. 
     } 
    } 


    ... 
} 

Sự cố đến từ đâu? Tôi có nên tải trước những hình ảnh này bằng cách nào đó trong bộ nhớ cache không? Trong khi tôi đã xem xét tính năng ưu tiên mới của Picasso, tôi có nên nói cho Picasso bằng cách nào đó để tải hình ảnh theo thứ tự xuất hiện trong listview của tôi không? Bất kỳ ý tưởng? Làm thế nào tôi có thể "giữ" hình ảnh đã được tải khi cuộn lên? Cảm ơn!

- 24x7

+0

Theo mặc định, Picasso đã làm bộ nhớ đệm theo khuyến nghị của tài liệu dành cho nhà phát triển [ở đây] (http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html). Xem [câu trả lời này] (http://stackoverflow.com/a/20105828/2911458) để biết một số cuộc thảo luận về bộ nhớ cache được sử dụng. Nếu bạn muốn kiểm tra xem bộ nhớ đệm có đang hoạt động hay không, hãy kích hoạt chế độ gỡ lỗi của Picasso bằng cách gọi 'setIndicatorsEnabled (true)' trên thể hiện Picasso của bạn. Các chỉ số được mô tả [ở đây] (http://square.github.io/picasso/). – stkent

+1

Tôi bật các chỉ số, nhưng không thể xác định được nhiều. Ngay cả với một số hình ảnh giảm (7) bên trong một listview với 10 mục vẫn còn hoạt động bất thường. Hình ảnh tải lại khi bạn cuộn lên và xuất hiện để tải chậm trừ khi chúng được tập trung vào listview. – 24x7

+0

Tại sao bạn gọi setVisibility() trên imageView. Hãy thử nó mà không có điều đó. Sử dụng trình giữ chỗ và hình ảnh lỗi trong Picasso cho điều đó, điều này có thể là một phần của vấn đề. Bạn có thể. Load (null) với Picasso tôi tin. –

Trả lời

4

Kích thước của bộ nhớ cache của Picasso bị hạn chế vì vậy nó không tạo ra các lỗi bộ nhớ khi di chuyển danh sách dài. Khi hình ảnh đã hết bộ nhớ đệm, trình giữ chỗ sẽ được hiển thị trong khi hình ảnh được tải lại từ bộ nhớ cache trên đĩa hoặc mạng.

Bộ đệm đĩa được bật theo mặc định nên thời gian tải lại sẽ rất nhanh. Bạn có thể sử dụng setIndicatorsEnabled(true) để xem hình ảnh đang được tải từ đâu.

Nếu bạn thấy Picasso đang tải lại hình ảnh từ mạng, đây có thể là vấn đề với tiêu đề HTTP được gửi từ máy chủ. Tôi không tin Picasso thực sự lưu trữ hình ảnh trên đĩa, thay vì dựa vào lớp HTTP, nó sẽ tuân theo tiêu đề không có bộ nhớ cache và sẽ tải lại từ mạng nếu thời gian hết hạn trôi qua.

+0

Các nguồn của URL hình ảnh chủ yếu là từ Parse nhưng cũng có một số từ Facebook và imgur. Tất cả các hình ảnh đều là URL trực tiếp. Tôi cũng đã giảm số mục trong danh sách xem xuống còn 10 - 7 trong số đó có hình ảnh. Và lỗi tương tự vẫn xảy ra. Các hình ảnh tải chậm. Nếu bạn sau đó cuộn xuống và sao lưu lại, chúng sẽ tải lại. – 24x7

+0

Họ có tải lại từ mạng hoặc bộ nhớ cache trên đĩa không? –

+0

Tôi không chắc lắm. Đây là đầu ra từ logcat của tôi: http://pastebin.com/usNa77Hq, tôi cuộn xuống và lên hai lần. – 24x7

4

Tôi sẽ xem xét hai điều.

Số một là kích thước của hình ảnh đang được tải. Tôi không biết kích thước bộ nhớ cache tối đa mặc định là gì trong Picasso, nhưng có vẻ như bạn có thể vượt quá nó chỉ với một vài hình ảnh, khiến cho những người khác bị xóa khỏi bộ nhớ cache.

Số hai có lẽ không phải là vấn đề cốt lõi, mà còn góp phần vào hiệu suất. Bạn đang thực hiện nhiều cuộc gọi findViewById(), điều này khá tốn kém. Nhìn vào mẫu "ViewHolder" để "lưu vào bộ nhớ đệm" những tra cứu đó.

Chỉnh sửa - xem Jake Wharton's answer to a similar question để xem chi tiết hơn

+0

làm ghi chú, tôi đổi kích thước hình ảnh của mình và khắc phục sự cố tôi đã xem là @ 24x7. – Liangjun

+0

bạn có thể chỉ cho tôi mã về cách bạn thay đổi kích thước hình ảnh trên chiều cao thay đổi và chiều rộng cố định không? Ngoài ra, không phải là phù hợp() nghĩa vụ phải thực hiện điều tương tự? Tôi đã bao gồm một cuộc gọi cho nó đã có trong picasso – 24x7

5

sử dụng thay đổi kích thước với picasso

Picasso.with(context) 
.load(imageURL) 
.tag(context) 
.placeholder(R.drawable.kanye8080s) 
.error(R.drawable.stadiumarcadium) 
.into(imageView) 
.resize(x,y); 

// Điều này chắc chắn sẽ giúp

-1

Sử dụng:

recyclerview.getRecycledViewPool().setMaxRecycledViews(0, 0); 

này giải quyết vấn đề của tôi

1

Tôi khuyên bạn nên sử dụng GLIDE để tải hình ảnh. Kể từ GLIDE là nhanh chóng và có tính năng bộ nhớ cache tải của nó bạn có thể nhận được hình ảnh tải siêu nhanh, Với GLIDE bạn nhận được rất nhiều tính năng ..

Tải đây https://github.com/bumptech/glide

Các vấn đề liên quan