滚动到特定位置时 Recyclerview 崩溃

Posted

技术标签:

【中文标题】滚动到特定位置时 Recyclerview 崩溃【英文标题】:Recyclerview crashed when scrolled to particular position 【发布时间】:2017-12-17 15:36:08 【问题描述】:

我有RecyclerView,它有分页,当我滚动几次时它会崩溃。当我慢慢滚动时,它不会崩溃。我提供了适配器和活动代码。请让我知道我在这里犯的任何错误。我已经搜索过相同的问题,但我无法在此处发现错误。

private class GetTrending extends AsyncTask<Void, Void, Void> 
    BufferedReader bufferedReader = null;
    private StringBuffer stringBuffer = new StringBuffer();
    private JSONArray jArray = new JSONArray();
    private int pageNum;
    private boolean value;

    public GetTrending(int pageNum, boolean value) 
        this.pageNum = pageNum;
        this.value = value;
    

    @Override
    protected Void doInBackground(Void... params) 
        try 

            HttpClient httpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet();
            URI uri = new URI(getString(R.string.url) +
                    "products?bestsellers=on&items_per_page=24&page=" + pageNum + mWholeSaleUrlTag);

            httpGet.setURI(uri);
            httpGet.addHeader(BasicScheme.authenticate(
                    new UsernamePasswordCredentials(getString(R.string.username), getString(R.string.password)),
                    HTTP.UTF_8, false));
            HttpResponse httpResponse;
            Log.e("Trending-Before", "Date" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new Date()));
            httpResponse = httpClient.execute(httpGet);
            Log.e("Trending-After", "New Date" + new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(new Date()));
            InputStream inputStream = httpResponse.getEntity().getContent();
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            //Log.e("Hi", String.valueOf(bufferedReader));
            String readLine = bufferedReader.readLine();
            while (readLine != null) 
                stringBuffer.append(readLine);
                //stringBuffer.append("\n");
                readLine = bufferedReader.readLine();

            
            //Log.e("BestSellers", String.valueOf(stringBuffer));
         catch (IOException e) 
            e.printStackTrace();
         catch (URISyntaxException e) 
            e.printStackTrace();
        
        try 
            JSONObject prodObjects = new JSONObject(String.valueOf(stringBuffer));
            jArray = prodObjects.optJSONArray("products");
            if (jArray.length() < 24) 
                shouldFetchTrending = false;
            

            for (int i = 0; i < jArray.length(); i++) 
                Home home = new Home();
                prodObjects = jArray.getJSONObject(i);
                home.setProduct_id(prodObjects.getString("product_id"));
                // Log.e("Trending id", jobj.getString("product_id"));
                home.setProduct_name(prodObjects.getString("product"));
                NumberFormat nf = NumberFormat.getInstance();
                nf.setMinimumFractionDigits(2);
                nf.setMaximumFractionDigits(2);
                home.setProduct_price(nf.format(Double.parseDouble(prodObjects.getString("price"))));
                home.setProduct_listprice(nf.format(Double.parseDouble(prodObjects.getString("list_price"))));
                String mAmount = prodObjects.getString("amount");
                home.setAmount(mAmount);


                Item item = new Item();

                item.setName(prodObjects.getString("product"));
                item.setProductId(prodObjects.getString("product_id"));
                item.setPrice(nf.format(Double.parseDouble(prodObjects.getString("price"))));
                item.setListPrice(nf.format(Double.parseDouble(prodObjects.getString("list_price"))));
                item.setImage(prodObjects.getJSONObject("main_pair").getJSONObject("detailed").getString("image_path"));
                item.setAmount(mAmount);


                home.setProduct_image(prodObjects.getJSONObject("main_pair").getJSONObject("detailed").getString("image_path"));

                if (prodObjects.getString("status").equalsIgnoreCase("A") && !prodObjects.getString("amount").equalsIgnoreCase("0")) 
                    Sports.add(home);
                    trendingItemList.add(item);
                


            
            // Log.e("Length", String.valueOf(Sports.size()));
         catch (JSONException e) 
            e.printStackTrace();
        


        return null;
    

    protected void onPostExecute(Void result) 
        super.onPostExecute(result);
        shouldFetchTrending = true;
        if (value) 
            trendingItemAdapter = new ItemAdapter(HomeActivity.this, trendingItemList);
            mTrendingRecyclerView.setAdapter(trendingItemAdapter);
        
        trendingItemAdapter.notifyDataSetChanged();


        mTrendingRecyclerView.addOnItemTouchListener(new RecyclerItemClickListener(HomeActivity.this, new RecyclerItemClickListener.OnItemClickListener() 
            @Override
            public void onItemClick(View view, int position) 
                ((CardView) view).setCardElevation(100);
                Intent myintent = new Intent(HomeActivity.this, ProductPageActivity.class);
                myintent.putExtra("Prodid", trendingItemList.get(position).getProductId());
                myintent.putExtra("FromHome", "Home");
                startActivity(myintent);
            
        ));

        try 
            for (int i = 0; i < Sports.size(); ++i) 
                trendinglinear[i].setVisibility(View.VISIBLE);
                tname[i].setText(Sports.get(i).getProduct_name());
                tprice[i].setText(Sports.get(i).getProduct_price());
                ((View) tname[i].getParent()).setTag(Sports.get(i).getProduct_id());
                String[] simg = new String[25];
                simg[i] = Sports.get(i).getProduct_image();
                //Log.e("image", simg[i]);
                Picasso.with(getApplicationContext()).load(simg[i]).error(R.drawable.ic_launcher).resize(400, 400).into(timage[i]);

            
         catch (Exception e) 
            //Toast.makeText(HomeActivity.this, "Failed to connect to internet Try again !", Toast.LENGTH_SHORT).show();

        

    


