0

サンプルアプリケーションの目的は、SQLiteデータベースのアイテムを表示することですが、 (それ以外の場合は、2番目のテキストビューを表示します)。Androidリスト内のレイアウト内の1つのビューを非表示にする方法データベースカーソルアダプタによってバックアップされたビュー

問題は正しいものを隠さないということです。また、スクロール操作によってアイテムが表示されなくなり、表示に戻ると、2番目のテキストビューが隠され、様々なリストアイテムに不安定に表示されます。

隠しフラグが20、15、項目5、10に設定され、ここでそれが来るアップする方法ですされています:initial page 6 unexpectedly hiddenseveral unexpectedly hidden itemsmore unexpectedly hidden images スクロールダウン、他のさまざまな奇妙なアイテムが隠されている、そしてそれはしていないようです毎回同じである。エントリ14、エントリ16は、例えば、隠される。

先頭にスクロールすると、最初の項目のセットに、同じ隠れた2行目がなくなることがわかります。

after scrolling to the top, different things are hidden

そして、エントリーの全体の新しいセットを前後にスクロール隠されています。全くランダムではありませんが、不可解です。あなたはそれを信じるためにそれを見なければなりません。

このサンプルが基づいている「実際の」アプリケーション(ここには表示されていません)は、実際にはImageViewを表示したり隠したりしようとしていますが、TextViewを隠すのと同じ種類の問題があります。 。

以下はアプリケーションです。 この狂ったことを実行したい場合は、、サンプルデータを含む)を含める必要があります。それとも、githubの上でそれを見つけることができます。https://github.com/sengsational/LvCaApp

LvCaActivity.java

public class LvCaActivity extends AppCompatActivity { 

    private SimpleCursorAdapter dataAdapter; 
    private DbAdapter dbHelper; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_lv_ca); 

     dbHelper = new DbAdapter(this); 
     dbHelper.open(); 
     dbHelper.deleteAll(); 
     dbHelper.insertSome(); 

     Cursor bCursor = dbHelper.fetchAll(DbAdapter.bColumns); 

     dataAdapter = new MySimpleCursorAdapter(
       this, R.layout.b_item, 
       bCursor, 
       DbAdapter.bColumns, 
       ViewHolder.viewsArray, 
       0); 

     ListView listView = (ListView) findViewById(R.id.listView1); 

     listView.setAdapter(dataAdapter); 

    } 
} 

activity_lv_ca.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent" android:layout_height="fill_parent" 
       android:orientation="vertical"> 

    <ListView android:id="@+id/listView1" android:layout_width="fill_parent" 
       android:layout_height="fill_parent" /> 

</LinearLayout> 

b_item.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:orientation="vertical" 
       android:padding="6dip" 
       android:id="@+id/b_item_layout"> 

     <TextView 
      android:id="@+id/bName" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentLeft="true" 
      android:layout_alignParentTop="true" 
      android:textAppearance="?android:attr/textAppearanceListItem" 
      android:ellipsize="end" 
      android:singleLine="true" 
      android:paddingTop="30dp"/> 

     <TextView 
      android:id="@+id/bSecondLine" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_below="@+id/bName" 
      android:textAppearance="?android:attr/textAppearanceSmall" /> 

     <TextView 
      android:id="@+id/bDbItem" 
      android:layout_width="wrap_content" 
      android:layout_height="match_parent" 
      android:visibility="gone" 
      /> 
     <TextView 
      android:id="@+id/bHidden" 
      android:layout_width="wrap_content" 
      android:layout_height="match_parent" 
      android:visibility="gone" 
      /> 

</RelativeLayout> 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest package="com.company.cpp.lvcaapp" 
      xmlns:android="http://schemas.android.com/apk/res/android"> 

    <application 
     android:allowBackup="true" 
     android:icon="@mipmap/ic_launcher" 
     android:label="@string/app_name" 
     android:supportsRtl="true" 
     android:theme="@style/AppTheme"> 
     <activity android:name=".LvCaActivity"> 
      <intent-filter> 
       <action android:name="android.intent.action.MAIN"/> 

       <category android:name="android.intent.category.LAUNCHER"/> 
      </intent-filter> 
     </activity> 
    </application> 

</manifest> 

DbAdapter.java

public class DbAdapter { 

    private static final String TAG = "DbAdapter"; 
    private DatabaseHelper mDbHelper; 
    private SQLiteDatabase mDb; 

