অ্যানড্রয়েড তালিকাভিউ notifyDataSetChanged পরে সতেজ হয় না


116

আমার তালিকাফ্র্যাগমেন্ট কোড

public class ItemFragment extends ListFragment {

    private DatabaseHandler dbHelper;
    private static final String TITLE = "Items";
    private static final String LOG_TAG = "debugger";
    private ItemAdapter adapter;
    private List<Item> items;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.item_fragment_list, container, false);        
        return view;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.setHasOptionsMenu(true);
        super.onCreate(savedInstanceState);
        getActivity().setTitle(TITLE);
        dbHelper = new DatabaseHandler(getActivity());
        items = dbHelper.getItems(); 
        adapter = new ItemAdapter(getActivity().getApplicationContext(), items);
        this.setListAdapter(adapter);

    }



    @Override
    public void onResume() {
        super.onResume();
        items.clear();
        items = dbHelper.getItems(); //reload the items from database
        adapter.notifyDataSetChanged();
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        if(dbHelper != null) { //item is edited
            Item item = (Item) this.getListAdapter().getItem(position);
            Intent intent = new Intent(getActivity(), AddItemActivity.class);
            intent.putExtra(IntentConstants.ITEM, item);
            startActivity(intent);
        }
    }
}

আমার তালিকাভিউ

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

কিন্তু এই রিফ্রেশ না ListView। অ্যাপ্লিকেশন পুনরায় চালু করার পরেও আপডেট হওয়া আইটেমগুলি প্রদর্শিত হয় না। আমার ItemAdapterপ্রসারিতBaseAdapter

public class ItemAdapter extends BaseAdapter{

    private LayoutInflater inflater;
    private List<Item> items;
    private Context context;

    public ProjectListItemAdapter(Context context, List<Item> items) {
        super();
        inflater = LayoutInflater.from(context);
        this.context = context;
        this.items = items;

    }

    @Override
    public int getCount() {
        return items.size();
    }

    @Override
    public Object getItem(int position) {
        return items.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ItemViewHolder holder = null;
        if(convertView == null) {
            holder = new ItemViewHolder();
            convertView = inflater.inflate(R.layout.list_item, parent,false);
            holder.itemName = (TextView) convertView.findViewById(R.id.topText);
            holder.itemLocation = (TextView) convertView.findViewById(R.id.bottomText);
            convertView.setTag(holder);
        } else {
            holder = (ItemViewHolder) convertView.getTag();
        }
        holder.itemName.setText("Name: " + items.get(position).getName());
        holder.itemLocation.setText("Location: " + items.get(position).getLocation());
        if(position % 2 == 0) {                                                                                 
            convertView.setBackgroundColor(context.getResources().getColor(R.color.evenRowColor));
        } else {    
            convertView.setBackgroundColor(context.getResources().getColor(R.color.oddRowColor));
        }
        return convertView;
    }

    private static class ItemViewHolder {
        TextView itemName;
        TextView itemLocation;
    }
}

কেউ দয়া করে সাহায্য করতে পারেন?


2
ডাটাবেস অপারেশন সঠিকভাবে কাজ করছে কিনা তা পরীক্ষা করে দেখেছেন? অ্যাডাপ্টারটি কেমন দেখাচ্ছে? এছাড়াও, আপনি যদি adapterরেফারেন্সের জন্য কোনও অনজেক্ট তৈরি করেন তবে কেন আপনি নীচের নীচের এক লাইনের জন্য এটি পরীক্ষা করছেন?
Luksprog

কোড ব্যতিক্রম ছুঁড়ে না ফেলেছে এবং আমি ডিবাগ ব্যবহার করে পরীক্ষা করেছি। সমস্ত পদ্ধতি ত্রুটি ছাড়াই কার্যকর করা হয়েছে। হ্যাঁ একটি নির্বোধ ভুল।
কোডার

উত্তর:


229

আপনার onResumeপদ্ধতিটি এখানে দেখুন ItemFragment:

@Override
public void onResume() {
    super.onResume();
    items.clear();
    items = dbHelper.getItems(); // reload the items from database
    adapter.notifyDataSetChanged();
}

কল করার আগে আপনি যা আপডেট করেছেন notifyDataSetChanged()তা অ্যাডাপ্টারের ক্ষেত্র private List<Item> items;নয়, খণ্ডের অভিন্ন ঘোষিত ক্ষেত্র। আপনি অ্যাডাপ্টার তৈরি করার সময় অতিক্রমকারী আইটেমগুলির তালিকার একটি রেফারেন্স সংরক্ষণ করে (যেমন খণ্ডের অনক্রিট)। সংক্ষিপ্ততম (পরিবর্তনের সংখ্যার অর্থে) তবে আপনার কোডটি যেমনটি আপনি প্রত্যাশা করেন তেমন আচরণ করার মার্জিত উপায় নয় কেবল লাইনটি প্রতিস্থাপন করা:

    items = dbHelper.getItems(); // reload the items from database

