আমি কীভাবে একটি তালিকাতে একটি সারি আপডেট করতে পারি?


131

আমার কাছে একটি রয়েছে ListViewযা নিউজ আইটেমগুলি প্রদর্শন করে। এগুলিতে একটি চিত্র, একটি শিরোনাম এবং কিছু পাঠ্য রয়েছে। চিত্রটি একটি পৃথক থ্রেডে লোড করা হয়েছে (একটি সারি এবং সব সহ) এবং যখন চিত্রটি ডাউনলোড হয়, আমি এখন notifyDataSetChanged()তালিকার অ্যাডাপ্টারে কল করে ছবিটি আপডেট করি call এটি দৃশ্যমান সমস্ত আইটেমের জন্য কল করার getView()পরে এটি কার্যকর হয় তবে খুব ঘন ঘন notifyDataSetChanged()কল করা হয় called getView()আমি তালিকার একক আইটেমটি আপডেট করতে চাই। আমি এই কিভাবে করব?

আমার বর্তমান পদ্ধতির সাথে আমার যেসব সমস্যা রয়েছে তা হ'ল:

  1. স্ক্রোলিং ধীর
  2. আমার কাছে ইমেজে একটি ফিড-ইন অ্যানিমেশন রয়েছে যা প্রতিবার তালিকায় একটি নতুন চিত্র লোড হওয়ার পরে ঘটে।

উত্তর:


199

আমি উত্তরটি পেয়েছি, আপনার তথ্যের জন্য ধন্যবাদ মিশেল। আপনি প্রকৃতপক্ষে ব্যবহার করে সঠিক দর্শন পেতে পারেন View#getChildAt(int index)। ধরাটি এটি প্রথম দৃশ্যমান আইটেম থেকে গণনা শুরু করে counting আসলে, আপনি কেবল দৃশ্যমান আইটেমগুলি পেতে পারেন। আপনি এটি দিয়ে সমাধান করুন ListView#getFirstVisiblePosition()

উদাহরণ:

private void updateView(int index){
    View v = yourListView.getChildAt(index - 
        yourListView.getFirstVisiblePosition());

    if(v == null)
       return;

    TextView someText = (TextView) v.findViewById(R.id.sometextview);
    someText.setText("Hi! I updated you manually!");
}

2
স্বরে নোট করুন: এমআইএমজিভিউ.সেট আইজ্যুরি () তালিকা আইটেমটি আপডেট করবে তবে কেবল একবার; সুতরাং আমি পরিবর্তে mLstVwAdapter.notifyDataSetInuthorated () ব্যবহার করা ভাল।
কেলোগগুলি

এই সমাধান কাজ করে। তবে এটি কেবলমাত্র আপনার লিস্টভিউ.জেটচিল্ডএটি (সূচক) দিয়ে করা যেতে পারে; এবং দেখুন পরিবর্তন। উভয় সমাধান কাজ করে !!
অ্যান্ড্রয়েডদেভ

আমি যদি অ্যাডাপ্টারে কেবলমাত্র ভিটভিউ () কে কল করি তবেই যদি পজিশনটি ফার্স্টভিজিবলপজিশন () এবং getLastVisiblePosition () এর মধ্যে থাকে? এটা কি একই কাজ করবে? আমি মনে করি এটি যথারীতি ভিউ আপডেট করবে, তাইনা?
অ্যান্ড্রয়েড বিকাশকারী

আমার ক্ষেত্রে, কিছু সময় দর্শন বাতিল হয়, কারণ প্রতিটি আইটেম অবিচ্ছিন্নভাবে আপডেট হচ্ছে, দেখুন কিনা তা যাচাই করা ভাল! = নাল
খাওয়ার

2
দুর্দান্ত কাজ করে। এটি আমাকে ইনস্টাগ্রামের মতো অ্যাপ্লিকেশনটিতে লাইক বৈশিষ্ট্যটি প্রয়োগের কাজ শেষ করতে সহায়তা করে। আমি একটি কাস্টম অ্যাডাপ্টার ব্যবহার করছিলাম, তালিকার উপাদানগুলির মতো লাইক বোতামে একটি সম্প্রচার, পিতৃ খণ্ডে সম্প্রচারিত রিসিভারের সাথে ব্যাকএন্ডটি বলার জন্য একটি অ্যাসিনটাস্ক আরম্ভ করে এবং তালিকাটি আপডেট করার জন্য অবশেষে এরিকের উত্তর।
জোশ