    private static final String DATABASE_NAME = "adbname"; 
    private static final String SQLITE_TABLE = "atablename"; 
    private static final int DATABASE_VERSION = 1; 

    private final Context mCtx; 

    public static final String[] bColumns = new String[] { 
      "_id", 
      "NAME", 
      "SECOND_LINE", 
      "HIDDEN", 
    }; 

    private static final String DATABASE_CREATE = 
      "CREATE TABLE if not exists " + SQLITE_TABLE + " (" + 
        "_id INTEGER PRIMARY KEY AUTOINCREMENT, " + 
        "NAME TEXT, " + 
        "SECOND_LINE, " + 
        "HIDDEN" + 
        ");"; 

    private static class DatabaseHelper extends SQLiteOpenHelper { 
     DatabaseHelper(Context context) { 
      super(context, DATABASE_NAME, null, DATABASE_VERSION); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      Log.w(TAG, DATABASE_CREATE); 
      db.execSQL(DATABASE_CREATE); 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      Log.w(TAG, "Upgrading database from version " + oldVersion + " to " 
        + newVersion + ", which will destroy all old data"); 
      db.execSQL("DROP TABLE IF EXISTS " + SQLITE_TABLE); 
      onCreate(db); 
     } 
    } 

    public DbAdapter(Context ctx) { 
     this.mCtx = ctx; 
    } 

    public DbAdapter open() throws SQLException { 
     mDbHelper = new DatabaseHelper(mCtx); 
     mDb = mDbHelper.getWritableDatabase(); 
     return this; 
    } 

    public void close() { 
     if (mDbHelper != null) { 
      mDbHelper.close(); 
     } 
    } 
    public Cursor fetchAll(String[] fields) { 
     Cursor mCursor = mDb.query(SQLITE_TABLE, fields, null, null, null, null, null); 
     if (mCursor != null) { 
      mCursor.moveToFirst(); 
     } 
     return mCursor; 
    } 

    public void insertSome() { 
     AListItem.getInstance(); 
     String sampleData = "[{\"name\":\"Entry 1\",\"second_line\":\"Second Line 1\",\"hidden\":\"F\"},{\"name\":\"Entry 2\",\"second_line\":\"Second Line 2\",\"hidden\":\"F\"},{\"name\":\"Entry 3\",\"second_line\":\"Second Line 3\",\"hidden\":\"F\"},{\"name\":\"Entry 4\",\"second_line\":\"Second Line 4\",\"hidden\":\"F\"},{\"name\":\"EntryH 5\",\"second_line\":\"Second Line 5\",\"hidden\":\"T\"},{\"name\":\"Entry 6\",\"second_line\":\"Second Line 6\",\"hidden\":\"F\"},{\"name\":\"Entry 7\",\"second_line\":\"Second Line 7\",\"hidden\":\"F\"},{\"name\":\"Entry 8\",\"second_line\":\"Second Line 8\",\"hidden\":\"F\"},{\"name\":\"Entry 9\",\"second_line\":\"Second Line 9\",\"hidden\":\"F\"},{\"name\":\"EntryH 10\",\"second_line\":\"Second Line 10\",\"hidden\":\"T\"},{\"name\":\"Entry 11\",\"second_line\":\"Second Line 11\",\"hidden\":\"F\"},{\"name\":\"Entry 12\",\"second_line\":\"Second Line 12\",\"hidden\":\"F\"},{\"name\":\"Entry 13\",\"second_line\":\"Second Line 13\",\"hidden\":\"F\"},{\"name\":\"Entry 14\",\"second_line\":\"Second Line 14\",\"hidden\":\"F\"},{\"name\":\"EntryH 15\",\"second_line\":\"Second Line 15\",\"hidden\":\"T\"},{\"name\":\"Entry 16\",\"second_line\":\"Second Line 16\",\"hidden\":\"F\"},{\"name\":\"Entry 17\",\"second_line\":\"Second Line 17\",\"hidden\":\"F\"},{\"name\":\"Entry 18\",\"second_line\":\"Second Line 18\",\"hidden\":\"F\"},{\"name\":\"Entry 19\",\"second_line\":\"Second Line 19\",\"hidden\":\"F\"},{\"name\":\"EntryH 20\",\"second_line\":\"Second Line 20\",\"hidden\":\"T\"},{\"name\":\"Entry 21\",\"second_line\":\"Second Line 21\",\"hidden\":\"F\"},{\"name\":\"Entry 22\",\"second_line\":\"Second Line 22\",\"hidden\":\"F\"},{\"name\":\"Entry 23\",\"second_line\":\"Second Line 23\",\"hidden\":\"F\"}]"; 
     String[] items = sampleData.split("\\},\\{"); 
     for(String item: items){ 
      AListItem.clear(); 
      AListItem.load(item); 
      if(AListItem.getName().contains("Hide")){ 
       AListItem.setHidden("T"); 
      } 

      mDb.insert(SQLITE_TABLE, null, AListItem.getContentValues()); 

      ContentValues values = AListItem.getContentValues(); 
      Log.v(TAG, "values.toString()" + values.toString()); 
     } 
    } 

