jjzjj

android recyclerview 不一致检测到无效的 recycler viewholder 位置

coder 2023-11-25 原文

我的应用程序中有回收站 View 。用户界面类似于 Google Play 商店应用。它有两个 View 寻呼机以及交替方式的项目列表和网格。所有数据都从网络服务中获取,并分为两个 API 调用。列表和网格的数据是从另一个 API 填充的。问题是当我快速滚动 recyclerview 时我遇到了这个崩溃。在滚动 recyclerview 时,用于在列表/网格中加载数据的 API 调用来自 bindData()。 阅读有关此主题的大量问题,但无法找到解决方案。

Fatal Exception: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{396df09 position=3 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent}
       at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4505)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4636)
       at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4617)
       at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)
       at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1390)
       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:2979)
       at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:2619)
       at android.view.View.measure(View.java:18811)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
       at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
       at android.support.v7.widget.CardView.onMeasure(CardView.java:208)
       at android.view.View.measure(View.java:18811)
       at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5952)
       at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
       at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
       at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
       at android.view.View.measure(View.java:18811)
       at android.support.v7.widget.RecyclerView$LayoutManager.measureChildWithMargins(RecyclerView.java:7487)
       at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1416)
       at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)
       at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:574)
       at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3028)
       at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2906)
       at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3283)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:122)
       at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
       at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1192)
       at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:814)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1187)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1743)
       at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1586)
       at android.widget.LinearLayout.onLayout(LinearLayout.java:1495)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.widget.FrameLayout.layoutChildren(FrameLayout.java:336)
       at android.widget.FrameLayout.onLayout(FrameLayout.java:273)
       at com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2680)
       at android.view.View.layout(View.java:16653)
       at android.view.ViewGroup.layout(ViewGroup.java:5438)
       at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2198)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1958)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1134)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6045)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
       at android.view.Choreographer.doCallbacks(Choreographer.java:672)
       at android.view.Choreographer.doFrame(Choreographer.java:608)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
       at android.os.Handler.handleCallback(Handler.java:739)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5441)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)

这是我的主要 recyclerview 适配器:

public class HomeScreenDataAdapterv2 extends RecyclerView.Adapter<HomeScreenViewHolder> {
    private HomeScreenActionHandler homeScreenActionHandler;
    private ArrayList<HomeScreenParentDataModel> homeScreenParentDataModels;

    public HomeScreenDataAdapterv2(ArrayList<HomeScreenParentDataModel> homeScreenParentDataModels) {
        this.homeScreenParentDataModels = homeScreenParentDataModels;
    }