71

এই প্রশ্নটি গুগল আই / ও ২০১০ তে জিজ্ঞাসা করা হয়েছে, আপনি এটি এখানে দেখতে পারেন:

তালিকাভিউ দুনিয়া, সময় 52:30

মূলত রোমেন গাই যা ব্যাখ্যা করেছেন তা হল ভিউটি পাওয়ার জন্য কল getChildAt(int)করা ListViewএবং (আমি মনে করি) getFirstVisiblePosition()অবস্থান এবং সূচকের মধ্যে পারস্পরিক সম্পর্ক খুঁজে বের করার জন্য কল করা।

রোমেন উদাহরণস্বরূপ শেল্ভস নামক প্রকল্পটির দিকেও ইঙ্গিত করে , আমি মনে করি তিনি পদ্ধতিটি বোঝাতে ShelvesActivity.updateBookCovers()পারেন, তবে আমি কলটি পাই না getFirstVisiblePosition()

অসাধারণ আপডেটগুলি আসছে:

রিসাইক্লারভিউ অদূর ভবিষ্যতে এটি ঠিক করবে। Http://www.grokkingandroid.com/first-glance-androids-recyclerview/ এ উল্লিখিত হিসাবে , আপনি পরিবর্তনটি হুবহু নির্দিষ্ট করার জন্য পদ্ধতিগুলি কল করতে সক্ষম হবেন যেমন:

void notifyItemInserted(int position)
void notifyItemRemoved(int position)
void notifyItemChanged(int position)

এছাড়াও, প্রত্যেকেই রিসাইক্লভিউয়ের উপর ভিত্তি করে নতুন মতামতগুলি ব্যবহার করতে চাইবে কারণ তাদের সুন্দর-সন্ধানী অ্যানিমেশন দিয়ে পুরস্কৃত করা হবে! ভবিষ্যত দুর্দান্ত দেখায়! :-)


3
ভাল জিনিস! :) সম্ভবত আপনি এখানেও নাল চেক যুক্ত করতে পারেন - ভি মুহুর্তে দৃশ্যটি উপলব্ধ না হলে নাল হতে পারে। এবং অবশ্যই এই ডেটাটি চলে যাবে যদি ব্যবহারকারী তালিকাটি ভিউ স্ক্রল করে, তাই অ্যাডাপ্টারে ডাটা আপডেট করা উচিত (সম্ভবত notifyDataSetChanged () কল না করে)। সাধারণভাবে আমি মনে করি এই সমস্ত যুক্তিটিকে অ্যাডাপ্টারের মধ্যে রাখা ভাল ধারণা হবে, অর্থাৎ এটির সাথে তালিকা ভিউ রেফারেন্সটি পাস করা।
মিরিচেল্ট

এটি আমার পক্ষে কাজ করেছিল, ব্যতীত - যখন দৃশ্যটি স্ক্রীনটি ছেড়ে যায়, যখন এটি পুনরায় প্রবেশ করে পরিবর্তনটি পুনরায় সেট করা হয়। আমার ধারণা, ভিউভিউতে এটি এখনও মূল তথ্যটি পাচ্ছে। আমি কিভাবে এই কাছাকাছি পেতে পারি?
gloscherrybomb 23'12

6

আমি এটি এইভাবে করেছি:

আপনার আইটেমগুলিতে (সারিগুলি) অবশ্যই অনন্য আইড থাকতে হবে যাতে আপনি সেগুলি পরে আপডেট করতে পারেন। তালিকাটি অ্যাডাপ্টারের থেকে ভিউটি পাওয়ার সময় প্রতিটি দৃশ্যের ট্যাগ সেট করুন। (যদি ডিফল্ট ট্যাগটি অন্য কোথাও ব্যবহার করা হয় তবে আপনি কী ট্যাগও ব্যবহার করতে পারেন)

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    View view = super.getView(position, convertView, parent);
    view.setTag(getItemId(position));
    return view;
}

আপডেটের জন্য তালিকার প্রতিটি উপাদান চেক করুন, প্রদত্ত আইডি সহ কোনও ভিউ যদি তা উপস্থিত থাকে তবে আমরা আপডেটটি সম্পাদন করি।

