android - बनत - पुनर्चक्रण क्या है




पेजिंग के लिए प्रोग्रेसबार के साथ अंतहीन पुनर्नवीकरण (6)

अलग दृष्टिकोण कुछ प्रगति संकेतक देखने के लिए आइटम में onBindViewHolder और प्रारंभिक स्थान के भीतर एपीआई कॉल शुरू करने के लिए किया जाएगा। कॉल समाप्त होने के बाद, आप दृश्य को अपडेट करते हैं (प्रगति को छिपाएं और प्राप्त डेटा दिखा रहे हैं)। चित्र लोडिंग के लिए पिकासो के साथ उदाहरण के लिए, onBindViewHolder विधि इस तरह दिखाई देगी

@Override
public void onBindViewHolder(final MovieViewHolder holder, final int position) {
    final Movie movie = items.get(position);
    holder.imageProgress.setVisibility(View.VISIBLE);
    Picasso.with(context)
            .load(NetworkingUtils.getMovieImageUrl(movie.getPosterPath()))
            .into(holder.movieThumbImage, new Callback() {
                @Override
                public void onSuccess() {
                    holder.imageProgress.setVisibility(View.GONE);
                }
                @Override
                public void onError() {

                }
            });
}

जैसा कि मैंने इसे देखा, दो मामले हैं जो सामने आ सकते हैं:

  1. जहां आप एक संस्करण के साथ लाइट संस्करण में सभी आइटम डाउनलोड करते हैं (जैसे कि एडॉप्टर तुरंत जानता है कि उसे 40 चित्रों से निपटना होगा, लेकिन इसे मांग पर डाउनलोड करें -> मामला जो मैंने पिकासो के साथ पहले दिखाया था)
  2. जहां आप वास्तविक आलसी लोडिंग के साथ काम कर रहे हैं और आप सर्वर से आपको डेटा का अतिरिक्त हिस्सा देने के लिए कह रहे हैं। इस मामले में, पहली शर्त यह है कि आवश्यक जानकारी के साथ सर्वर से पर्याप्त प्रतिक्रिया हो। उदाहरण उदाहरण {"ऑफसेट": 0, "कुल": 100, "आइटम": [{आइटम}]}

प्रतिक्रिया का मतलब है कि आपको कुल 100 डेटा का पहला हिस्सा मिला है। मेरा दृष्टिकोण कुछ इस तरह होगा:

डेटा का पहला हिस्सा मिलने के बाद देखें (उदाहरण 10) उन्हें एडॉप्टर में जोड़ें।

RecyclerView.Adcape.getItemCount जब तक उपलब्ध वस्तुओं की वर्तमान राशि कुल राशि से कम है (जैसे 10 उपलब्ध; कुल 100), getItemCount विधि में आप items.size () + 1 लौटा देंगे

RecyclerView.Adcape.getItemViewType यदि डेटा की कुल राशि एडॉप्टर में उपलब्ध वस्तुओं की मात्रा से अधिक है और स्थिति = items.size () (यानी आपने getItemCount पद्धति में आइटम को काल्पनिक रूप से जोड़ा गया है), तो उस प्रकार के रूप में जब आप कुछ प्रगति-संकेतक लौटाते हैं । अन्यथा आप सामान्य लेआउट प्रकार वापस करेंगे

RecyclerView.Adcape.onCreateViewHolder जब आपको प्रगति-संकेतक दृश्य प्रकार का उपयोग करने के लिए कहा जाता है, तो आपको केवल अपने प्रस्तोता से वस्तुओं का अतिरिक्त हिस्सा लेने और एडॉप्टर को अपडेट करने के लिए कहना होगा।

तो मूल रूप से, यह वह दृष्टिकोण है जहां आपको सूची से आइटम जोड़ना / हटाना नहीं है और जहां आलसी लोडिंग शुरू हो जाएगी, उस स्थिति पर आपका नियंत्रण है।

यहाँ कोड उदाहरण है:

public class ForecastListAdapter extends RecyclerView.Adapter<ForecastListAdapter.ForecastVH> {
private final Context context;
private List<Forecast> items;
private ILazyLoading lazyLoadingListener;

public static final int VIEW_TYPE_FIRST         = 0;
public static final int VIEW_TYPE_REST          = 1;
public static final int VIEW_TYPE_PROGRESS      = 2;

public static final int totalItemsCount = 14;

public ForecastListAdapter(List<Forecast> items, Context context, ILazyLoading lazyLoadingListener) {
    this.items = items;
    this.context = context;
    this.lazyLoadingListener = lazyLoadingListener;
}

public void addItems(List<Forecast> additionalItems){
    this.items.addAll(additionalItems);
    notifyDataSetChanged();
}

@Override
public int getItemViewType(int position) {
    if(totalItemsCount > items.size() && position == items.size()){
        return VIEW_TYPE_PROGRESS;
    }
    switch (position){
        case VIEW_TYPE_FIRST:
            return VIEW_TYPE_FIRST;
        default:
            return VIEW_TYPE_REST;
    }
}

@Override
public ForecastVH onCreateViewHolder(ViewGroup parent, int viewType) {
    View v;
    switch (viewType){
        case VIEW_TYPE_PROGRESS:
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_progress, parent, false);
            if (lazyLoadingListener != null) {
                lazyLoadingListener.getAdditionalItems();
            }
            break;
        case VIEW_TYPE_FIRST:
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_first, parent, false);
            break;
        default:
            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.forecast_list_item_rest, parent, false);
            break;
    }
    return new ForecastVH(v);
}

@Override
public void onBindViewHolder(ForecastVH holder, int position) {
    if(position < items.size()){
        Forecast item = items.get(position);
        holder.date.setText(FormattingUtils.formatTimeStamp(item.getDt()));
        holder.minTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMin()));
        holder.maxTemperature.setText(FormattingUtils.getRoundedTemperature(item.getTemp().getMax()));
    }

}

@Override
public long getItemId(int position) {
    long i = super.getItemId(position);
    return i;
}

@Override
public int getItemCount() {
    if (items == null) {
        return 0;
    }
    if(items.size() < totalItemsCount){
        return items.size() + 1;
    }else{
        return items.size();
    }
}

public class ForecastVH extends RecyclerView.ViewHolder{
    @BindView(R.id.forecast_date)TextView date;
    @BindView(R.id.min_temperature)TextView minTemperature;
    @BindView(R.id.max_temperature) TextView maxTemperature;
    public ForecastVH(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

public interface ILazyLoading{
    public void getAdditionalItems();
}}

शायद यह आपको कुछ ऐसा बनाने के लिए प्रेरित करेगा जो आपकी आवश्यकताओं के अनुरूप होगा

मैं एक RecyclerView का उपयोग कर रहा हूं और दस के बैच में API से ऑब्जेक्ट ला रहा हूं। EndlessRecyclerOnScrollListener लिए, मैं EndlessRecyclerOnScrollListener उपयोग करता EndlessRecyclerOnScrollListener

यह सब ठीक से काम कर रहा है। अब जो कुछ बचा है वह सूची के निचले भाग में एक प्रगति स्पिनर को जोड़ना है जबकि वस्तुओं के अगले बैच को एपीआई द्वारा प्राप्त किया जाता है। यहां Google Play Store ऐप का एक स्क्रीनशॉट है, जो निश्चित रूप से एक RecyclerView दिखा रहा है, जो कि RecyclerView :

समस्या यह है कि न तो RecyclerView और न ही EndlessRecyclerOnScrollListener ने नीचे की तरफ एक ProgressBar दिखाने के लिए बिल्ट-इन सपोर्ट दिया है, जबकि ऑब्जेक्ट्स का अगला बैच लाया जा रहा है।

मैंने पहले ही निम्नलिखित उत्तर देख लिए हैं:

1. एक RecyclerView एक RecyclerView ग्रिड में पाद लेख के रूप में रखो

2. निचले स्तर पर ProgressBar साथ अंतहीन स्क्रॉल RecyclerView आइटम जोड़ना

मैं उन उत्तरों (एक ही व्यक्ति द्वारा दोनों) से संतुष्ट नहीं हूं। इसमें उपयोगकर्ता द्वारा स्क्रॉल करते समय डेटा-सेट मिडवे में एक null ऑब्जेक्ट को जूता करना शामिल है और अगले बैच के वितरित होने के बाद इसे बाहर निकालना। यह एक हैक की तरह दिखता है जो मुख्य समस्या को दूर करता है जो ठीक से काम नहीं कर सकता है या नहीं। और यह सूची में थोड़ी गड़बड़ी और विकृति का कारण बनता है

SwipeRefreshLayout का उपयोग करना यहां कोई समाधान नहीं है। SwipeRefreshLayout में नए आइटम लाने के लिए ऊपर से खींचना शामिल है, और यह वैसे भी प्रगति दृश्य नहीं दिखाता है।

क्या कोई इसके लिए एक अच्छा समाधान प्रदान कर सकता है? मुझे यह जानने में दिलचस्पी है कि Google ने अपने स्वयं के ऐप्स के लिए इसे कैसे लागू किया है (जीमेल ऐप के पास भी है)। क्या कोई लेख है जहां इसे विस्तार से दिखाया गया है? सभी उत्तरों और टिप्पणियों की सराहना की जाएगी। धन्यवाद।

कुछ अन्य संदर्भ :

1. पुनर्नवीनीकरण दृश्य के साथ पृष्ठ पर अंक लगाना । (शानदार अवलोकन ...)

2. RecyclerView हेडर और पाद । (एक जैसा पर उससे अधिक ...)

3. निचले स्तर पर ProgressBar साथ अंतहीन RecyclerView


आप इस तरह से recycleView में layout_above टैग का उपयोग कर सकते हैं:

<RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginLeft="16dp"
                    android:layout_marginRight="16dp"
                    android:orientation="vertical">
                    <androidx.recyclerview.widget.RecyclerView
                        android:id="@+id/rv"
                        android:layout_below="@+id/tv2"
                        android:layout_width="match_parent"
                        android:focusable="false"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="24dp"
                        android:layout_above="@+id/pb_pagination"/>