    @Override
    public HomeScreenViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View holderView;
        Context ctx = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(ctx);
        switch (viewType) {
            case HomeScreenDataViewTypes.HOME_SCREEN_MAIN_BANNER_VIEW_TYPE:
                holderView = inflater.inflate(R.layout.home_main_banner_adapter, parent, false);
                return new HomeScreenMainBannerViewHolder(ctx, holderView, homeScreenActionHandler);

            case HomeScreenDataViewTypes.HOME_SCREEN_HOT_DEALS_VIEW_TYPE:
                holderView = inflater.inflate(R.layout.home_hot_deals_adapter, parent, false);
                return new HotDealsViewHolder(ctx, holderView, homeScreenActionHandler);

            case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCKS_LIST_VIEW_TYPE:
                holderView = inflater.inflate(R.layout.home_screen_dynamic_blocks_parent_list_adapter, parent, false);
                return new HomeScreenDynamicBlocksListViewHolder(ctx, holderView, homeScreenActionHandler);

            case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCK_GRID_VIEW_TYPE:
                holderView = inflater.inflate(R.layout.home_screen_dynamic_blocks_parent_grid_adapter, parent, false);
                return new HomeScreenDynamicBlocksGridViewHolder(ctx, holderView, homeScreenActionHandler);
            default:
                return null;
        }
    }

    @Override
    public void onBindViewHolder(HomeScreenViewHolder holder, int position) {
        HomeScreenParentDataModel homeScreenParentDataModel = homeScreenParentDataModels.get(position);
        switch (homeScreenParentDataModels.get(position).getHome_screen_view_type()) {
            case HomeScreenDataViewTypes.HOME_SCREEN_MAIN_BANNER_VIEW_TYPE:
                ((HomeScreenMainBannerViewHolder) holder).bindData((HomeBannerDataModel) homeScreenParentDataModel);
                break;

            case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCKS_LIST_VIEW_TYPE:
                ((HomeScreenDynamicBlocksListViewHolder) holder).bindListData((HomeScreenDynamicBlocksDataModel) homeScreenParentDataModel);
                break;

            case HomeScreenDataViewTypes.HOME_SCREEN_DYNAMIC_BLOCK_GRID_VIEW_TYPE:
                ((HomeScreenDynamicBlocksGridViewHolder) holder).bindGridData((HomeScreenDynamicBlocksDataModel) homeScreenParentDataModel);
                break;
        }
    }

    @Override
    public int getItemCount() {
        return homeScreenParentDataModels.size();
    }


    @Override
    public int getItemViewType(int position) {
        return homeScreenParentDataModels.get(position).getHome_screen_view_type();
    }

    private static class HomeScreenMainBannerViewHolder extends HomeScreenViewHolder {
        private Context ctx;
        private HomeScreenActionHandler homeScreenActionHandler;
        private ViewPager main_banner_view_pager;
        private CirclePageIndicator pager_indicator;

        HomeScreenMainBannerViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
            super(itemView);
            this.ctx = ctx;
            this.homeScreenActionHandler = homeScreenActionHandler;
            main_banner_view_pager = (ViewPager) itemView.findViewById(R.id.main_banner_view_pager);
            main_banner_view_pager.setClipToPadding(false);


    int padding = Util.convertDptoPixel(ctx, 9.0f);
                main_banner_view_pager.setPageMargin(
Util.convertDptoPixel(ctx, 9.0f));
            main_banner_view_pager.setPadding(padding, 0, padding, 0);
            pager_indicator = (CirclePageIndicator) itemView.findViewById(R.id.pager_indicator);
        }

        public void bindData(HomeBannerDataModel homeMainBannerDataModel) {
            HomeMainBannerPagerAdapter mainBannerAdapter = new HomeMainBannerPagerAdapter(ctx, homeMainBannerDataModel.getBannerList());
            mainBannerAdapter.setHomeScreenActionHandler(homeScreenActionHandler);
            main_banner_view_pager.setAdapter(mainBannerAdapter);
            pager_indicator.setViewPager(main_banner_view_pager);
        }
    }

    private static class HomeScreenDynamicBlocksListViewHolder extends HomeScreenViewHolder implements View.OnClickListener {
        private HomeScreenActionHandler homeScreenActionHandler;
        private RubikMediumTextView section_name;
        private RubikMediumButton btn_view_all;
        private RecyclerView dynamic_widgets_container;
        private Widget widget;
        private HomeScreenBlockListAdapter blockListAdapter;

        HomeScreenDynamicBlocksListViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
            super(itemView);
            this.homeScreenActionHandler = homeScreenActionHandler;
            section_name = (RubikMediumTextView) itemView.findViewById(R.id.section_name);
            btn_view_all = (RubikMediumButton) itemView.findViewById(R.id.btn_view_all);
            btn_view_all.setOnClickListener(this);

            dynamic_widgets_container = (RecyclerView) itemView.findViewById(R.id.dynamic_widgets_container);
            section_name.setTextColor(Color.parseColor("#546682"));
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx);
            linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
            linearLayoutManager.setAutoMeasureEnabled(true);
            dynamic_widgets_container.setLayoutManager(linearLayoutManager);
            dynamic_widgets_container.addItemDecoration(new DividerItemDecoration(ctx));
            dynamic_widgets_container.setNestedScrollingEnabled(false);
        }

        void bindListData(HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel) {
            widget = dynamicBlocksDataModel.getWidget();
            if (widget != null) {
                section_name.setText(widget.getName());
                ArrayList<BuyListingsModel> dynamicModels = widget.getDynamicDataModels();
                if (blockListAdapter == null) {
                    blockListAdapter = new HomeScreenBlockListAdapter(dynamicModels, homeScreenActionHandler);
                    dynamic_widgets_container.setAdapter(blockListAdapter);
                }
                if (dynamicModels.isEmpty()) {
                    homeScreenActionHandler.fetchWidgetData(widget.getName(), getAdapterPosition(), dynamicBlocksDataModel, blockListAdapter);
                }
            }
        }

        @Override
        public void onClick(View v) {
            if (homeScreenActionHandler != null && widget != null) {
                homeScreenActionHandler.gotoSearchResult(widget.getListingFilters());
            }
        }
    }

    private static class HomeScreenDynamicBlocksGridViewHolder extends HomeScreenViewHolder implements View.OnClickListener {
        private HomeScreenActionHandler homeScreenActionHandler;
        private RubikMediumTextView section_name;
        private RubikMediumButton btn_view_all;
        private RecyclerView dynamic_widgets_container;
        private Widget widget;
        private HomeScreenBlockGridAdapter blockGridAdapter;

        HomeScreenDynamicBlocksGridViewHolder(Context ctx, View itemView, HomeScreenActionHandler homeScreenActionHandler) {
            super(itemView);
            this.homeScreenActionHandler = homeScreenActionHandler;
            section_name = (RubikMediumTextView) itemView.findViewById(R.id.section_name);
            btn_view_all = (RubikMediumButton) itemView.findViewById(R.id.btn_view_all);
            btn_view_all.setOnClickListener(this);

            dynamic_widgets_container = (RecyclerView) itemView.findViewById(R.id.dynamic_widgets_container);
            GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 2);
            gridLayoutManager.setAutoMeasureEnabled(true);
            dynamic_widgets_container.addItemDecoration(new GridSpacingItemDecoration(2, 1, true));
            dynamic_widgets_container.setNestedScrollingEnabled(false);
            dynamic_widgets_container.setLayoutManager(gridLayoutManager);
        }

        void bindGridData(HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel) {
            widget = dynamicBlocksDataModel.getWidget();
            if (widget != null) {
                section_name.setText(widget.getName());
                ArrayList<BuyListingsModel> dynamicModels = widget.getDynamicDataModels();
                if (blockGridAdapter == null) {
                    blockGridAdapter = new HomeScreenBlockGridAdapter(dynamicModels, homeScreenActionHandler);
                    dynamic_widgets_container.setAdapter(blockGridAdapter);
                }

                if (dynamicModels.isEmpty()) {
                    homeScreenActionHandler.fetchWidgetData(widget.getName(), getAdapterPosition(), dynamicBlocksDataModel, blockGridAdapter);
                }
            }
        }

        @Override
        public void onClick(View v) {
            if (homeScreenActionHandler != null && widget != null) {
                homeScreenActionHandler.gotoSearchResult(widget.getListingFilters());
            }
        }
    }

    public interface HomeScreenActionHandler {
        void gotoCategoryListing(String categoryName);

        void gotoCategoryPage();

        void handleBannerClick(Banner banner);

        void gotoSearchResult(Bundle listingFiltersBundle);

        void fetchWidgetData(String widgetName, int adapterPosition, HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel, RecyclerView.Adapter listAdapter);

        void performWishlistAction(BuyListingsModel buyListingsModel, int childApdaterPosition, RecyclerView.Adapter listAdapter);

        void performBlockClick(String listing_id, boolean isInWatchlist);
    }

    public void setHomeScreenActionHandler(HomeScreenActionHandler homeScreenActionHandler) {
        this.homeScreenActionHandler = homeScreenActionHandler;
    }
}