private void update(long id)
{

    int c = list.getChildCount();
    for (int i = 0; i < c; i++)
    {
        View view = list.getChildAt(i);
        if ((Long)view.getTag() == id)
        {
            // update view
        }
    }
}

এটি অন্যান্য পদ্ধতির তুলনায় আসলেই সহজ এবং যখন আপনি আইডির সাথে সম্পর্কিত না হন তখন আরও কার্যকর! এছাড়াও দৃশ্যমান হওয়া আইটেমগুলির জন্য আপনাকে অবশ্যই আপডেট আপডেট কল করতে হবে।


3

এই মডেল শ্রেণীর অবজেক্টের মতো বিশ্বব্যাপী মডেল ক্লাসটি প্রথম পান

SampleModel golbalmodel=new SchedulerModel();

এবং এটি বিশ্বব্যাপী সূচনা করুন

মডেলটির মাধ্যমে এটির বৈশ্বিক মডেলকে সূচনা করে বর্তমান সারিটি সন্ধান করুন

SampleModel data = (SchedulerModel) sampleList.get(position);
                golbalmodel=data;

সেট করার জন্য গ্লোবাল মডেল অবজেক্ট পদ্ধতিতে পরিবর্তিত মান সেট করুন এবং বিজ্ঞপ্তিডেটসেটটি আমার জন্য এটির কাজগুলি যুক্ত করুন

golbalmodel.setStartandenddate(changedate);

notifyDataSetChanged();

এখানে ভাল উত্তর সহ একটি সম্পর্কিত প্রশ্ন।


এটি সঠিক পন্থা, যেহেতু আপনি যে অবজেক্টটি আপডেট করতে চান, এটি আপডেট করতে চান এবং তারপরে অ্যাডাপ্টারকে অবহিত করতে চান এবং এটি নতুন ডেটা দিয়ে সারি তথ্য পরিবর্তন করবে।
গ্যাস্টান স্যালেন

2

উত্তরগুলি পরিষ্কার এবং সঠিক, আমি CursorAdapterএখানে মামলার জন্য একটি ধারণা যুক্ত করব ।

আপনি যদি সাবক্লাসিং CursorAdapter(বা ResourceCursorAdapter, বা SimpleCursorAdapter) হন, তবে আপনি হয় প্রয়োগ ViewBinderবা ওভাররাইড bindView()এবং newView()পদ্ধতিগুলি পেতে পারেন , এগুলি আর্গুমেন্টে বর্তমান তালিকা আইটেম সূচকটি গ্রহণ করে না। সুতরাং, যখন কিছু ডেটা আসে এবং আপনি প্রাসঙ্গিক দৃশ্যমান তালিকা আইটেমগুলি আপডেট করতে চান, আপনি তাদের সূচকগুলি কীভাবে জানেন?

আমার কাজটি ছিল:

  • সমস্ত তৈরি তালিকা আইটেম দর্শনের একটি তালিকা রাখুন, থেকে এই তালিকায় আইটেম যুক্ত করুন newView()
  • ডেটা এলে এগুলি পুনরাবৃত্তি করুন এবং কোনটি আপডেট করার প্রয়োজন তা দেখুন - notifyDatasetChanged()সেগুলি করা এবং তা রিফ্রেশ করার চেয়ে ভাল

দেখার পুনর্ব্যবহারের কারণে দেখার রেফারেন্সের সংখ্যাটি আমার সংরক্ষণ করতে হবে এবং পুনরাবৃত্তি স্ক্রিনে দৃশ্যমান তালিকা আইটেমগুলির সংখ্যার সমান হবে।