    public boolean deleteAll() { 
     int doneDelete = 0; 
     doneDelete = mDb.delete(SQLITE_TABLE, null , null); 
     Log.w(TAG, Integer.toString(doneDelete)); 
     return doneDelete > 0; 
    } 
} 

AListItem.java

public class AListItem { 

    static String rawInputString; 

    static String name; 
    static String second_line; 
    static String hidden; 

    static AListItem aListItem; 

    private AListItem() { 
    } 

    public static AListItem getInstance(){ 
     if (aListItem == null) { 
      aListItem = new AListItem(); 
     } 
     return aListItem; 
    } 

    public static void clear() { 
     rawInputString = null; 
     name = null; 
     second_line = null; 
     hidden = null; 
    } 

    public static ContentValues getContentValues() { 
     ContentValues values = new ContentValues(); 
     values.put("NAME", name); 
     values.put("SECOND_LINE", second_line); 
     values.put("HIDDEN", hidden); 
     return values; 
    } 


    public static void load(String string) { 
     StringBuffer buf = new StringBuffer(string); 
     if (buf.substring(0,2).equals("[{")){ 
      buf.delete(0,2); 
     } 
     rawInputString = buf.toString(); 
     parse(); 
    } 

    public static void parse() { 

     if (rawInputString == null) { 
      System.out.println("nothing to parse"); 
      return; 
     } 

     rawInputString = rawInputString.replaceAll("\"\\:null,", "\"\\:\"null\","); 
     String[] nvpa = rawInputString.split("\",\""); 
     for (String nvpString : nvpa) { 
      String[] nvpItem = nvpString.split("\":\""); 
      if (nvpItem.length < 2) continue; 
      String identifier = nvpItem[0].replaceAll("\"", ""); 
      String content = nvpItem[1].replaceAll("\"", ""); 

      switch (identifier) { 
       case "name": 
        setName(content); 
        break; 
       case "second_line": 
        setSecond_line(content); 
        break; 
       case "hidden": 
        setHidden(content); 
        break; 
       default: 
        System.out.println("nowhere to put [" + nvpItem[0] + "] " + nvpString + " raw: " + rawInputString); 
        break; 
      } 
     } 
    } 

    public static String getName() { 
     return name; 
    } 

    public static void setName(String name) { AListItem.name = name; } 

    public static void setSecond_line(String second_line) { 
     AListItem.second_line = second_line; 
    } 

    public static String getSecond_line() { 
     return second_line; 
    } 

    public static void setHidden(String hidden) { 
     AListItem.hidden = hidden; 
    } 

    public static String getHidden() { 
     return hidden; 
    } 

    public String toString() { 
     return getName() + ", " + 
       getSecond_line() + ", " + 
       getHidden(); 
    } 

} 

MySimpleCursorAdapter.java

public class MySimpleCursorAdapter extends SimpleCursorAdapter { 

    Context context; 
    Cursor cursor; 
    public static final String TAG = "MySimpleCursorAdapter"; 

