0

I have recently developed a Android app that displays tourist attractions. the List passed to the RecyclerView.Adapter has already sorted by the distance between the destination and capital city. For example,

  • SYDNEY|Sydney Opera House|174m
  • SYDENY|The Strand Arcade|391m
  • SYDNEY|Darling Harbour|1.5km
  • SYDNEY|Sydney Harbour Bridge|1.7km
  • SYDNEY|Bondi Beach|6.5km
  • SYDNEY|Blue Mountains|84.6km
  • SYDNEY|Jenolan Caves|104.4km
  • SYDNEY|Hunter Valley|117.2km
  • SYDNEY|Hyams Beach|144.5km
  • SYDNEY|Whale Watching|224.6km
  • SYDNEY|Taronga Western Plains Zoo|331.8km
  • SYDNEY|Thredbo - snow resorts|393.7km

The problem is when i lunch the app that the items are displayed in different orders with different mobile devices or emulators. For example,

Pixel XL

Pixel XL

Nexus 5X

Nexus 5X

I have been looking for the solution for a few days with no success. Would anyone here help me would be much appreciated. Below is my layout and adapter.

    implementation 'com.android.support:recyclerview-v7:27.1.0'



        public class AttractionListFragment extends Fragment {
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {

                attractions = populateAttractionData(ausAttractionList, state, mSelectedStateLat);
View view = inflater.inflate(R.layout.fragment_main, container, false);
                mAdapter = new AttractionAdapter(getActivity(), attractions);
                AttractionsRecyclerView recyclerView =  (AttractionsRecyclerView) view.findViewById(android.R.id.list);
                recyclerView.setEmptyView(view.findViewById(android.R.id.empty));
                recyclerView.setHasFixedSize(true);
                recyclerView.setAdapter(mAdapter);

                return view;
            }


            private class AttractionAdapter extends RecyclerView.Adapter<ViewHolder>
                implements ItemClickListener {

            public List<Attraction> mAttractionList;
            private Context mContext;

            public AttractionAdapter(Context context, List<Attraction> attractions) {
                super();
                mContext = context;
                mAttractionList = attractions;
            }

            @Override
            public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                LayoutInflater inflater = LayoutInflater.from(mContext);
                View view = inflater.inflate(R.layout.list_row, parent, false);
                return new ViewHolder(view, this);
            }

            @Override
            public void onBindViewHolder(ViewHolder holder, int position) {
                Attraction attraction = mAttractionList.get(position);

                    holder.mTitleTextView.setText(attraction.name);
                    holder.mDescriptionTextView.setText(attraction.description);

                    Glide.with(mContext)
                        .load(attraction.imageUrl)
                        .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                        .placeholder(R.drawable.empty_photo)
                        .override(mImageSize, mImageSize)
                        .into(holder.mImageView);

                   holder.mOverlayTextView.setText(attraction.distance);
            }

            @Override
            public long getItemId(int position) {
                return position;
            }

            @Override
            public int getItemCount() {
                return mAttractionList == null ? 0 : mAttractionList.size();
            }

            @Override
            public void onItemClick(View view, int position) {
                if (!mItemClicked) {
                    mItemClicked = true;
                    View heroView = view.findViewById(android.R.id.icon);
                    DetailActivity.launch(getActivity(), mAdapter.mAttractionList.get(position).name, heroView);
                }
            }
        }


            private static class ViewHolder extends RecyclerView.ViewHolder
                implements View.OnClickListener {

            TextView mTitleTextView;
            TextView mDescriptionTextView;
            TextView mOverlayTextView;
            ImageView mImageView;
            ItemClickListener mItemClickListener;

            public ViewHolder(View view, ItemClickListener itemClickListener) {
                super(view);
                mTitleTextView = (TextView) view.findViewById(android.R.id.text1);
                mDescriptionTextView = (TextView) view.findViewById(android.R.id.text2);
                mOverlayTextView = (TextView) view.findViewById(R.id.overlaytext);
                mImageView = (ImageView) view.findViewById(android.R.id.icon);
                mItemClickListener = itemClickListener;
                view.setOnClickListener(this);
            }

            @Override
            public void onClick(View v) {
                mItemClickListener.onItemClick(v, getAdapterPosition());
            }
        }


        interface ItemClickListener {
            void onItemClick(View view, int position);
        }

    public class AttractionsRecyclerView extends RecyclerView {
        private View mEmptyView;

        private AdapterDataObserver mDataObserver = new AdapterDataObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
                updateEmptyView();
            }
        };

        public AttractionsRecyclerView(Context context) {
            super(context);
        }

        public AttractionsRecyclerView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public AttractionsRecyclerView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        /**
         * Designate a view as the empty view. When the backing adapter has no
         * data this view will be made visible and the recycler view hidden.
         *
         */
        public void setEmptyView(View emptyView) {
            mEmptyView = emptyView;
        }

        @Override
        public void setAdapter(RecyclerView.Adapter adapter) {
            if (getAdapter() != null) {
                getAdapter().unregisterAdapterDataObserver(mDataObserver);
            }
            if (adapter != null) {
                adapter.registerAdapterDataObserver(mDataObserver);
            }
            super.setAdapter(adapter);
            updateEmptyView();
        }

        private void updateEmptyView() {
            if (mEmptyView != null && getAdapter() != null) {
                boolean showEmptyView = getAdapter().getItemCount() == 0;
                mEmptyView.setVisibility(showEmptyView ? VISIBLE : GONE);
                setVisibility(showEmptyView ? GONE : VISIBLE);
            }
        }
    }


