Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/212.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当搜索栏中的文本写入Recyclerview android时,调用notifyItemRangechanged_Android_Animation_Android Recyclerview_Searchview_Notify - Fatal编程技术网

当搜索栏中的文本写入Recyclerview android时,调用notifyItemRangechanged

当搜索栏中的文本写入Recyclerview android时,调用notifyItemRangechanged,android,animation,android-recyclerview,searchview,notify,Android,Animation,Android Recyclerview,Searchview,Notify,每当用户在搜索栏中键入内容时,我想在我的回收视图上添加动画。我已经实现了一个Filter方法来过滤项目,但未能在OnQuerytextChanged中调用notifyItemrangechanged,因此出现。我已经尝试过这样的方法: @Override public boolean onQueryTextChange(String newText) { istyping = true;

每当用户在
搜索栏中键入内容时,我想在我的
回收视图
上添加
动画
。我已经实现了一个
Filter
方法来过滤项目,但未能在
OnQuerytextChanged
中调用
notifyItemrangechanged
,因此出现。我已经尝试过这样的方法:

@Override
                public boolean onQueryTextChange(String newText) {


                    istyping = true;

                    ArrayList<String> templist = new ArrayList<>();

                    mSearchQuery = newText;

 //this line -->   adapter.notifyItemRangeChanged(0, namelistwithnumber.size());    <---



                    for (String temp : namelistwithnumber) {
                        if (temp.toLowerCase().contains(newText.toLowerCase())) {
                            templist.add(temp);
                        }
                    }

                    if (newText.isEmpty()){
                        mainlist.setAdapter(null);
                        adapter = new MyRecyclerViewAdapter(MainActivity.this, namelist);
                        mainlist.setAdapter(adapter);
                        adapter.notifyDataSetChanged();
                        istyping = false;
                    }

                    if (templist.size() == 0) {
                        mainlist.setAdapter(null);
                        noresults.setVisibility(View.VISIBLE);
                    } else {
                        if (!newText.isEmpty()){
                          adapter = new MyRecyclerViewAdapter(MainActivity.this, templist);
                            mainlist.setAdapter(adapter);
                            noresults.setVisibility(View.INVISIBLE);
                            adapter.setClickListener(MainActivity.this);

                        }
                        noresults.setVisibility(View.INVISIBLE);
                    }

                    return true;
                }
@覆盖
公共布尔onQueryTextChange(字符串newText){
istyping=true;
ArrayList templist=新的ArrayList();
mSearchQuery=newText;

//此行-->adapter.notifyItemRangeChanged(0,namelistwithnumber.size());每次创建新适配器时,这意味着没有以前的数据…这反过来意味着不能有任何动画;-)

您需要做的是在适配器中引用的活动中创建一个ArrayList

然后在发布的方法中修改ArrayList中的项,然后调用adapter.notifyItemRangeChanged(0,list.size()); 即

。。。
private ArrayList list=new ArrayList();
专用MyRecycleServiceAdapter适配器;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...
//创建适配器并引用ArrayList
适配器=新的MyRecycleServiceAdapter(MainActivity.this,列表);
...
@凌驾
公共布尔onQueryTextChange(字符串newText){
istyping=true;
ArrayList templist=新的ArrayList();
mSearchQuery=newText;
for(字符串温度:namelistwithnumber){
if(temp.toLowerCase().contains(newText.toLowerCase())){
圣堂武士。添加(临时);
}
}
//无需设置新适配器,适配器已具有对ArrayList的引用
//所以只需修改它,并告诉适配器它已更改,动画将被处理
//自动地
list.clear();
list.addAll(圣殿骑士);
adapter.notifyItemRangeChanged(0,list.size());
...

每次创建新适配器时,这意味着没有以前的数据…这反过来意味着不可能有任何动画;-)

您需要做的是在适配器中引用的活动中创建一个ArrayList

然后在发布的方法中修改ArrayList中的项,然后调用adapter.notifyItemRangeChanged(0,list.size()); 即

。。。
private ArrayList list=new ArrayList();
专用MyRecycleServiceAdapter适配器;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
...
//创建适配器并引用ArrayList
适配器=新的MyRecycleServiceAdapter(MainActivity.this,列表);
...
@凌驾
公共布尔onQueryTextChange(字符串newText){
istyping=true;
ArrayList templist=新的ArrayList();
mSearchQuery=newText;
for(字符串温度:namelistwithnumber){
if(temp.toLowerCase().contains(newText.toLowerCase())){
圣堂武士。添加(临时);
}
}
//无需设置新适配器,适配器已具有对ArrayList的引用
//所以只需修改它,并告诉适配器它已更改,动画将被处理
//自动地
list.clear();
list.addAll(圣殿骑士);
adapter.notifyItemRangeChanged(0,list.size());
...

这是一个完整的工作示例。我从示例列表中查询单词,但您可以从db或web API中进行查询。我对recyclerView使用了固定的高度,以便可以看到所有动画。这里有很多概念在起作用:MVVM设计模式、LiveData、数据绑定等。要获得最佳结果,没有简单的答案。如果不熟悉的话有了这些概念,我们就可以一个接一个地研究它们

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}
MainViewModel.java

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}
活动\u main.xml

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

这是一个完整的工作示例。我从示例列表中查询单词,但您可以从db或web API中进行查询。我对recyclerView使用了固定的高度,以便可以看到所有动画。这里有很多概念在工作:MVVM设计模式、LiveData、数据绑定等。要获得最佳结果,没有简单的答案。如果不熟悉ese概念会逐一进行研究

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}
MainViewModel.java

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}
活动\u main.xml

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private SearchAdapter searchAdapter;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        searchAdapter = new SearchAdapter();
        binding.recycler.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, false));
        binding.recycler.setAdapter(searchAdapter);

        observeData();

        viewModel.queryWord("");

        binding.search.setOnQueryTextListener((new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                viewModel.queryWord(query);
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                viewModel.queryWord(newText);
                return false;
            }
        }));
    }

    private void observeData() {
        viewModel.getResult().observe(this, result -> {
            searchAdapter.submitList(result);
        });
    }
}
public class MainViewModel extends AndroidViewModel {