সঙ্গে

    items.addAll(dbHelper.getItems()); // reload the items from database

আরও মার্জিত সমাধান:

1) আইটেমগুলি private List<Item> items;থেকে সরান ItemFragment- আমাদের কেবল তাদের অ্যাডাপ্টারে রেফারেন্স রাখতে হবে

2) onCreate এতে পরিবর্তন করুন:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.setHasOptionsMenu(true);
    getActivity().setTitle(TITLE);
    dbHelper = new DatabaseHandler(getActivity());
    adapter = new ItemAdapter(getActivity(), dbHelper.getItems());
    setListAdapter(adapter);
}

3) আইটেমএডাপ্টারে পদ্ধতি যুক্ত করুন:

public void swapItems(List<Item> items) {
    this.items = items;
    notifyDataSetChanged();
}

4) আপনার অনারিউম এ পরিবর্তন করুন:

@Override
public void onResume() {
    super.onResume();
    adapter.swapItems(dbHelper.getItems());
}

অ্যাডাপ্টারে পুরো ডিবিহেল্পার জিনিসটি স্থানান্তর করা কি পরিষ্কার হবে না? সুতরাং আপনি কেবল কল করবেন adapter.swapItems();এবং অ্যাডাপ্টার স্টাফটি করবে dbHelper.getItems()। তবে যাইহোক উত্তরের জন্য ধন্যবাদ :)
আনসগার

7
আপনাকে কেন পরিষ্কার করতে হবে () এবং আইটেমগুলি আবার যুক্ত করতে হবে? এটাই কি ঠিক উদ্দেশ্য নয় notifyDataSetChanged()?
ফিল রায়ান

1
@tomsaz আপনি আমাকে এই সাহায্য করতে পারে stackoverflow.com/questions/28148618/...

1
ধন্যবাদ @ টমাসজ গাওয়েল, আপনার অদলবদলগুলি আমাকে সত্যই অনেক সাহায্য করে, আমি জানি না যে আমার অ্যাডাপ্টারটি কেন কাজ করে না ify ধারণা
কিমমি ধিঙ্গরা

1
এই উত্তরটি সঠিক। সমস্যাটি হ'ল অ্যাডাপ্টারের আইটেম অ্যারেলিস্ট আপডেট করা হচ্ছিল না। এর অর্থ আপনার মুখের কোনও প্রভাব ছাড়াই নীল না হওয়া পর্যন্ত আপনি notifydatasetchanged কল করতে পারবেন। অ্যাডাপ্টার আপনার ডেটাসেটটিকে একই ডেটাসেটের সাথে আপডেট করছে যাতে কোনও পরিবর্তন হয় না। এই উত্তরে পোস্ট করা সমাধানের আরেকটি বিকল্প যা পরিষ্কার হতে পারে: অ্যাডাপ্টার.াইটেমস = আইটেম; adapter.notifyDataSetChanged ();
রায় লি

23

আপনি গ্লোবাল ভেরিয়েবল আইটেমগুলিতে পুনরায় লোড হওয়া আইটেমগুলি বরাদ্দ করছেন onResume(), তবে ItemAdapterএটি শ্রেণিতে প্রতিফলিত হবে না , কারণ এর নিজস্ব আইটেমগুলি নামে পরিচিত আইটেম রয়েছে vari

রিফ্রেশ করার জন্য ক্লাসে ListViewএকটি রিফ্রেশ () যুক্ত করুন ItemAdapterযা তালিকার ডেটা অর্থাৎ আইটেমগুলিকে গ্রহণ করে

class ItemAdapter
{
    .....

    public void refresh(List<Item> items)
    {
        this.items = items;
        notifyDataSetChanged();
    } 
}

onResume()নিম্নলিখিত কোড সহ আপডেট করুন

@Override
public void onResume()
{
    super.onResume();
    items.clear();
    items = dbHelper.getItems(); //reload the items from database
    **adapter.refresh(items);**
}

1
এটা ঠিক ঠিক। অ্যাডাপ্টারের কনস্ট্রাক্টর আইটেম উত্তীর্ণ হওয়ার প্রত্যাশা করে তবে তিনি কেবল বাইরের শ্রেণীর ক্ষেত্রটিই আপডেট করেন।
লাক্সারীমোড

হাই সান্থোষ : আপনি একই সমস্যা কটাক্ষপাত করা যাবে stackoverflow.com/questions/35850715/...

8

OnResume () এ এই লাইনটি পরিবর্তন করুন

items = dbHelper.getItems(); //reload the items from database

প্রতি

items.addAll(dbHelper.getItems()); //reload the items from database