fragment_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="2dp"
        android:orientation="vertical"
        tools:context=".ui.AttractionListFragment">


        <HorizontalScrollView
            android:layout_width="366dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginLeft="2dp"
            android:layout_marginTop="10dp"
            android:layout_marginRight="2dp"
            android:layout_marginBottom="10dp"
            android:scrollbars="none">


            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                    <ImageView
                        android:id="@+id/id_things_to_do"
                        android:layout_width="150dp"
                        android:layout_height="120dp"
                        android:layout_alignParentTop="true"
                        android:layout_centerHorizontal="true"
                        android:layout_margin="2dp"
                        android:scaleType="center"
                        android:src="@drawable/vic_attraction_grampian" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/id_things_to_do"
                        android:gravity="center"
                        android:text="@string/things_to_do"
                        android:textSize="15sp" />
            </LinearLayout>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <ImageView
                        android:id="@+id/id_one_day_tour"
                        android:layout_width="150dp"
                        android:layout_height="120dp"
                        android:layout_alignParentTop="true"
                        android:layout_centerHorizontal="true"
                        android:layout_margin="2dp"
                        android:scaleType="centerCrop"
                        android:src="@drawable/vic_attraction_grampian" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/id_one_day_tour"
                        android:text="@string/day_trip"
                        android:gravity="center"
                        android:textSize="15sp" />
                </LinearLayout>


                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <ImageView
                        android:id="@+id/id_two_day_tour"
                        android:layout_width="150dp"
                        android:layout_height="120dp"
                        android:layout_alignParentTop="true"
                        android:layout_centerHorizontal="true"
                        android:layout_margin="2dp"
                        android:scaleType="centerCrop"
                        android:src="@drawable/vic_attraction_grampian" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/id_two_day_tour"
                        android:gravity="center"
                        android:text="@string/two_days_tour"
                        android:textSize="15sp" />
                </LinearLayout>


                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">

                    <ImageView
                        android:id="@+id/id_three_day_tour"
                        android:layout_width="150dp"
                        android:layout_height="120dp"
                        android:layout_alignParentTop="true"
                        android:layout_centerHorizontal="true"
                        android:layout_margin="2dp"
                        android:scaleType="centerCrop"
                        android:src="@drawable/vic_attraction_grampian" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_below="@+id/id_three_day_tour"
                        android:gravity="center"
                        android:text="@string/three_days_tour"
                        android:textSize="15sp" />
                </LinearLayout>

            </LinearLayout>

        </HorizontalScrollView>

        <com.kplau.attractionsinAustralia.ui.AttractionsRecyclerView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="vertical"
            app:layoutManager="GridLayoutManager"
            app:spanCount="@integer/list_columns" />

        <TextView
            android:id="@android:id/empty"
            android:text="@string/empty_list"
            style="?android:attr/textAppearanceMedium"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:gravity="center" />

    </LinearLayout>