    private ArrayList<String> namelistwithnumber;

    MutableLiveData<List<SearchResult>> result = new MutableLiveData<>();

    public MainViewModel(@NonNull Application application) {
        super(application);
        namelistwithnumber = new ArrayList(Arrays.asList("aa", "ab", "ac", "ad", "ba", "bb", "bc", "bd", "ca", "cb", "cc", "cd", "da", "db", "dc", "dd"));
    }

    public void queryWord(String word) {
        ArrayList<SearchResult> templist = new ArrayList<>();
        int id = 0;

        if (word.equals("")) {
            for (String temp : namelistwithnumber) {
                id++;
                SearchResult anItem = new SearchResult(id, temp);
                templist.add(anItem);
            }
        } else {
            for (String temp : namelistwithnumber) {
                if (temp.toLowerCase().contains(word.toLowerCase())) {
                    id++;
                    SearchResult anItem = new SearchResult(id, temp);
                    templist.add(anItem);
                }
            }
        }
        result.setValue(templist);
    }

    public MutableLiveData<List<SearchResult>> getResult() {
        return result;
    }
}
public class SearchAdapter extends ListAdapter<SearchResult, SearchAdapter.ViewHolder> {

    private LayoutInflater mInflater;
    private Context context;

    public SearchAdapter() {
        super(DIFF_CALLBACK);
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        context = parent.getContext();
        this.mInflater = LayoutInflater.from(context);
        ResultItemBinding binding = ResultItemBinding.inflate(mInflater, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        SearchResult searchResult= getItem(position);
        holder.bind(searchResult);
    }


    public static class ViewHolder extends RecyclerView.ViewHolder {
        ResultItemBinding binding;

        ViewHolder(ResultItemBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }

        void bind(SearchResult item) {
            binding.setResult(item);
        }
    }


    public static final DiffUtil.ItemCallback<SearchResult> DIFF_CALLBACK =
            new DiffUtil.ItemCallback<SearchResult>() {
                @Override
                public boolean areItemsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // User properties may have changed if reloaded from the DB, but ID is fixed
                    return oldUser.getWord().equals(newUser.getWord());
                }

                @Override
                public boolean areContentsTheSame(
                        @NonNull SearchResult oldUser, @NonNull SearchResult newUser) {
                    // NOTE: if you use equals, your object must properly override Object#equals()
                    // Incorrectly returning false here will result in too many animations.
                    return oldUser.getWord().equals(newUser.getWord());
                }
            };
}
public class SearchResult {
    private long id;
    private String word;

    public SearchResult(long id, String word) {
        this.id = id;
        this.word = word;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getWord() {
        return word;
    }

    public void setWord(String word) {
        this.word = word;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.SearchView
                android:id="@+id/search"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recycler"
                android:layout_width="match_parent"
                android:layout_height="600dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/search" />


        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.core.widget.NestedScrollView>

</layout>
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="result"
            type="com.example.recyclerviewtest.SearchResult" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp">

        <TextView
            android:id="@+id/word"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:gravity="start|center_vertical"
            android:maxLines="1"
            android:text="@{result.word}"
            android:textColor="#000"
            android:textSize="16sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.example.recyclerviewtest"
        minSdkVersion 28
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        // for view binding:
        // viewBinding true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains:annotations-java5:15.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}

新浪的回答似乎很好,它有很好的实践(除了冗余数据绑定),但既然您不接受它,我想您不想用这些附加概念重写代码。下面是一个简单的解决方案:

  • setHassTableId(true)
    设置为适配器
  • 覆盖适配器内部的getItemId(内部位置)
  • DefaultItemAnimator()
    添加到RecyclerView

  • 分步指南:

    1.将默认项Animator添加到回收视图中

    mainlist.setItemAnimator(new DefaultItemAnimator());
    
    2.向适配器添加更新列表的功能

    您不应该每次更改项目列表时都重新初始化您的
    MyRecycleServiceAdapter
    。从构造函数中删除列表!而是在dapter类中声明成员varialbe
    List nameListWithNumber=new ArrayList();
    ,并向适配器添加函数:

    public void setItems(List<NameListwithNumber> newItems){
    nameListWithNumber.clear();
    nameListWithNumber.addAll(newItems);
    notifydatasetChanged();
    }
    
    (我不确定为什么需要适配器tho中的活动实例)

    并在
    onCreate()方法中初始化它

     myAdapter = new MyRecyclerViewAdapter(MainActivity.this);
     myAdapter.setHasStableIds(true);
     mainList.setAdapter(myAdapter);
    
    4.覆盖适配器内部的getItemId(int位置)

    在适配器内部添加以下功能:

    @Override
    public long getItemId(int position) {
       return nameListWithNumber.get(position).id;
    }
    
    如果您的模型没有唯一id,只需使用
    返回nameListWithNumber.get(position).hashCode();


    最后 在您的
    公共布尔onQueryTextChange(字符串newText)
    你需要改变

      if (newText.isEmpty()) {
           adapter.setItems(nameList)
           istyping = false;
        }
      else {
        adapter.setItems(tempList)
        noresults.setVisibility(templist.size() == 0 ? View.VISIBLE : View.INVISIBLE)
    }
    

    这是完全相同的方法的结果,只是过滤方式不同


    新浪的答案似乎不错,它有很好的做法(除了redund)