                     <ProgressBar
                        android:id="@+id/pb_pagination"
                        style="@style/Widget.AppCompat.ProgressBar"
                        android:layout_width="30dp"
                        android:layout_height="30dp"
                        android:indeterminate="true"
                         android:visibility="gone"
                        android:layout_alignParentBottom="true"
                        android:layout_centerHorizontal="true" />
    </RelativeLayout>

मुझे एक एडॉप्टर में प्रगति देखने वाले को जोड़ने का विचार पसंद है, लेकिन यह कुछ बदसूरत तर्क हेरफेर को जन्म देता है जो आप चाहते हैं। व्यू होल्डर अप्रोच आपको getItemCount() , getItemViewType() , getItemId(position) और किसी भी तरह के getItem(position) पद्धति के रिटर्न मानों के साथ getItemCount() करके आपको किसी भी प्रकार की getItem(position) विधि से getItem(position) के लिए getItem(position) जिसे आप शामिल करना चाहते हैं।

वैकल्पिक तरीका यह है कि लोडिंग शुरू होने और क्रमशः समाप्त होने पर RecyclerView नीचे ProgressBar को दिखा या छिपाकर ProgressBar या Activity स्तर पर ProgressBar दृश्यता का प्रबंधन किया जाए। यह ProgressBar सीधे व्यू लेआउट में शामिल करके या कस्टम RecyclerView ViewGroup वर्ग में जोड़कर प्राप्त किया जा सकता है। यह समाधान आमतौर पर कम रखरखाव और कम कीड़े को जन्म देगा।

अद्यतन: जब आप सामग्री को लोड कर रहे हैं, तो मेरे सुझाव को वापस स्क्रॉल करने पर एक समस्या उत्पन्न होती है। ProgressBar व्यू लेआउट के निचले हिस्से पर चिपक जाएगा। यह शायद वह व्यवहार नहीं है जो आप चाहते हैं। इस कारण से, अपने एडॉप्टर में प्रगति देखने वाले को जोड़ना संभवतः सबसे अच्छा, कार्यात्मक समाधान है। बस अपने आइटम एक्सेसर विधियों की रक्षा करना न भूलें। :)


मैंने अपने पुराने प्रोजेक्ट पर इसे लागू किया, मैंने इसे इस प्रकार किया ...

मैंने एक interface बनाया interface जैसा कि आपके उदाहरण के दोस्तों ने किया था

public interface LoadMoreItems {
  void LoadItems();
}

फिर मैं अपने Adapter पर एक addOnScrollListener() जोड़ा

 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView,
                                   int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                totalItemCount = linearLayoutManager.getItemCount();
                lastVisibleItem = linearLayoutManager
                        .findLastVisibleItemPosition();
                if (!loading
                        && totalItemCount <= (lastVisibleItem + visibleThreshold)) {
                    //End of the items
                    if (onLoadMoreListener != null) {
                        onLoadMoreListener.LoadItems();
                    }
                    loading = true;

                }
            }
        });

onCreateViewHolder() वह जगह है जहाँ मैंने ProgressBar डाला या नहीं।

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                  int viewType) {
    RecyclerView.ViewHolder vh;
    if (viewType == VIEW_ITEM) {
        View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.list_row, parent, false);

        vh = new StudentViewHolder(v);
    } else {
        View v = LayoutInflater.from(parent.getContext()).inflate(
                R.layout.progressbar_item, parent, false);

        vh = new ProgressViewHolder(v);
    }
    return vh;
}

अपनी MainActivity पर, जहां मैं अन्य आइटम जोड़ने के लिए LoadItems() डाल रहा हूं:

mAdapter.setOnLoadMoreListener(new LoadMoreItems() {
        @Override
        public void LoadItems() {
            DataItemsList.add(null);
            mAdapter.notifyItemInserted(DataItemsList.size() - 1);

            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    //   remove progress item
                    DataItemsList.remove(DataItemsList.size() - 1);
                    mAdapter.notifyItemRemoved(DataItemsList.size());
                    //add items one by one
                    //When you've added the items call the setLoaded()
                    mAdapter.setLoaded();
                    //if you put all of the items at once call
                    // mAdapter.notifyDataSetChanged();
                }
            }, 2000); //time 2 seconds

        }
    });

अधिक जानकारी के लिए मैंने सिर्फ इस Github repository अनुसरण किया ( नोट: यह AsyncTask का उपयोग कर AsyncTask शायद यह मेरे उत्तर के रूप में उपयोगी है, क्योंकि मैंने इसे मैन्युअल रूप से API से डेटा के साथ नहीं किया था, लेकिन साथ ही साथ यह काम भी करना चाहिए ) यह पोस्ट मेरे लिए endless-recyclerview-with-progress-bar सहायक थी endless-recyclerview-with-progress-bar

इसके अलावा, मुझे नहीं पता कि आपने इसका नाम रखा है, लेकिन मुझे यह पोस्ट infinite_scrolling_recyclerview भी मिली, शायद यह भी आपकी मदद कर सके।

यदि यह वह नहीं है जो आप ढूंढ रहे हैं, तो मुझे बताएं और मुझे बताएं कि इस कोड में क्या गलत है और मैं इसे आपकी तरह संशोधित करने का प्रयास करूंगा।

आशा है ये मदद करेगा।

संपादित करें

चूँकि आप किसी आइटम को हटाना नहीं चाहते हैं ... मैंने पाया कि मैं एक आदमी का अनुमान लगाता हूँ जो इस पद पर केवल footer निकालता है: diseño-android-endless-recyclerview

यह ListView लिए है, लेकिन मुझे पता है कि आप इसे RecyclerView अनुकूलित कर सकते हैं वह किसी भी आइटम को हटा नहीं रहा है जिसे वह अभी देख रहा है Visible/Invisible है ProgressBar एक नज़र डालें: detecting-end-of-listview

इस पर भी एक नज़र डालें: यह प्रश्न android-implementing-progressbar-and-loading-for-endless-list-like-android


यहाँ एक नकली वस्तु (कोटलिन में लेकिन सरल) को जोड़े बिना मेरा काम है:

अपने एडॉप्टर में जोड़ें:

private var isLoading = false
private val VIEWTYPE_FORECAST = 1
private val VIEWTYPE_PROGRESS = 2

override fun getItemCount(): Int {
    if (isLoading)
        return items.size + 1
    else
        return items.size
}

override fun getItemViewType(position: Int): Int {
    if (position == items.size - 1 && isLoading)
        return VIEWTYPE_PROGRESS
    else
        return VIEWTYPE_FORECAST
}

override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
    if (viewType == VIEWTYPE_FORECAST)
        return ForecastHolder(LayoutInflater.from(context).inflate(R.layout.item_forecast, parent, false))
    else
        return ProgressHolder(LayoutInflater.from(context).inflate(R.layout.item_progress, parent, false))
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
    if (holder is ForecastHolder) {
        //init your item
    }
}

public fun showProgress() {
    isLoading = true
}


public fun hideProgress() {
    isLoading = false
}

अब आप API कॉल से पहले आसानी से showProgress() कॉल कर सकते हैं। और एपीआई कॉल करने के बाद hideProgress()


यहाँ SIMPLER और स्वच्छ APPROACH है।

इस कोडपथ गाइड से अंतहीन स्क्रॉलिंग को लागू करें और फिर निम्नलिखित चरणों का पालन करें।

1. RecyclerView के तहत प्रगति बार जोड़ें।

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_movie_grid"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:paddingBottom="50dp"
        android:clipToPadding="false"
        android:background="@android:color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </android.support.v7.widget.RecyclerView>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="invisible"
        android:background="@android:color/transparent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

यहाँ Android: paddingBottom = "50dp" और android: clipToPadding = "false" बहुत महत्वपूर्ण हैं।

2. प्रगति पट्टी का संदर्भ लें।

progressBar = findViewById(R.id.progressBar);

3. प्रगति पट्टी को दिखाने और छिपाने के लिए तरीकों को परिभाषित करें।

void showProgressView() {
    progressBar.setVisibility(View.VISIBLE);
}

void hideProgressView() {
    progressBar.setVisibility(View.INVISIBLE);
}




android-progressbar