这是在列表中加载数据的 API 调用:

public void fetchWidgetData(final String widgetName, final int adapterPosition,
                                final HomeScreenDynamicBlocksDataModel dynamicBlocksDataModel, final RecyclerView.Adapter listAdapter) {
        final Widget widget = dynamicBlocksDataModel.getWidget();

        Bundle b = widget.getListingFilters();
        HashMap<String, String> params = new HashMap<>();
        if (!b.containsKey("recently_sold"))
            params.put("isSearch", "1");
        Set<String> keySet = b.keySet();
        Iterator<String> it = keySet.iterator();
        while (it.hasNext()) {
            String key = it.next();
            params.put(key, b.getString(key));
        }
        Response.Listener<JSONObject> responseListener = new Response.Listener<JSONObject>() {

            @Override
            public void onResponse(JSONObject response) {
                                    try {
                    String code = response.getString("code");
                    if (code.equalsIgnoreCase("success")) {
                        JSONArray dataArray = response.getJSONArray("data");
                        ArrayList<BuyListingsModel> models = HomeScreenDataParser
                                .getDynamicBlocksModelList(dataArray);
                        if (models != null && !models.isEmpty()) {
                            ArrayList<BuyListingsModel> buyListingsModels = widget.getDynamicDataModels();
                            buyListingsModels.clear();
                            if (listAdapter != null) {
                                int size = models.size();
                                int upperbound = listAdapter instanceof HomeScreenBlockListAdapter ? 3 : 4;
                                for (int i = 0; i < size && i < upperbound; i++) {
                                    buyListingsModels.add(models.get(i));
                                }
                                listAdapter.notifyItemRangeInserted(0, buyListingsModels.size());

                            }
                            //homeScreenDataAdapterv2.notifyItemChanged(adapterPosition);
                        }
                    } else if (code.equalsIgnoreCase("failed")) {
                        handleError(response);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        };

        Response.ErrorListener errorListener = new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        };
        Api.getHomeScreenWidgetDetails(widgetName, responseListener, errorListener, ctx, params);

最佳答案

由于您实际上是在替换所有数据,因此调用 notifyItemRangeInserted() 而实际上没有向适配器中插入任何内容会引发此问题。您必须在将实际数据设置到适配器之后调用正确的通知程序,或者更准确地说是底层列表列表。

notifyItemRangeInserted(pos, count) 通知适配器期望在 pos 处插入 count 个项目。因此,列表的大小应该增加 count,而不仅仅是 count。由于您替换了所有数据,因此您应该改为调用 notifyDataSetChanged() 或使用 DiffUtil 来计算数据的实际差异。但这样一来,您就不必再担心要使用哪个通知了。

listAdapter.notifyDataSetChanged();

关于android recyclerview 不一致检测到无效的 recycler viewholder 位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43994845/

有关android recyclerview 不一致检测到无效的 recycler viewholder 位置的更多相关文章

  1. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  2. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  3. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  4. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  5. ruby - 如何排除无效日期 ruby - 2

    我想知道我应该引用什么异常名称。我的日期无效。我检查了文档,但找不到。BeginDate.new(day,month,year)Rescueexceptionnamestatements 最佳答案 我认为您正在寻找ArgumentError.使用irb:>Date.new(2,-200,3)ArgumentError:invaliddatefrom(irb):11:in`new'from(irb):11所以beginDate.new(2,-200,3)rescueArgumentError#yourlogicend

  6. ruby - 下载位置 Selenium-webdriver Cucumber Chrome - 2

    我将Cucumber与Ruby结合使用。通过Selenium-Webdriver在Chrome中运行测试时,我想将下载位置更改为测试文件夹而不是用户下载文件夹。我当前的chrome驱动程序是这样设置的:Capybara.default_driver=:seleniumCapybara.register_driver:seleniumdo|app|Capybara::Selenium::Driver.new(app,:browser=>:chrome,desired_capabilities:{'chromeOptions'=>{'args'=>%w{window-size=1920,1

  7. ruby - Heroku production.log 文件位置 - 2

    我想在heroku.com上查看我的应用程序日志的内容,所以我关注了thisexcellentadvice并拥有我所有的日志内容。但是我现在很想知道我的日志文件实际在哪里,因为“log/production.log”似乎是空的:C:\>herokuconsoleRubyconsoleforajpbrevx.heroku.com>>files=Dir.glob("*")=>["public","tmp","spec","Rakefile","doc","config.ru","app","config","lib","README","Gemfile.lock","vendor","sc

  8. ruby - 在 Ruby 中查找多个正则表达式匹配的模式和位置 - 2

    这应该是一个简单的问题,但我找不到任何相关信息。给定一个Ruby中的正则表达式,对于每个匹配项,我需要检索匹配的模式$1、$2,但我还需要匹配位置。我知道=~运算符为我提供了第一个匹配项的位置,而string.scan(/regex/)为我提供了所有匹配模式。如果可能,我需要在同一步骤中获得两个结果。 最佳答案 MatchDatastring.scan(regex)do$1#Patternatfirstposition$2#Patternatsecondposition$~.offset(1)#Startingandendingpo

  9. ruby - 检测由 RSpec、Ruby 运行的代码 - 2

    我想知道我的代码是否在rspec下运行。这可能吗?原因是我正在加载一些错误记录器,这些记录器在测试期间会被故意错误(expect{x}.toraise_error)弄得乱七八糟。我查看了我的ENV变量,没有(明显的)测试环境变量的迹象。 最佳答案 在spec_helper.rb的开头添加:ENV['RACK_ENV']='test'现在您可以在代码中检查RACK_ENV是否经过测试。 关于ruby-检测由RSpec、Ruby运行的代码,我们在StackOverflow上找到一个类似的问题

  10. ruby - 使用 Ruby Daemons gem 检测停止 - 2

    我正在使用rubydaemongem。想知道如何向停止操作添加一些额外的步骤?希望我能检测到停止被调用,并向其添加一些额外的代码。任何人都知道我如何才能做到这一点? 最佳答案 查看守护程序gem代码,它似乎没有用于此目的的明显扩展点。但是,我想知道(在守护进程中)您是否可以捕获守护进程在发生“停止”时发送的KILL/TERM信号...?trap("TERM")do#executeyourextracodehereend或者你可以安装一个at_exit钩子(Hook):-at_exitdo#executeyourextracodehe

随机推荐