将过滤器应用于列表后,TextWatcher 和 ListView 元素的位置出现问题

Posted

技术标签:

【中文标题】将过滤器应用于列表后,TextWatcher 和 ListView 元素的位置出现问题【英文标题】:Problem with TextWatcher and position of ListView element after applying the filter to the list 【发布时间】:2021-04-18 23:13:21 【问题描述】:

我正在开发一个 android 应用程序,它显示一个包含 SQL 数据库数据的列表视图。

单击列表视图元素后,将打开一个包含有关它的信息的新 Activity。

我已经实现了Textwatcher 来在列表中进行搜索,并且列表会更新,因为它应该可以工作。

问题是,当我单击更新列表的列表元素时,它会打开一个包含旧位置数据的活动,例如通过单击 Zinn ID:939。它会打开一个具有 Altbach ID:940 数据的新活动。 在TextWatcher 工作后更新元素位置并将其传递给onItemClick 方法的最佳方法是什么?或者我怎样才能在TextWatcher 工作后获得更新的列表? 提前谢谢!

那是我的课。

    public class LibraryActivity extends AppCompatActivity implements View.OnClickListener 

    static String db_name = "test_stolpersteine_db.sqlite";
    StolpersteineDAO stolpersteinedao;
    List<Stolpersteine> stolpersteine_list;
    ListView list_view;
    private ArrayAdapter<CharSequence> adapter;

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

        ////////////////////////////// Database ////////////////////////////////////////////////////
        final File dbFile = this.getDatabasePath(db_name); // we create a database path

        if (!dbFile.exists())      // we checking if the directory is existing
            try 
                copyDatabaseFile(dbFile.getAbsolutePath());  // method to copy the database
             catch (IOException e) 
                e.printStackTrace();
            
        

        ////// Database
        startDatabase();
        stolpersteine_list = stolpersteinedao.getAllStolpersteine();
        list_view = findViewById(R.id.list);
        adapter = createAdapterhtml(stolpersteine_list);
        list_view.setAdapter(adapter);
        ////////////////////////////// Database ////////////////////////////////////////////////////

        //////////////////////////// Buttons ///////////////////////////////////////////////////////
        Button button_home = findViewById(R.id.button_home);
        Button button_map = findViewById(R.id.button_map);
        Button button_library = findViewById(R.id.button_library);

        button_home.setOnClickListener(this);
        button_map.setOnClickListener(this);
        button_library.setOnClickListener(this);

        button_library.setEnabled(false);
        /////////////////////////// Buttons ////////////////////////////////////////////////////////

        EditText theFilter = findViewById(R.id.edit_text);

        theFilter.addTextChangedListener(new TextWatcher() 
            @Override
            public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) 
            
            @Override
            public void onTextChanged(CharSequence charSequence, int start, int before, int count) 
                (LibraryActivity.this).adapter.getFilter().filter(charSequence);
            
            @Override
            public void afterTextChanged(Editable charSequence) 
            
        );

        //// OnClickListener
        list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() 


            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) 

                String url = stolpersteine_list.get(position).getURL();
                Intent i = new Intent(getApplicationContext(), RecordActivity.class);

                i.putExtra("url", url);
                i.putExtra("first_name", stolpersteine_list.get(position).getFirst_Name());
                i.putExtra("name", stolpersteine_list.get(position).getName());
                startActivity(i);


              // end of listener

        );

     // end of onCreate method
    

    ////////////////////////////// Database ////////////////////////////////////////////////////////
    private void copyDatabaseFile(String destinationPath) throws IOException 

        InputStream assetsDB = this.getAssets().open(db_name);
        OutputStream dbOut = new FileOutputStream(destinationPath);

        byte[] buffer = new byte[1024];

        int length;

        while ((length = assetsDB.read(buffer)) > 0) 

            dbOut.write(buffer, 0, length);
        

        dbOut.flush();
        dbOut.close();
     //end of copyDatabaseFile method


    private ArrayAdapter<CharSequence> createAdapterHtml(List<Stolpersteine> s_list) 

        Spanned[] html_array = new Spanned[s_list.size()];

        for (int i = 0; i < s_list.size(); i++) 
            html_array[i] = Html.fromHtml(
                    s_list.get(i).getName()
                    + " "
                    + "ID: "+ s_list.get(i).getID() + "<br></i>"

                    + s_list.get(i).getHouse_Number() +" "
                    + s_list.get(i).getHouse_Number_Extension() + "</i>");
        

        ArrayAdapter<CharSequence> my_adapter =
                new ArrayAdapter<CharSequence>(this, R.layout.list_item, html_array);

        return my_adapter;

     // end of createAdapterHtml

    private void startDatabase() 
        AppDatabase database = Room.databaseBuilder(this, AppDatabase.class, db_name)
                .allowMainThreadQueries()
                .build();

        stolpersteinedao = database.getStolpersteineDAO();

     // end of startDatabase method
    ////////////////////////////// Database ////////////////////////////////////////////////////////

    @Override
    public void onClick(View v) 

        switch (v.getId()) 
            case R.id.button_home:
                startActivity(new Intent(this, MainActivity.class));
                break;
            case R.id.button_map:
                startActivity(new Intent(this, MapboxActivity.class));
                break;
            case R.id.button_library:
                startActivity(new Intent(this, LibraryActivity.class));
                break;
        

    
 // end of class

【问题讨论】:

请提供您如何过滤列表 我使用 Textwatcher 自动过滤列表。我也可以使用带有 getSearchResult 方法的 DAO public interface StolpersteineDAO @Query("SELECT * FROM stolpersteine_table ORDER BY name ASC") public List getAllStolpersteine(); @Query("SELECT * FROM stolpersteine_table WHERE (name || first_name || street LIKE '%' || :keyword_to_search_for || '%') ORDER BY name ASC") // 相同的行但与 public List getSearchResults( String keyword_to_search_for); 【参考方案1】:

问题是onItemClick()回调有一个过滤列表后位置的参数;即这个位置是相对于过滤列表而不是原始列表的,尽管您需要从原始列表中获取实际位置。

要获取原始位置(不是过滤后的),您可以先获取过滤后的项目,然后使用原始列表中的indexOf() 获取其位置。

要应用此功能,请将 list_view OnItemClickListener 更改为:

//// OnClickListener
list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() 

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
        
        // Getting the clicked item from the filtered list
        Stolpersteine filteredItem = (Stolpersteine) ((ListView) parent).getAdapter().getItem(position);

        // Getting the original position
        int originalPos = getList().indexOf(filteredItem);

        // Use originalPos instead of position in your code:
        
        String url = stolpersteine_list.get(originalPos).getURL();
        Intent i = new Intent(getApplicationContext(), RecordActivity.class);

        i.putExtra("url", url);
        i.putExtra("first_name", stolpersteine_list.get(originalPos).getFirst_Name());
        i.putExtra("name", stolpersteine_list.get(originalPos).getName());
        startActivity(i);


      // end of listener
);

【讨论】:

以上是关于将过滤器应用于列表后,TextWatcher 和 ListView 元素的位置出现问题的主要内容,如果未能解决你的问题,请参考以下文章

将过滤器应用于列表并显示数据

如何将 dplyr 过滤器应用于数据框列表?

将条件应用于列列表的数据框过滤

防止“输入键”触发 TextWatcher

从控制器将变量应用于视图中的按钮?Sencha Touch

在过滤器 findAny 之前,地图是不是应用于所有列表?