list_row.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:foreground="?attr/selectableItemBackground"
    android:layout_height="@dimen/image_size">



    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/gallery_list">


        <ImageView
            android:id="@android:id/icon"
            android:layout_width="@dimen/image_size"
            android:layout_height="match_parent"
            android:src="@drawable/empty_photo"
            android:scaleType="centerCrop"
            android:transitionName="image" />

        <TextView
            android:id="@+id/overlaytext"
            android:layout_width="@dimen/image_size"
            android:layout_height="wrap_content"
            android:layout_alignBottom="@android:id/icon"
            android:gravity="center"
            android:padding="@dimen/tiny_margin"
            style="?android:textAppearanceSmallInverse"
            android:background="@color/text_background"
            tools:text="Overlay"/>

        <TextView
            android:id="@android:id/text1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toEndOf="@android:id/icon"
            android:paddingTop="@dimen/small_margin"
            android:paddingLeft="@dimen/small_margin"
            android:paddingRight="@dimen/small_margin"
            android:maxLines="1"
            android:ellipsize="end"
            android:textSize="16sp"
            style="@style/TextAppearance.AppCompat.Body1"
            tools:text="Title 1" />

        <TextView
            android:id="@android:id/text2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toEndOf="@android:id/icon"
            android:layout_below="@android:id/text1"
            android:padding="@dimen/small_margin"
            android:ellipsize="end"
            android:maxLines="4"
            android:textSize="14sp"/>
    </RelativeLayout>

</FrameLayout>



Main Activity

download the data from website and store in the later use by the populateAttractionData method.

    private class DownloadTask extends AsyncTask<String, Void, Object> {

            protected Object doInBackground(String... args) {
                //System.out.println("Debug : MainActivity.DownloadTask.searchUrl[Start]");

                //String searchUrl =  "http://www.flipjob.com.au/export_attractions.csv";
                HttpURLConnection urlConnection = null;
                int counter = 0;
                try {
                    //System.out.println("Debug : MainActivity.DownloadTask.urlConnection.searchUrl[" + searchUrl + "]");
                    URL url = new URL(SEARCH_URL);
                    urlConnection = (HttpURLConnection) url.openConnection();
                    urlConnection.setRequestMethod("GET");
                    int statusCode = urlConnection.getResponseCode();
                    //System.out.println("Debug : MainActivity.DownloadTask.urlConnection.statusCode[" + statusCode + "]");
                    //  title:string shortdescr:string longdescr:string image:string latitude:float longitude:float state:string city:string

                    if (statusCode == 200) {
                        BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));;
                        String line = null;
                        while ((line = in.readLine()) != null) {
                            if (line==null && line.length()< 100) {
                                //Log.d(TAG, "Debug : PaidJobActivity.DownloadTask.searchUrl[line == null]");
                                break;
                            } else {
                                counter++;
                                //System.out.println("Debug : MainActivity.DownloadTask.line[" + line + "] | counter[" + counter + "]");

                                String[] row = line.split("\\|");

                                int id = Integer.parseInt(row[0].toString());
                                String title = row[1].toString();
                                String shortdescr = row[2].toString();
                                String longdescr = row[3].toString();
                                String image = row[4].toString();

                                //System.out.println("Debug : MainActivity.AustraliaAttraction[" + counter + ":" + row[5].toString() + "|" + row[6].toString() + "]");
                                float  latitude = Float.parseFloat(row[5].toString());
                                float  longitude = Float.parseFloat(row[6].toString());
                                String state = row[7].toString();
                                String city = row[8].toString();
                                String website = row[9].toString();
                                String attractionType = row[10].toString();
                                String titleChinese = row[11].toString();
                                String shortdescrChinese = row[12].toString();
                                String longdescrChinese =  row[13].toString();


                                LatLng attractionLoc = new LatLng(latitude, longitude);
                                LatLng stateLat = Utils.getSelectedStateLocation(state);
                                double distanceBetweenCapitalCity = Utils.calculateDistanceBetweenCapitalCity(stateLat, attractionLoc);

                                //System.out.println("Debug : MainActivity.AustraliaAttraction[" + counter + ":" + title + "|" + shortdescr + "|" + longdescr +  "|" + image + "|" + latitude + "|" + longitude + "|" + state + "|" + city);
                                australiaAttractionList.add(new AustraliaAttraction(id, title, titleChinese,  website, attractionType, shortdescr, shortdescrChinese, longdescr, longdescrChinese, image, latitude, longitude, distanceBetweenCapitalCity, state, city));
                                //System.out.println("Debug : MainActivity.AustraliaAttraction = add[" + counter + ":" + title  + "|" + image + "|" + latitude + "|" + longitude + "|" + distanceBetweenCapitalCity + "|" + state + "|" + city);
                                //Log.d(TAG, "Debug : MainActivity.after adding a job to currentJobVacancyList");
                            }
                        }
                        in.close();
                    }

                }  catch (MalformedURLException e)  {
                    System.out.println("Debug : MainActivity: failed downloading file using http RESTFUL - MalformedURLException due to[" + e.getMessage() + "]");
                    e.printStackTrace();
                }
                catch (IOException e)  {
                    System.out.println("Debug : MainActivity : failed downloading file using http RESTFUL - IOException due to[" + e.getMessage() + "]");
                    e.printStackTrace();
                }

                // Sort australiaAttractionList by distanceBetweenCaptial
                Collections.sort(australiaAttractionList, new Comparator<AustraliaAttraction>() {

                    public int compare(AustraliaAttraction o1, AustraliaAttraction o2) {
                        return Double.compare(o1.getDistanceBetweenCaptialCity(), o2.getDistanceBetweenCaptialCity());
                    }

                });
                //System.out.println("Debug : MainActivity.DownloadTask.searchUrl[End]");

    //            for (AustraliaAttraction australiaAttraction : australiaAttractionList) {
    //                System.out.println("Debug : MainActivity.title[" + australiaAttraction.getTitle() + "|" + australiaAttraction.getDistanceBetweenCaptialCity());
    //            }
                return null;
            }


