草庐IT

android - RecyclerView 在 NotifyDataSetChanged() 后不更新,内容在打开和关闭屏幕后显示

coder 2023-12-12 原文

我是 Android 的新手,我正在与一群大学 friend 一起构建和应用程序。我们遇到的问题是,当通过从服务器获取数据来填充要显示的元素列表时,数据会加载并添加到列表中,但 recyclerView 从不显示它(即使在从我的自定义适配器调用 NotifyDataSetChanged 之后)。当我们使用硬编码数据来测试应用程序时,这从未发生过。

奇怪的是,在我关闭显示器然后重新打开它之后,元素列表显示在 recyclerView 上(当我重新打开屏幕时,我的自定义适配器的 onBindViewHolder 被调用)。此外,如果我用另一个替换包含 recyclerView 的 fragment ,然后将数据返回给它,数据已加载到列表但未显示。

我想知道的是为什么会发生这种情况以及我能做些什么来解决它(解决它我的意思是在我启动 fragment 时显示填充了正确项目的 recyclerView 并在我添加更多时更新 recyclerView列表中的元素)

我们使用自定义适配器和 Retrofit 从服务器获取数据。

这是代码

包含 recyclerView 的 fragment

    public class EventViewListFragment extends Fragment implements EventListAdapter.ClickListener{

    private RestClient restClient;
    private Builder builder;
    private String token ;

    private boolean userScrolled = true;
    int pastVisiblesItems, visibleItemCount, totalItemCount;

    private LinearLayoutManager mLayoutManager;

    private RecyclerView recyclerView;
    private EventListAdapter eventListAdapter;

    private Button btnNewEvent;

    FloatingActionButton suggestFAB;

    private int currentPage=1;


    public  EventViewListFragment(){
        restClient = new RestClient();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        System.out.println("Se llamo al onCreate de EventViewListFragment");
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        System.out.println("se llamo al onCreateView de EvENT List Fragment");
        // Inflate the layout for this fragment
        View layout =inflater.inflate(R.layout.fragment_events_list, container, false);
        setUpElements(layout);
        addListeners();
        return layout;
    }

    private void setUpElements(View layout)
    {
        recyclerView = (RecyclerView) layout.findViewById(R.id.eventList);
        eventListAdapter = new EventListAdapter(getActivity());
        eventListAdapter.setClickListener(this);
        eventListAdapter.setData(getInitialData());
        recyclerView.setAdapter(eventListAdapter);
        mLayoutManager=new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(mLayoutManager);
        suggestFAB = (FloatingActionButton)  layout.findViewById(R.id.suggestFAB);
        builder = new Builder();
    }

    private void addListeners()
    {
        addNewEventListener();
        addScrollBottomListener();
    }



    private void addNewEventListener()
    {
        /*btnNewEvent.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view)
            {
                EventsActivity.getInstance().toNewEventForm();
            }
        });*/

        suggestFAB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                EventsActivity.getInstance().toNewEventForm();
                currentPage=1;
            }
        });
    }

    public List<Event> getInitialData()
    {
        List<Event> data=new ArrayList<>();
        data = getEvents(data);
        return data;
    }

    @Override
    public void itemClicked(View view, int position) {
        EventsActivity.getInstance().toEventPage(eventListAdapter.getItemAtPos(position));
        currentPage=1;

    }
    private void addScrollBottomListener() {
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {

                super.onScrollStateChanged(recyclerView, newState);
                if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                    userScrolled = true;

                }

            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx,
                                   int dy) {

                super.onScrolled(recyclerView, dx, dy);
                // Here get the child count, item count and visibleitems
                // from layout manager

                visibleItemCount = mLayoutManager.getChildCount();
                totalItemCount = mLayoutManager.getItemCount();
                pastVisiblesItems = mLayoutManager.findFirstVisibleItemPosition();
                if (userScrolled && (visibleItemCount + pastVisiblesItems) == totalItemCount) {
                    userScrolled = false;

                    addNewElementsToList();
                }

            }

        });

    }

    private void addNewElementsToList()
    {
        Toast.makeText(getActivity(), "Cargando Mas Elementos", Toast.LENGTH_SHORT).show();
        eventListAdapter.setData(getEvents(eventListAdapter.getData()));
    }

    private List<Event> getEvents(final List<Event> eventsList)
    {
        System.out.println("Asignando CALL");
        Call<JsonElement> eventPage = restClient.getConsumerService().getEvents(token, "", currentPage, 10);
        System.out.println("Enquequeing");
        eventPage.enqueue(new Callback<JsonElement>() {
            @Override
            public void onResponse(Response<JsonElement> response) {
                JsonObject responseBody = response.body().getAsJsonObject();
                if (responseBody.has("events")) {
                    JsonArray jsonArray = responseBody.getAsJsonArray("events");
                    System.out.println(jsonArray.size());
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JsonObject storedObject = jsonArray.get(i).getAsJsonObject();
                        Event current = new Event();
                        current.setEventId(storedObject.get("id").getAsInt());
                        current.setName(storedObject.get("title").getAsString());
                        Calendar startCal = new GregorianCalendar();
                        startCal.setTimeInMillis((storedObject.get("starts_at").getAsLong()) * 1000);
                        current.setStartDateTime(startCal);
                        Calendar endCal = new GregorianCalendar();
                        endCal.setTimeInMillis((storedObject.get("ends_at").getAsLong()) * 1000);
                        current.setFinishDateTime(endCal);
                        current.setImgUrl(storedObject.get("image").getAsString());
                        eventsList.add(current);
                    }
                } else {
                    if (responseBody.has("error")) {
                        System.out.println("ERROR");
                        wan.wanmarcos.models.Error error = builder.buildError(responseBody.get("error").getAsJsonObject());
                        Toast.makeText(getActivity(), "Error : " + error.toString(), Toast.LENGTH_SHORT).show();
                    } else {

                    }
                }
            }

            @Override
            public void onFailure(Throwable t) {
            }
        });
        eventListAdapter.notifyDataSetChanged();
        currentPage++;
        return eventsList;
    }
}