public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> 
    private List<Item> itemList;
    private Context context;
    private int lastPosition = -1;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) 

        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.home_recycler_item, parent, false);

        ViewHolder vh = new ViewHolder(v);
        return vh;
    

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) 
        Item item = itemList.get(position);
        holder.tvName.setText(item.getName());
        if(Integer.valueOf(item.getAmount()) == 0)
        holder.tvOutofstack.setVisibility(View.VISIBLE);
        else holder.tvOutofstack.setVisibility(View.INVISIBLE);

        holder.tvPrice.setText(item.getPrice());
        Picasso.with(context).load(item.getImage()).into(holder.ivImage);
        setAnimation(holder.cardView, position);

    

    @Override
    public int getItemCount() 
        return itemList.size();
    

    public static class ViewHolder extends RecyclerView.ViewHolder 

        public TextView tvName,tvOutofstack;
        public TextView tvPrice;
        public ImageView ivImage;

        public CardView cardView;



        public ViewHolder(View itemView) 
            super(itemView);
            tvName = (TextView) itemView.findViewById(R.id.tv_name);
            tvOutofstack = (TextView) itemView.findViewById(R.id.item_adapter_tv);
            tvPrice = (TextView) itemView.findViewById(R.id.tv_price);
            ivImage = (ImageView) itemView.findViewById(R.id.iv_image);
            cardView = (CardView) itemView.findViewById(R.id.card_view);
        
    

    public ItemAdapter(Context context, List<Item> itemList) 
        this.itemList = itemList;
        this.context = context;
    

    private void setAnimation(View viewToAnimate, int position)
    
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition)
        
            Animation animation = AnimationUtils.loadAnimation(context,  android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        
    

显示一些错误(日志):

java.lang.InternalError: 线程在运行时关闭期间启动 07-13 09:01:29.721 32089-1640/? W / System.err:在 java.lang.Thread.nativeCreate(本机方法) - - - - - 和 - - - - - GC_FOR_ALLOC 释放 1057K,释放 20% 115415K/143088K,暂停 295ms,共 295ms 07-13 11:57:15.692 11792-12003/com.dealmaar.customer I/dalvikvm-heap:将堆(碎片情况)增加到 116.585MB,分配 4000012 字节 07-13 11:57:15.936 11792-12001/com.dealmaar.customer D/dalvikvm: GC_FOR_ALLOC freed

【问题讨论】:

请发布您的错误日志 发布你的堆栈跟踪。为什么要使用异步任务和 http 客户端,因为您可以使用 Retrofit 轻松调用网络并使用 jackson 解析器解析 json,这将消除大量代码 没有错误日志。 【参考方案1】:

应用程序因内存管理失败而崩溃,这里每个项目都分配了动画,并且应用的动画没有清除。我花了 1 天时间解决了你的问题,它对我有用。

@Override public void onViewDetachedFromWindow(ViewHolder holder)  
super.onViewDetachedFromWindow(holder);
 ((ViewHolder)holder).clearAnimation();
  

在我的 ViewHolder 中添加方法:

public void clearAnimation()  
itemView.clearAnimation(); 

【讨论】:

【参考方案2】:

您有内存不足异常。 在某些设备中,当您通过最大堆时,它不会显示任何日志,并且 JVM 只会终止您的应用程序。 当你缓慢滚动时,你让 JVM 完成它的垃圾收集过程,但是当你快速滚动时,它没有足够的时间来完成它的任务,你会通过最大堆。 我看到您持有对视图列表和 ImageViews 的引用。

try 
        for (int i = 0; i < Sports.size(); ++i) 
            trendinglinear[i].setVisibility(View.VISIBLE);
            tname[i].setText(Sports.get(i).getProduct_name());
            tprice[i].setText(Sports.get(i).getProduct_price());
            ((View) tname[i].getParent()).setTag(Sports.get(i).getProduct_id());
            String[] simg = new String[25];
            simg[i] = Sports.get(i).getProduct_image();
            //Log.e("image", simg[i]);
            Picasso.with(getApplicationContext()).load(simg[i]).error(R.drawable.ic_launcher).resize(400, 400).into(timage[i]);

        
     catch (Exception e) 
        //Toast.makeText(HomeActivity.this, "Failed to connect to internet Try again !", Toast.LENGTH_SHORT).show();

    

这可能是堆达到最大大小的原因之一。

【讨论】:

【参考方案3】:

你在主线程中做了太多的工作。系统已经超过了它的限制,要执行你的进程需要大量的资源,它会冻结主 UI 线程导致 ANR 错误。我建议您使用AsyncTask 在后台线程中执行所有 API 调用和 JSON 解析。

【讨论】:

以上是关于滚动到特定位置时 Recyclerview 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView - 如何平滑滚动到嵌套滚动视图内某个位置的项目顶部?

应用程序在 recyclerview 滚动 android kotlin 时崩溃

使用 Recycler View 将房间数据库滚动到特定位置

检测 RecyclerView 滚动时何时到达最底部位置

将 RecyclerView 与 FirestoreRecyclerAdapter 一起使用时如何设置滚动位置?

RecyclerView在刷新时滚动时崩溃