2
int wantedPosition = 25; // Whatever position you're looking for
int firstPosition = linearLayoutManager.findFirstVisibleItemPosition(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;

if (wantedChild < 0 || wantedChild >= linearLayoutManager.getChildCount()) {
    Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
    return;
}

View wantedView = linearLayoutManager.getChildAt(wantedChild);
mlayoutOver =(LinearLayout)wantedView.findViewById(R.id.layout_over);
mlayoutPopup = (LinearLayout)wantedView.findViewById(R.id.layout_popup);

mlayoutOver.setVisibility(View.INVISIBLE);
mlayoutPopup.setVisibility(View.VISIBLE);

রিসাইকেলভিউয়ের জন্য দয়া করে এই কোডটি ব্যবহার করুন


আমি এটি রিসাইকেলভিউতে প্রয়োগ করেছি, এটি কাজ করে। তবে আপনি তালিকাটি স্ক্রোল করলে এটি আবার পরিবর্তন হয়ে যায়। কোন সাহায্য?
ফাহিদ নাদিম

1

আমি কোডটি ব্যবহার করেছি যা এরিক সরবরাহ করেছিল, দুর্দান্ত কাজ করে, তবে আমার তালিকাভিউয়ের জন্য আমার একটি জটিল কাস্টম অ্যাডাপ্টার রয়েছে এবং আমি ইউআই আপডেট করে এমন কোডটি দ্বিগুণ প্রয়োগের মুখোমুখি হয়েছিল। আমি আমার অ্যাডাপ্টারগুলি get ভিউ পদ্ধতি থেকে নতুন দৃষ্টিভঙ্গিটি পাওয়ার চেষ্টা করেছি (তালিকাভিত্তিক ডেটা ধারণ করে এমন অ্যারেলিস্ট সমস্ত আপডেট হয়েছে / পরিবর্তন হয়েছে):

View cell = lvOptim.getChildAt(index - lvOptim.getFirstVisiblePosition());
if(cell!=null){
    cell = adapter.getView(index, cell, lvOptim); //public View getView(final int position, View convertView, ViewGroup parent)
    cell.startAnimation(animationLeftIn());
}

এটি ভালভাবে কাজ করছে, তবে আমি জানি না এটি একটি ভাল অনুশীলন কিনা। সুতরাং আমার কাছে কোডটি প্রয়োগ করার দরকার নেই যা তালিকার আইটেমটি দুবার আপডেট করে।


1

ঠিক আমি এটি ব্যবহার করেছি

private void updateSetTopState(int index) {
        View v = listview.getChildAt(index -
                listview.getFirstVisiblePosition()+listview.getHeaderViewsCount());

        if(v == null)
            return;

        TextView aa = (TextView) v.findViewById(R.id.aa);
        aa.setVisibility(View.VISIBLE);
    }

আপেক্ষিক বিন্যাসের ভিতরে পাঠ্যদর্শনটি কীভাবে খুঁজে পাব তা আপেক্ষিক বিন্যাস হিসাবে দেখুন পাচ্ছি?
গিরিশ

1

আমি আর একটি সমাধান করেছি, যেমন রিসাইক্লিরভিউ পদ্ধতিটি শূন্যnotifyItemChanged(int position) , ঠিক এর মতো কাস্টমবেসএডাপ্টার ক্লাস তৈরি করুন :

public abstract class CustomBaseAdapter implements ListAdapter, SpinnerAdapter {
    private final CustomDataSetObservable mDataSetObservable = new CustomDataSetObservable();

    public boolean hasStableIds() {
        return false;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer);
    }

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

    public void notifyItemChanged(int position) {
        mDataSetObservable.notifyItemChanged(position);
    }

    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }

    public boolean areAllItemsEnabled() {
        return true;
    }

    public boolean isEnabled(int position) {
        return true;
    }

    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        return getView(position, convertView, parent);
    }

    public int getItemViewType(int position) {
        return 0;
    }

    public int getViewTypeCount() {
        return 1;
    }

    public boolean isEmpty() {
        return getCount() == 0;
    } {

    }
}

একটি তৈরি করতে ভুলবেন না CustomDataSetObservable বর্গ জন্য খুব mDataSetObservableমধ্যে পরিবর্তনশীল CustomAdapterClass ভালো:

public class CustomDataSetObservable extends Observable<DataSetObserver> {

    public void notifyChanged() {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }

    public void notifyInvalidated() {
        synchronized (mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onInvalidated();
            }
        }
    }

    public void notifyItemChanged(int position) {
        synchronized(mObservers) {
            // since onChanged() is implemented by the app, it could do anything, including
            // removing itself from {@link mObservers} - and that could cause problems if
            // an iterator is used on the ArrayList {@link mObservers}.
            // to avoid such problems, just march thru the list in the reverse order.
            mObservers.get(position).onChanged();
        }
    }
}