RecyclerView 的自定义适配器

    public class EventListAdapter extends  RecyclerView.Adapter<EventListAdapter.EventListViewHolder>{
    private LayoutInflater inflater;
    private List<Event> data = Collections.emptyList();
    private Context context;
    private ClickListener clickListener;

    public EventListAdapter(Context context){
        inflater = LayoutInflater.from(context);
        this.context=context;
    }

    @Override
    public EventListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =  inflater.inflate(R.layout.event_list_item, parent, false);
        EventListViewHolder holder = new EventListViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(EventListViewHolder holder, int position) {
        System.out.println("se llamo al onBindViewHolder de ELA");
        Event current = getData().get(position);
        holder.title.setText(current.getName());
        Picasso.with(context)
                .load(current.getImgUrl())
                .into(holder.img);
        String startDateAndTime = current.CalendarToString(current.getStartDateTime())+" - "+current.CalendarToString(current.getFinishDateTime());
        holder.dateAndTime.setText(startDateAndTime);
    }

    public void setClickListener(ClickListener clickListener){

        this.clickListener=clickListener;
    }

    @Override
    public int getItemCount() {

        return getData().size();
    }

    public List<Event> getData() {
        return data;
    }

    public void setData(List<Event> data) {
        this.data = data;
    }

    class EventListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        TextView title;
        TextView dateAndTime;
        ImageView img;

        public EventListViewHolder(View itemView) {

            super(itemView);
            itemView.setOnClickListener(this);
            title = (TextView) itemView.findViewById(R.id.eventListTitle);
            img = (ImageView) itemView.findViewById(R.id.eventListImage);
            dateAndTime =(TextView) itemView.findViewById(R.id.eventListDateAndTime);
        }


        @Override
        public void onClick(View v) {

            if(clickListener!=null)
            {
                clickListener.itemClicked(v,getPosition());
            }
        }

    }

    public Event getItemAtPos(int pos)
    {
        return getData().get(pos);
    }


    public interface ClickListener{
        public void itemClicked(View view,int position);
    }



}

fragment XML 文件

    <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/main_content"
    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">

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="wan.wanmarcos.fragments.EventViewListFragment">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/eventList"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="vertical"
                >
            </android.support.v7.widget.RecyclerView>
    </RelativeLayout>

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/suggestFAB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|right"
        app:layout_anchorGravity="bottom|right|end"
        android:layout_margin="16dp"
        android:clickable="true"
        android:src="@mipmap/ic_add_white_48dp" />

</android.support.design.widget.CoordinatorLayout>

最佳答案

eventsList在你的Activitydata在您的适配器中有两个不同的集合。你正在填补前者而不是后者。 初始化 datanew ArrayList<>而不是 Collections.emptyList();然后在你的适配器中添加一个方法,调用 addAll,就像这样:

public void addAll(final List<Event> new events) {
      final int currentCount = data.size();
      synchronized(data) {
         data.addAll(events);
      }
      if (Looper.getMainLooper() == Looper.myLooper()) {
          notifyItemRangeInserted(currentCount, events.size());
      } else {
          new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                notifyItemRangeInserted(currentCount, events.size());
            }
          });
      }
}

if else 检查您是从 ui 线程还是从不同的线程调用 addAll 并调用 notifyItemRangeInserted以安全的方式。在Activity什么时候onResponse被调用,在你完全填满后 eventsList , 只需调用 eventListAdapter.addAll(eventsList)

关于android - RecyclerView 在 NotifyDataSetChanged() 后不更新,内容在打开和关闭屏幕后显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33605292/

有关android - RecyclerView 在 NotifyDataSetChanged() 后不更新,内容在打开和关闭屏幕后显示的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  4. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  5. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

  6. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  7. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  8. objective-c - 在设置 Cocoa Pods 和安装 Ruby 更新时出错 - 2

    我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U

  9. ruby - 如何使用 Selenium Webdriver 根据 div 的内容执行操作? - 2

    我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption

  10. ruby-on-rails - Rails Associations 的更新方法是什么? - 2

    这太简单了,太荒谬了,我在任何地方都找不到关于它的任何信息,包括API文档和Rails源代码:我有一个:belongs_to关联,我开始理解当您没有关联时您在Controller中调用的正常模型方法与您有关联时调用的方法略有不同。例如,我的关联在创建Controller操作时运行良好:@user=current_user@building=Building.new(params[:building])respond_todo|format|if@user.buildings.create(params[:building])#etcetera但我找不到关于更新如何工作的文档:@user

随机推荐