Posted by custom View for the map

 public class MetroMapView extends ScrollView { Context ctx; List<Station> list; RelativeLayout v; LayoutInflater inflater; View station; DisplayMetrics metrics; HorizontalScrollView xScroller; List<View> stations; public MetroMapView(Context ctx, AttributeSet attrs) { super(ctx, attrs); this.ctx = ctx; inflater = (LayoutInflater)ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE); metrics = new DisplayMetrics(); ((GameActivity)ctx).getWindowManager().getDefaultDisplay().getMetrics(metrics); v = new RelativeLayout(ctx); v.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); v.setMinimumHeight(metrics.heightPixels * 2); v.setMinimumWidth(metrics.widthPixels * 3); xScroller = new HorizontalScrollView(ctx); xScroller.setScrollContainer(true); xScroller.addView(v); addView(xScroller); setScrollContainer(true); setVerticalScrollBarEnabled(true); setHorizontalScrollBarEnabled(true); } void setElements(ArrayList<Station> list) throws Exception { this.list = list; for(Station s : list) { View station = inflater.inflate(R.layout.station_view, v, true); station.setId(View.generateViewId()); station.setX(s.getX()); station.setY(s.getY()); v.addView(station); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } } 

In ScrollView sits HorizontalScrollView , and in it - RelativeLayout , in which I place the View . In the setElements method setElements I pass in a collection of stations. Each station has x and y coordinates. That's how I do in activity

 List<Station> stations = new ArrayList<>(); Station lt = new Station(0,0); Station rt = new Station(metrics.widthPixels * 3 - 50,0); Station lb = new Station(0,metrics.heightPixels * 2 - 50); Station rb = new Station(metrics.widthPixels * 3 - 50, metrics.heightPixels * 2 - 50); stations.add(lt); stations.add(rt); stations.add(lb); stations.add(rb); try { map.setElements(stations); } catch (Exception e) { Log.d("$", e.toString()); } 

As a result, I get such a log

The specified child already has a parent. You must call removeView () on the child's parent first.

But I do not understand what it means already busy. I find solutions where I need to delete the View , but I don’t need it, they should stay

    3 answers 3

    You have in the setElements(ArrayList<Station> list) method setElements(ArrayList<Station> list) in the following line:

     View station = inflater.inflate(R.layout.station_view, v, true); 

    The boolean parameter is true . This means that you are asking to attach the View station you are creating to the root View v , which you also pass as a parameter.

    And then say:

     v.addView(station); 

    and then your IllegalStateException .

    That's because inside the inflate method inflate when the true parameter is v.addView(station) already implicitly called, where the station remembers its parent . In the text of the error, and say "I do not want this uncle, I already have my Dad!" (free translation). It does not matter that this uncle is the same Pope, such a check is missing there :)

    You need to either remove the true parameter, or remove the v.addView(station); , depending on your xml markup.

    PS: Enough to carry around Context already; every View contains it in itself; you just need to call the getContext() method :)

    • The context in the custom view is a required constructor parameter, without it, do not call the parent's constructor and, accordingly, in the custom view you will not get the context using the getContext () method if it is not in the parent. - pavlofff
    • I'm not talking about the designer, but about the fact that he brings the Context into the class field :) - Artilirium
    • one
      if the context is passed to the class, it is more logical and more correct to keep it in the class field than constantly pulling the method. Permanent link is cheaper than calling the method - pavlofff
    • If it jerks 100 times per second, then yes, and if only during initialization, it increases the number of lines of code, which impairs readability. And if specifically, saving on the jerking of methods that are rarely called is saving on matches. - Artilirium
    • it's not even about saving on matches, but in code culture, android is a well-established practice with context and vice versa improves readability (especially if you read the standard view code and use it when creating your own). getContext () is an external method, for "external use", inside the view it is customary to use the class field. - pavlofff

    Try checking if you have already added a view. Those. instead

     v.addView(station); 

    Make:

     if(station.getParent() != null){ v.addView(station); } 
    • To no avail. Maybe this is due to the fact that the root is ScrollView , add to RelativeLayout ? But he is his child - Flippy
    • @Flippy, well, at least let me see exactly where it falls ... - YuriySPb

    The markup with which I inflatil was without a parent, that is, View . I wrapped it in LinearLayout and it all worked.