কাস্টমবেসএডাপ্টারে ক্লাসে একটি পদ্ধতি রয়েছে notifyItemChanged(int position)এবং আপনি যেখানে চান সেখানে সারি আপডেট করতে চাইলে আপনি সেই পদ্ধতিটি কল করতে পারেন (বোতাম ক্লিক করুন বা যে কোনও জায়গা থেকে আপনি সেই পদ্ধতিতে কল করতে চান)। এবং ভয়েলা! আপনার একক সারি তাত্ক্ষণিকভাবে আপডেট হবে ..


0

আমার সমাধান: যদি এটি সঠিক হয় *, সম্পূর্ণ তালিকাটি আবার অঙ্কন না করে ডেটা এবং দেখারযোগ্য আইটেমগুলি আপডেট করুন। অন্যটি বিজ্ঞপ্তি ডেটাসেট পরিবর্তন হয়েছে।

সঠিক - ওল্ডডাটা আকার == নতুন ডেটা আকার এবং পুরানো ডেটা আইডি এবং তাদের ক্রম == নতুন ডেটা আইডি এবং অর্ডার

কিভাবে:

/**
 * A View can only be used (visible) once. This class creates a map from int (position) to view, where the mapping
 * is one-to-one and on.
 * 
 */
    private static class UniqueValueSparseArray extends SparseArray<View> {
    private final HashMap<View,Integer> m_valueToKey = new HashMap<View,Integer>();

    @Override
    public void put(int key, View value) {
        final Integer previousKey = m_valueToKey.put(value,key);
        if(null != previousKey) {
            remove(previousKey);//re-mapping
        }
        super.put(key, value);
    }
}

@Override
public void setData(final List<? extends DBObject> data) {
    // TODO Implement 'smarter' logic, for replacing just part of the data?
    if (data == m_data) return;
    List<? extends DBObject> oldData = m_data;
    m_data = null == data ? Collections.EMPTY_LIST : data;
    if (!updateExistingViews(oldData, data)) notifyDataSetChanged();
    else if (DEBUG) Log.d(TAG, "Updated without notifyDataSetChanged");
}


/**
 * See if we can update the data within existing layout, without re-drawing the list.
 * @param oldData
 * @param newData
 * @return
 */
private boolean updateExistingViews(List<? extends DBObject> oldData, List<? extends DBObject> newData) {
    /**
     * Iterate over new data, compare to old. If IDs out of sync, stop and return false. Else - update visible
     * items.
     */
    final int oldDataSize = oldData.size();
    if (oldDataSize != newData.size()) return false;
    DBObject newObj;

    int nVisibleViews = m_visibleViews.size();
    if(nVisibleViews == 0) return false;

    for (int position = 0; nVisibleViews > 0 && position < oldDataSize; position++) {
        newObj = newData.get(position);
        if (oldData.get(position).getId() != newObj.getId()) return false;
        // iterate over visible objects and see if this ID is there.
        final View view = m_visibleViews.get(position);
        if (null != view) {
            // this position has a visible view, let's update it!
            bindView(position, view, false);
            nVisibleViews--;
        }
    }

    return true;
}

এবং অবশ্যই:

@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
    final View result = createViewFromResource(position, convertView, parent);
    m_visibleViews.put(position, result);

    return result;
}

বাইন্ডভিউতে সর্বশেষ প্যারামটি উপেক্ষা করুন (আমাকে ইমেজড্রোয়েবলের জন্য বিটম্যাপগুলি পুনর্ব্যবহার করতে হবে কিনা তা নির্ধারণ করতে এটি ব্যবহার করি)।

উপরে উল্লিখিত হিসাবে, মোট 'দৃশ্যমান' দর্শনগুলির সংখ্যা মোটামুটি স্ক্রিনে ফিট করে (ওরিয়েন্টেশন পরিবর্তনগুলি উপেক্ষা করে), সুতরাং কোনও বড় মেমরি অনুসারে নয়।


0

এই সমাধানটি ছাড়াও ( https://stackoverflow.com/a/3727813/5218712 ) কেবল যুক্ত করতে চান যে listView.getChildCount() == yourDataList.size(); তালিকাভিউতে অতিরিক্ত ভিউ থাকতে পারে তবেই এটি কাজ করা উচিত ।

কীভাবে শিশু উপাদানগুলি জনবহুল হয় তার উদাহরণ:  listView.mChildren অ্যারে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.