Android ListView Recycler吓坏了,还是我失败了?

问题描述:

我已经创建了使用row.xml文件填充的自定义列表视图。每行包含两个TextView和一个ImageView。我从一个JSON文件填充TextView(但是这工作正常,所以我认为你可以放心地忽略这个),并且我基于SharedPreferences填充ImageView ...这是问题所在。Android ListView Recycler吓坏了,还是我失败了?

基本上,逻辑是这样的:有人点击列表视图中的一行,如果关联的活动成功完成,我通知SharedPreferences,然后,一旦用户返回列表,开关/大小写读取SharedPreferences文件,然后更新该特定行中的ImageView,以显示绿色图标。如果用户未能通过Activity,那么该行中的ImageView会显示一个红色图标。在列表中第一个未完成的活动旁边显示一个蓝色图标。

我通过在视图形成循环中为SharedPreferences运行switch/case命令来完成此操作。

所以......我的问题:我打开列表,一切工作正常。如预期的那样,该列表显示一个蓝色图标。当我向下滚动时,我又看到另一个蓝色图标......这不应该在那里。好吧,你在想“你把你的编码搞定了”。但是 - 当我向后滚动列表时,我看到蓝色图标现在已从预期列表项目跳到下面的一个。我再次向下滚动,我看到蓝色图标已经成倍增加 - 现在有两个不同的行,其中两个不存在之前。所以我完成了一项任务。一个绿色的图标出现在它应该的地方我上下滚动几次,突然有不同列表行旁边有3-4个绿色图标。

我唯一的猜测是回收商吓坏了。我对吗?我能做些什么来解决这个问题吗?我尝试了偷偷摸摸 - 我使用了'setVisibility-GONE'来处理不需要imageview的行...在一些滚动之后,它就是 - 它令人讨厌的绿色照亮了它不可能存在的行。这里是我的源代码:

public class MainList extends ListActivity { 
static SharedPreferences statusSettings; 
String jsonString; 
static JSONObject json; 
static JSONArray arrayTest; 
static int bob = 3; 


@Override 
protected void onListItemClick(ListView l, View v, int position, long id) { 
    // TODO Auto-generated method stub 
    super.onListItemClick(l, v, position, id); 

    try { 
     JSONObject e = arrayTest.getJSONObject(position); 
     Intent intent = new Intent(); 
     intent.putExtra("clientName", e.getString("proj_name")); 
     intent.putExtra("clientAddress", e.getString("c_address")); 
     intent.putExtra("clientComments", e.getString("comments")); 
     intent.putExtra("clientOrder", e.getString("order")); 
     intent.setClass(MainList.this, ClientDetails.class); 
     MainList.this.startActivity(intent); 


    } catch (JSONException e) { 
     // TODO Auto-generated catch block 
     Log.e("JSON", "Problem creating object from array!"); 
     e.printStackTrace(); 
    } 
} 

private static class EfficientAdapter extends BaseAdapter { 
    private LayoutInflater mInflater; 


    public EfficientAdapter(Context context) { 
     // Cache the LayoutInflate to avoid asking for a new one each time. 
     mInflater = LayoutInflater.from(context); 

    } 

    public int getCount() { 
     return arrayTest.length(); 

    } 

    public Object getItem(int position) { 
     return position; 
    } 

    public long getItemId(int position) { 
     return position; 
    } 

    public View getView(int position, View convertView, ViewGroup parent) { 
     // A ViewHolder keeps references to children views to avoid unneccessary calls 
     // to findViewById() on each row. 
     ViewHolder holder; 

     // When convertView is not null, we can reuse it directly, there is no need 
     // to reinflate it. We only inflate a new View when the convertView supplied 
     // by ListView is null. 
     if (convertView == null) { 
      convertView = mInflater.inflate(R.layout.mainlist, null); 

      // Creates a ViewHolder and store references to the two children views 
      // we want to bind data to. 
      holder = new ViewHolder(); 
      holder.icon = (ImageView) convertView.findViewById(R.id.ivMainIcon); 
      holder.textName = (TextView) convertView.findViewById(R.id.tvMainName); 
      holder.textAddress = (TextView) convertView.findViewById(R.id.tvMainAddress); 


      convertView.setTag(holder); 
     } else { 
      // Get the ViewHolder back to get fast access to the TextView 
      // and the ImageView. 
      holder = (ViewHolder) convertView.getTag(); 
     } 

     // Bind the data efficiently with the holder. 

     JSONObject e; 
     try { 
      e = arrayTest.getJSONObject(position); 
      holder.textName.setText(e.getString("proj_name")); 
      holder.textAddress.setText(e.getString("c_address")); 

      switch (statusSettings.getInt(e.getString("order"), 0)){ 
       case 1: 
        holder.icon.setVisibility(View.INVISIBLE); 
        break; 
       case 2: 
        if(bob == 3){ 
         holder.icon.setImageResource(R.drawable.next_delivery); 
         bob = 5; 
        } 
        break; 
       case 3: 
        holder.icon.setImageResource(R.drawable.delivered_icon); 
        break; 
       case 4: 
        holder.icon.setImageResource(R.drawable.undelivered_icon); 
        break; 
      } 


     } catch (JSONException e1) { 
      // TODO Auto-generated catch block 
      Log.e("JSON", "Couldn't put one of JSON arrays into object"); 
      e1.printStackTrace(); 
     } 

     return convertView; 
    } 