populateAttractionData
=======================

    public static List<Attraction>
    populateAttractionData(ArrayList<AustraliaAttraction> ausAttractionList, String state, LatLng selectedStateLat ) {

            //System.out.println("Debug : populateAttractionData.state[" + state + "]");
            List<Attraction> attractionList = new ArrayList<Attraction>();
            Attraction attraction;
            for(AustraliaAttraction australiaAttraction : ausAttractionList) {
                if (state.equalsIgnoreCase(australiaAttraction.getState())) {
                    //System.out.println("Kam : populateAttractionData.state[" + state + "] | getTitle[" + australiaAttraction.getTitle() + "]|distanceBetweenCaptialCity[" + australiaAttraction.getDistanceBetweenCaptialCity() + "]");
                    LatLng attractionlatLng = new LatLng(australiaAttraction.getLatitude(), australiaAttraction.getLongitude());
                    String distanceBetweenCaptialCityStr = Utils.formatDistanceBetweenCaptialCity(australiaAttraction.getDistanceBetweenCaptialCity());
                    final String imageWithFullPath = "http://flipjob.com.au/images/" + state.toLowerCase() + "/" + australiaAttraction.getImageUrl();
                    Attraction myattraction = new Attraction(
                            australiaAttraction.getAttractionId(),
                            australiaAttraction.getTitle(),
                            australiaAttraction.getWebsite(),
                            australiaAttraction.getTitleChinese(),
                            australiaAttraction.getShortDesc(),
                            australiaAttraction.getShortDescChinese(),
                            australiaAttraction.getLongDesc(),
                            australiaAttraction.getLongDescChinese(),
                            Uri.parse(imageWithFullPath),
                            Uri.parse(imageWithFullPath),
                            attractionlatLng,
                            distanceBetweenCaptialCityStr,
                            australiaAttraction.getCity());
                    attractionList.add(myattraction);
                }
            }

    //        for(Attraction debugAttraction : attractionList){
    //            System.out.println("Debug : TouristAttractions.populateAttractionData[" + debugAttraction.name + "|" + debugAttraction.distance + "]");
    //        }
  • post your populateAttractionData method here – Sohel S9 Feb 21 '19 at 12:01
  • did you log and see the data? is it coming in order? – Vinil Prabhu Feb 21 '19 at 12:41
  • I enclosed the snapshot of the main activity that download the data from the website then use Collections.sort to sort the record and then store in the ausAttractionList List. The populateAttractionData method will extracted the attraction data from the ausAttractinList list with the selected state. I have already checked the data stored in Attraction list that passed to the adaptor has already been sorted by the distance – mylottofinder.com.au Feb 22 '19 at 13:08

1 Answers1

0

Ok finally, i worked it out. I just have to sort the item on the onResume() method