    public MySimpleCursorAdapter(Context context, int layout, Cursor cursor, String[] from, int[] to, int flags) { 
     super(context, layout, cursor, from, to, flags); 
     this.context = context; 
     this.cursor = cursor; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     Log.v(TAG,"getView() >>>>>>STARTING"); 

     ViewHolder viewHolder; 
     LayoutInflater inflater = LayoutInflater.from(context); 
     if (null == convertView || null == convertView.getTag()) { 
      convertView = inflater.inflate(R.layout.b_item, null); 
      viewHolder = new ViewHolder(convertView); 
     } else { 
      viewHolder = (ViewHolder) convertView.getTag(); 
     } 

     for (int i = 0; i < cursor.getColumnCount(); i++) { 
      Log.v(TAG, "getView cursor " + i + ": " + cursor.getString(i)); 
     } 

     String hidden = cursor.getString(ViewHolder.HIDDEN); 
     if (hidden == null) hidden = "F"; 
     Log.v(TAG,"Hidden State: " + hidden); 
     switch (hidden) { 
      case "F": 
       viewHolder.showSecondLine(); // DRS 20160827 - Added line suggested by aiwiguna 
       break; 
      case "T": 
       Log.v(TAG,">>>>>Hidden was TRUE<<<<<<<: " + cursor.getString(ViewHolder.NAME)); 
       viewHolder.hideSecondLine(); 
       break; 
     } 

     convertView.setTag(viewHolder); 
     View returnView = super.getView(position, convertView, parent); 

     Log.v(TAG,"getView() ENDING<<<<<<<<<"); 

     return returnView; 
    } 
} 

ViewHolder.java

class ViewHolder { 

    public static final String TAG = "ViewHolder"; 

    public static final int DB_ITEM = 0; 
    public static final int NAME = 1; 
    public static final int SECOND_LINE = 2; 
    public static final int HIDDEN = 3; 

    public static final int[] viewsArray = new int[] { 
      R.id.bDbItem, 
      R.id.bName, 
      R.id.bSecondLine, 
      R.id.bHidden, 
    }; 

    public static final TextView[] textViewArray = new TextView[viewsArray.length]; 

    public ViewHolder(final View root) { 
     Log.v(TAG, "ViewHolder constructor"); 
     for (int i = 0; i < viewsArray.length; i++) { 
      textViewArray[i] = (TextView) root.findViewById(viewsArray[i]); 
      Log.v(TAG, "    textViewArray[" + i + "]: " + textViewArray[i]); 
     } 
    } 

    public void hideSecondLine() { 
     textViewArray[SECOND_LINE].setVisibility(View.INVISIBLE); 
    } 

    //DRS 20160827 - Addition recommended by aiwiguna 
    public void showSecondLine() { 
     textViewArray[SECOND_LINE].setVisibility(View.VISIBLE); 
    } 

} 

答えて

1

  1. ListViewSimpleCursorAdapter実装はRecyclerCursorAdapter実装で交換する必要があるRecyclerView、プラス
  2. に置き換える必要があります。

MyRecyclerCursorAdapter、例の新しいクラスは、RecyclerView.Adapter延び:このクラスはリストを移入するSQLiteのデータベースエントリへのリンクであるCursorオブジェクトを運ぶ

//DRS 20160829 - Added class. Replaces MySimpleCursorAdapter 
public class MyRecyclerCursorAdapter extends RecyclerView.Adapter{ 

    private Cursor cursor; 
    private Context context; 
    private static final String TAG = MyRecyclerCursorAdapter.class.getSimpleName(); 

    public MyRecyclerCursorAdapter(Context context, Cursor cursor) { 
     this.cursor = cursor; 
     this.context = context; 
    } 

    //DRS 20160829 - Critical method within new class 
    @Override 
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     Log.v(TAG, "onCreateViewHolder "); 
     Context context = parent.getContext(); 
     LayoutInflater inflater = LayoutInflater.from(context); 

     View itemView = inflater.inflate(R.layout.b_item, parent, false); 

     ViewHolder viewHolder = new ViewHolder(itemView, cursor); 
     return viewHolder; 
    } 

    //DRS 20160829 - Critical method within new class 
    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
     cursor.moveToPosition(position); 
     ((ViewHolder)holder).bindFields(cursor); 
    } 

    @Override 
    public int getItemCount() { 
     return cursor.getCount(); 
    } 
} 

留意されたいです。

また、リサイクラービューへのアクセスを得るためには、依存関係がbuild.gradleに追加する必要があります。

// DRS 20160829 - Added recyclerview 
dependencies { 
    compile fileTree(include: ['*.jar'], dir: 'libs') 
    testCompile 'junit:junit:4.12' 
    compile 'com.android.support:appcompat-v7:24.2.0' 
    compile 'com.android.support:recyclerview-v7:24.2.0' 
} 

b_item.xml