    static class ViewHolder { 
     ImageView icon; 
     TextView textName; 
     TextView textAddress; 

    } 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    jsonString = getIntent().getExtras().getString("jsonString"); 
    try { 
     json = new JSONObject(jsonString); 
     arrayTest = json.getJSONArray("client_list"); 
    } catch (JSONException e) { 
     // TODO Auto-generated catch block 
     Log.e("JSON", "Couldn't create the JSON Array"); 
     e.printStackTrace(); 
    } 
    setListAdapter(new EfficientAdapter(this)); 

} 

@Override 
protected void onResume() { 
    // TODO Auto-generated method stub 
    super.onResume(); 
    bob = 3;   
    statusSettings = getSharedPreferences("status", 0); 

    setListAdapter(new EfficientAdapter(this)); 
} 


} 

任何帮助将不胜感激。

/编辑:如果你需要它 - 这里是row.xml文件:

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" > 

<LinearLayout 
    android:id="@+id/LinearLayout02" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignParentBottom="true" > 

    <TextView 
     android:id="@+id/tvMainName" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_weight="1" 
     android:paddingBottom="10dp" 
     android:paddingTop="10dp" 
     android:text="Large Text" 
     android:textColor="#FFFFFF" 
     android:textSize="25dp" /> 

    <ImageView 
     android:id="@+id/ivMainIcon" 
     android:layout_width="15dp" 
     android:layout_height="15dp" 
     android:layout_gravity="bottom" 
     android:layout_marginRight="20dp" 
     android:layout_marginBottom="10dp" 
     android:layout_weight="0" 
     android:scaleType="fitXY" /> 
</LinearLayout> 

<TextView 
    android:id="@+id/tvMainAddress" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:paddingBottom="5dp" 
    android:text="TextView" 
    android:textSize="15dp" /> 

</LinearLayout> 

更新交换机/箱(布里格姆提供)...依然采用与鲍勃半称职的解决方案可变的。至少现在一切工作,因为它应该!:

switch (statusSettings.getInt(e.getString("order"), 0)){ 
       case 1: 
        holder.icon.setVisibility(View.INVISIBLE); 
        break; 
       case 2: 
        if(bob.toString().equalsIgnoreCase("do it") || bob.toString().equalsIgnoreCase(e.getString("proj_name"))){ 

         holder.icon.setVisibility(View.VISIBLE); 
         holder.icon.setImageResource(R.drawable.next_delivery); 
         bob = e.getString("proj_name"); 
        }else{ 
         holder.icon.setVisibility(View.INVISIBLE); 
        } 
        break; 
       case 3: 
        holder.icon.setVisibility(View.VISIBLE); 
        holder.icon.setImageResource(R.drawable.delivered_icon); 
        break; 
       case 4: 
        holder.icon.setVisibility(View.VISIBLE); 
        holder.icon.setImageResource(R.drawable.undelivered_icon); 
        break; 
       default: 
        holder.icon.setVisibility(View.INVISIBLE); 
        break; 
      } 
+0

convertView是否每次都为空?你是否试图摆脱ViewHolder并直接使用RelativeLayout并返回它?你的statusSettings.getInt(e.getString(“order”),0)总是返回不同的值吗?你的row.xml是怎么样的?谢谢。 – 2012-02-02 15:20:06

+0

不知道有关convertView,我也没有尝试RelativeLayout。我仍然是学习的小白,所以我需要看看这些东西是如何完成的。至于statusSettings.getInt(e.getString(“order”) - no - 它只返回4个值1 =“未完成”2 =“以前的活动已完成,但我还没有完成”3 =“成功完成“和4 =”任务失败“ 这也是bob的原因 - 因为我只想要一个案例2:显示一个蓝色图标 – Wildblood 2012-02-02 15:50:48

在你case 2,你只有bob == 3设置图像。您应该添加一个else子句,并在bob != 3时使图像不可见。您还应该确保在switch语句之前将图标设置为可见,因为大多数情况下都需要它可见。

您还应该考虑在switch语句中添加一个默认情况。

 holder.icon.setVisibility(View.VISIBLE); 
     switch (statusSettings.getInt(e.getString("order"), 0)){ 
      case 1: 
       holder.icon.setVisibility(View.INVISIBLE); 
       break; 
      case 2: 
       if(bob == 3){ 
        holder.icon.setImageResource(R.drawable.next_delivery); 
        bob = 5; 
       } else { 
        holder.icon.setVisibility(View.INVISIBLE); 
       } 
       break; 
      case 3: 
       holder.icon.setImageResource(R.drawable.delivered_icon); 
       break; 
      case 4: 
       holder.icon.setImageResource(R.drawable.undelivered_icon); 
       break; 
      default: 
       holder.icon.setVisibility(View.INVISIBLE); 
       break; 
     } 
+0

好的,这似乎已经修复了很多。 (交付和未交付)现在工作正常 - 没有跳来跳去,但是蓝色消失了,但我认为视图是由回收站在滚动时动态创建的,因此它看到bob = 3,显示next_delivery图标,将bob更改为5,然后一旦它破坏了视图,它再也不会显示图标,因为bob不再是3.我需要重新思考我的逻辑,并且做出一些严肃的事情而不是那种半分析的解决方案。谢谢你。 我仍然无法弄清楚为什么绿色和红色的图标不断在增加......它正在我的脑海里! – Wildblood 2012-02-02 15:28:04

+0

正确...我修复了我的半分析解决方案,因此它现在变得更加复杂,但没有更多的尊严,半分析解决方案。该应用程序正在按预期工作 - 非常感谢! – Wildblood 2012-02-02 15:55:53

+2

基本上,当您使用循环视图时,您需要确保重置视图中的每个字段,否则最终会出现一些旧视图的工件,如您所看到的那样弹出。 – Brigham 2012-02-02 15:57:05

另一种选择是禁用回收站。你可能不想这样做,但你所要做的就是删除convertView == null,它是else语句。这将停止回收视图中的工件。