সমস্যাটি হ'ল আপনি কখনই নতুন আইটেমের তালিকা সম্পর্কে আপনার অ্যাডাপ্টারটি বলছেন না। আপনি যদি নিজের অ্যাডাপ্টারে কোনও নতুন তালিকা পাস করতে চান না (যেমন মনে হয় আপনি তা করেন না) তবে কেবল items.addAllআপনার পরে ব্যবহার করুন clear()। এটি নিশ্চিত করবে যে আপনি অ্যাডাপ্টারের যে রেফারেন্সটি রেফারেন্স করেছেন সেই একই তালিকাটি আপনি সংশোধন করছেন।


এটি বিভ্রান্তিকর যা adapter.clear()অ্যাডাপ্টারকে বুঝতে অনুভব করতে বাধ্য করে না যে ভিউটি রিফ্রেশ হওয়া উচিত, adapter.add()বা করা adapter.addAll()উচিত। যদিও উত্তরের জন্য ধন্যবাদ!
w3bshark

নোট করুন যে আমি items.addAll()অ্যাডাপ্টার.এডডএল () ব্যবহার করেছিলাম এবং করছি না। অ্যাডাপ্টার পরিবর্তনের জন্য প্রতিক্রিয়া দেখাতে দিচ্ছে এমন একমাত্র জিনিস notifyDataSetChanged। অ্যাডাপ্টারের একেবারে পরিবর্তনগুলি দেখার কারণটি হ'ল itemsতালিকাটি অ্যাডাপ্টারটি ব্যবহার করছে।
জাস্টিন ব্রেটফেলার

4

যদি অ্যাডাপ্টারটি ইতিমধ্যে সেট করা থাকে তবে এটি পুনরায় সেট করা তালিকার দর্শনটি রিফ্রেশ করবে না। পরিবর্তে প্রথমে তালিকার ভিউটিতে অ্যাডাপ্টার রয়েছে কিনা তা পরীক্ষা করে যথাযথ পদ্ধতিতে কল করুন।

আমি মনে করি তালিকার ভিউটি সেট করার সময় অ্যাডাপ্টারের একটি নতুন উদাহরণ তৈরি করা খুব ভাল ধারণা নয়। পরিবর্তে, একটি বস্তু তৈরি করুন।

BuildingAdapter adapter = new BuildingAdapter(context);

    if(getListView().getAdapter() == null){ //Adapter not set yet.
     setListAdapter(adapter);
    }
    else{ //Already has an adapter
    adapter.notifyDataSetChanged();
    }

এছাড়াও আপনি ইউআই থ্রেডে রিফ্রেশ তালিকাটি চালানোর চেষ্টা করতে পারেন:

activity.runOnUiThread(new Runnable() {         
        public void run() {
              //do your modifications here

              // for example    
              adapter.add(new Object());
              adapter.notifyDataSetChanged()  
        }
});

আমি কীভাবে ইউআই থ্রেড প্রয়োগ করব তা নিশ্চিত নই। আমার মূল ক্রিয়াকলাপে 3 টি টুকরা (ট্যাব) রয়েছে এবং প্রশ্নের কোডটি খণ্ডের সাথে তালিকায় রয়েছে এমন একটি খণ্ডের সাথে সম্পর্কিত। আইটেমগুলিতে পাস করার কারণটি ItemAdapterহ'ল আমি সারিগুলিকে রঙ করতে চাই এবং তালিকার ভিউ একাধিক ডেটা আইটেম প্রদর্শন করে। আমি অ্যাডাপ্টারের জন্য কোড পোস্ট করেছি।
কোডার

"আপনার" ব্যবহার করে আপনার কোডটি আমার উদাহরণ কোডে আপনার তালিকা স্থাপন করতে হবে। "ক্রিয়াকলাপ" এর পরিবর্তে
আলেক্সগো

কিছু ক্ষেত্রে এটি আপডেট হয় না যখন আপনি নোটিফিকেশন ডেটাসেট চেঞ্জড () বিভিন্ন থ্রেডে চালান, সুতরাং উপরের সমাধানটি কিছু ক্ষেত্রে সঠিক।
আয়মান আল-আবসি

4

আপনি আপডেট করতে আপনার listview ব্যাপার না আপনি যে কাজ করতে চান চান onResume(), onCreate()অথবা অন্য কোনো ফাংশনে, প্রথম জিনিস আপনি বুঝতে আছে যে আপনার অ্যাডাপ্টারের একটি নতুন দৃষ্টান্ত তৈরি করার প্রয়োজন হবে না, শুধু জনপূর্ণ আপনার ডেটা দিয়ে আবার অ্যারে। ধারণাটি এর অনুরূপ কিছু:

private ArrayList<String> titles;
private MyListAdapter adapter;
private ListView myListView;

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    myListView = (ListView) findViewById(R.id.my_list);

    titles = new ArrayList<String>()

    for(int i =0; i<20;i++){
        titles.add("Title "+i);
    }

    adapter = new MyListAdapter(this, titles);
    myListView.setAdapter(adapter);
}


@Override
public void onResume(){
    super.onResume();
    // first clear the items and populate the new items
    titles.clear();
    for(int i =0; i<20;i++){
        titles.add("New Title "+i);
    }
    adapter.notifySetDataChanged();
}

সুতরাং যে উত্তর উপর নির্ভর করে List<Item>আপনার নিজের মধ্যে একই ব্যবহার করা উচিত Fragment। আপনার প্রথম অ্যাডাপ্টার সূচনাতে আপনি আইটেমগুলির সাথে আপনার তালিকাটি পূরণ করুন এবং অ্যাডাপ্টারকে আপনার তালিকার দৃশ্যে সেট করুন। এর পরে আপনার আইটেমগুলির প্রতিটি পরিবর্তনের ক্ষেত্রে আপনাকে মূলটি থেকে মানগুলি সাফ করতে List<Item> itemsহবে এবং নিজের নতুন আইটেম এবং কল দিয়ে আবার এটি তৈরি করতে হবে notifySetDataChanged();

এটি কিভাবে এটি কাজ করে:)।


উত্তরের জন্য ধন্যবাদ. আপনি উল্লেখ হিসাবে পরিবর্তনগুলি করেছি। আমি আমার কোড পোস্ট করেছি। এটি এখনও কাজ করে না। এখন এটি নতুন আইটেম যুক্ত করা হলে তালিকার ভিউ এমনকি দেখায় না।
কোডার

আমি কোড পরিবর্তন করেছি। আশ্চর্যজনক বিষয়টি লক্ষ্য করুন যে আইটেমটি ডিবি
কোডার

এই থ্রেডটি ডাটাবেস স্ট্যাকওভারফ্লো.com
কোডার

3

অ্যালেক্সগোর একটি উত্তর আমার পক্ষে কৌশলটি করেছে:

getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
         messages.add(m);
         adapter.notifyDataSetChanged();
         getListView().setSelection(messages.size()-1);
        }
});

তালিকার আপডেটটি আমার জন্য কাজ করেছিল যখন জিইউআই ইভেন্ট থেকে আপডেটটি ট্রিগার করা হয়েছিল, এভাবে ইউআই থ্রেডে ছিল।

যাইহোক, আমি যখন অন্য ইভেন্ট / থ্রেড - অর্থাৎ অ্যাপ্লিকেশনটির বাইরের কোনও কল থেকে তালিকা আপডেট করি তখন আপডেটটি ইউআই থ্রেডে না থাকায় এটি লিস্টভিউয়ের কলটিকে উপেক্ষা করে। উপরের মতো রানঅনউইথ্রেডের সাথে আপডেটটি কল করা আমার জন্য কৌশলটি করেছে। ধন্যবাদ !!


3

এটা চেষ্টা কর

@Override
public void onResume() {
super.onResume();
items.clear();
items = dbHelper.getItems(); //reload the items from database
adapter = new ItemAdapter(getActivity(), items);//reload the items from database
adapter.notifyDataSetChanged();
}

3
adpter.notifyDataSetInvalidated();

onPause()কার্যকলাপ শ্রেণীর পদ্ধতিতে এটি ব্যবহার করে দেখুন ।



1

যদি আপনার তালিকাটি অ্যাডাপ্টারে নিজেই অন্তর্ভুক্ত থাকে তবে তালিকাটি আপডেট করে এমন ফাংশনটি কল করেও কল করা উচিত notifyDataSetChanged()

ইউআই থ্রেড থেকে এই ফাংশনটি চালানো আমার পক্ষে কৌশলটি করেছে:

refresh()ফাংশন অ্যাডাপ্টার ভিতরে

public void refresh(){
    //manipulate list
    notifyDataSetChanged();
}

তারপরে ইউআই থ্রেড থেকে এই ফাংশনটি চালান

getActivity().runOnUiThread(new Runnable() { 
    @Override
    public void run() {
          adapter.refresh()  
    }
});

আপডেটটি একটি ভিন্ন থ্রেডের মাধ্যমে নেটওয়ার্কের মাধ্যমে আসার সাথে সাথে এটি আমার পক্ষে সত্যিই একটি পার্থক্য তৈরি করেছে।
চক

0

এটির মতো চেষ্টা করুন:

this.notifyDataSetChanged();

পরিবর্তে:

adapter.notifyDataSetChanged();

যা শুরু করেছো notifyDataSetChanged()করার ListViewঅ্যাডাপ্টারের বর্গ নয়।


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