は何の変更を必要としません。
activity_lv_ca.xml古い ListViewの代わりに RecyclerViewを必要:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
      android:layout_width="fill_parent" android:layout_height="fill_parent" 
      android:orientation="vertical"> 

    <!-- DRS 20160829 - Commented ListView, Added RecyclerView 
    <ListView android:id="@+id/listView1" android:layout_width="fill_parent" 
      android:layout_height="fill_parent"/--> 
    <android.support.v7.widget.RecyclerView 
    android:id="@+id/recyclerView1" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:scrollbars="vertical" /> 

</LinearLayout> 

ViewHolderクラスは今Recycler.ViewHolderを拡張します。標準ViewHolderの実装を超えて、このカスタマイズされたViewHolderにはCursorもあり、リストの各行に表示されるTextViewsのテキストを設定するために使用されます。 。可視性は、私はbindFields()と呼ばれる方法で(管理されているところ、これがされています。何の変更を必要としない

public class ViewHolder extends RecyclerView.ViewHolder { 
    public static final String TAG = "ViewHolder"; 
    private final Cursor cursor; 

    public TextView bDbItem; 
    public TextView bName; 
    public TextView bSecondLine; 
    public TextView bHidden; 

    public static final int DB_ITEM = 0; 
    public static final int NAME = 1; 
    public static final int SECOND_LINE = 2; 
    public static final int HIDDEN = 3; 

    public ViewHolder(View root, Cursor cursor) { 
     super(root); 
     this.cursor = cursor; 
     Log.v(TAG, "ViewHolder constructor"); 
     bDbItem = (TextView) itemView.findViewById(R.id.bDbItem); 
     bName = (TextView) itemView.findViewById(R.id.bName); 
     bSecondLine = (TextView) itemView.findViewById(R.id.bSecondLine); 
     bHidden = (TextView) itemView.findViewById(R.id.bHidden); 
    } 

    public void bindFields(Cursor cursor) { 

     bDbItem.setText("" + cursor.getInt(DB_ITEM)); 
     bName.setText(cursor.getString(NAME)); 
     bSecondLine.setText(cursor.getString(SECOND_LINE)); 

     String hidden = cursor.getString(HIDDEN); 
     bHidden.setText(hidden); 
     if ("F".equals(hidden)) { 
      bSecondLine.setVisibility(View.VISIBLE); 
     } else { 
      bSecondLine.setVisibility(View.INVISIBLE); 
     } 
    } 
} 

AListItem.java一切の変更を必要としない
DBAdapter.java

動作するアプリケーションは、githubの上で見つけることができる:RecyclerViewSqlite

0

現在のソリューションでは、リサイクルされたビューで2番目の行を表示する必要があります。これを行う最も簡単な方法は、switchステートメントにあります。 FWIWでは、SQLiteテーブルに "hidden"フラグを整数値として格納することができます。これにより、比較が容易になり、おそらくやや速くなります。

もう1つの解決策は、通常の状況(hiddenが偽)と1つの "隠された"状況(hiddenが真)の2つの異なるレイアウトを持つことです。 MySimpleCursorAdapter.getView()では、ifステートメントは、どのレイアウトを展開するかを決定します。ビューがリサイクルされるときも、リサイクルされたビューが正しいタイプであることを確認してから、再利用すると同じ問題が発生します。このアプリケーションの作業を取得するために

+0

「RecyclerView」へのポインタありがとうございます。具体的にどのようにすればよいでしょうか? – Dale

+0

この単純な例では複数のレイアウトが論理的に見えますが、実際のアプリケーションではwhiこのサンプルアプリケーションでは、1つのTextViewを隠すほど簡単ではないので、効率的に管理するレイアウトが多すぎます。 – Dale

0
switch (hidden) { 
      case "F": 
       viewHolder.showSecondLine(); 
       break; 
      case "T": 
       Log.v(TAG,">>>>>Hidden was TRUE<<<<<<<: " + cursor.getString(ViewHolder.NAME)); 
       viewHolder.hideSecondLine(); 
       break; 
     } 
+0

提案していただきありがとうございます。残念なことに、この変化は「不安定な行動を改善しない」。私がこのサンプルアプリケーションを作成したとき(これはより大きい、より複雑なアプリケーションに基づいています)、私はそのアイテムを表示するアクションを無視しました。しかし、悲しいかな、違いはありません。 – Dale

関連する問題