Search code examples
androidlistviewbroadcastreceiverparcelableintentservice

IllegalStateException listView updating from the service


I use IntentService for recieving some data from the web-server and update my listview in Activity with this data. I used static ArrayList in the Activity and when I've got updatings from the server, I added item to the static ArrayList and sent broadcast notification to the Activity. But it caused IllegalStateException. I decided to use Parcelable class for my list updatings. So my object's class looks like that:

   public class Order implements Parcelable{

// ....fields initialazion
public Order()
{}
public Order(List<File> files, boolean customer_deadline_sent,
        boolean payed, boolean payment_failed, boolean not_payed_sent,
        String info, int id, Category category, String timezone,
        String title, Level level, DateTime updated_at, float price,
        DateTime checkpoint_deadline, boolean h_notified, float refund,
        String special_info, boolean checkpoint_deadline_sent,
        ProcessStatus process_status, DateTime created_at,
        CustomerThread cus_thread, boolean den, DateTime deadline , boolean is_active,
        Product product, Subject subject) {
    this.files = files;
    this.customer_deadline_sent = customer_deadline_sent;
    this.payed = payed;
    this.payment_failed = payment_failed;
    this.not_payed_sent = not_payed_sent;
    this.info = info;
    this.id = id;
    this.category = category;
    this.timezone = timezone;
    this.title = title;
    this.level = level;
    this.updated_at = updated_at;
    this.price = price;
    this.checkpoint_deadline = checkpoint_deadline;
    this.h_notified = h_notified;
    this.refund = refund;
    this.special_info = special_info;
    this.checkpoint_deadline_sent = checkpoint_deadline_sent;
    this.process_status = process_status;
    this.created_at = created_at;
    this.cus_thread = cus_thread;
    this.den = den;
    this.deadline = deadline;
    this.is_active = is_active;
    this.product = product;
    this.subject = subject;
}
//...getters and setters
    private void readFromParcel(Parcel in) {
    boolean[] myBooleanArr = new boolean[6];


    files = in.readArrayList(File.class.getClassLoader());

    checkpoint_deadline_sent = myBooleanArr[0];
    customer_deadline_sent =  myBooleanArr[1];
    payed = myBooleanArr[2];
    payment_failed = myBooleanArr[3];
    not_payed_sent = myBooleanArr[4];
    den = myBooleanArr[5];
    h_notified = myBooleanArr[6];
    in.readBooleanArray(myBooleanArr);
    special_info = in.readString();
    title = in.readString();
    timezone = in.readString();
    info = in.readString();
    id = in.readInt();
    category = in.readParcelable(Category.class.getClassLoader());
    level = in.readParcelable(Level.class.getClassLoader());
    updated_at =  in.readParcelable(DateTime.class.getClassLoader());
    deadline =  in.readParcelable(DateTime.class.getClassLoader());
    checkpoint_deadline =  in.readParcelable(DateTime.class.getClassLoader());
    created_at =  in.readParcelable(DateTime.class.getClassLoader());
    process_status =  in.readParcelable(ProcessStatus.class.getClassLoader());
    cus_thread =  in.readParcelable(CustomerThread.class.getClassLoader());
    price = in.readFloat();
    refund = in.readFloat();

}
public void writeToParcel(Parcel par, int arg1) {
    par.writeList(files);
    par.writeBooleanArray(new boolean[] {checkpoint_deadline_sent});
    par.writeBooleanArray(new boolean[] {customer_deadline_sent});
    par.writeBooleanArray(new boolean[] {payed});
    par.writeBooleanArray(new boolean[] {payment_failed});
    par.writeBooleanArray(new boolean[] {not_payed_sent});
    par.writeBooleanArray(new boolean[] {den});
    par.writeBooleanArray(new boolean[] {h_notified});
    par.writeString(special_info);
    par.writeString(info);
    par.writeString(timezone);
    par.writeString(title);
    par.writeInt(id);
    par.writeParcelable(category, arg1);
    par.writeParcelable(level, arg1);
    par.writeParcelable(checkpoint_deadline, arg1);
    par.writeParcelable(created_at, arg1);
    par.writeParcelable(deadline, arg1);
    par.writeParcelable(updated_at, arg1);
    par.writeParcelable(cus_thread, arg1);
    par.writeParcelable(process_status, arg1);
    par.writeFloat(price);
    par.writeFloat(refund);
}

public static final Parcelable.Creator<Order> CREATOR =
        new Parcelable.Creator<Order>() {
            public Order createFromParcel(Parcel in) {
                return new Order(in);
            }

            public Order[] newArray(int size) {
                //throw new UnsupportedOperationException();
                return new Order[size];
            }
        };
  }

This is how I add item in the IntentService:

 @Override
    protected void onHandleIntent(Intent intent) {
    // getting existing static ArrayList from the Activity
   public ArrayList<Order> serviceOrders =  DashboardActivityAlt.forPrint;
   // getting Order object from the web server and...
   serviceOrders.add(0,orderObj);
   // and finally sending it to the Activity:
   intent = new Intent(ORDERS_IMPORT);
   intent.putParcelableArrayListExtra("orders",  serviceOrders);
   sendBroadcast(intent);
}

and this is how I get in the Activity:

  @Override
        public void onReceive(Context context, Intent intent) {
            Log.i("Dashboard onreceive", "I've got receiving");
            updateUI(intent);       
        }
    };


    private void updateUI(Intent intent) {

        try 
        {   

            DashboardActivityAlt.this.runOnUiThread(new Runnable (){
            public void run() {

                         adapter.notifyDataSetChanged();
                    }
            });
        } 
        catch (Exception e) 
        {
            e.printStackTrace();
        }
    }

but nevertheless I've got the same IllegalStateException.

    java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296256, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]
    at android.widget.ListView.layoutChildren(ListView.java:1558)
at android.widget.AbsListView.onLayout(AbsListView.java:1366)
at android.view.View.layout(View.java:7175)
at android.widget.RelativeLayout.onLayout(RelativeLayout.java:912)
at android.view.View.layout(View.java:7175)
at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
at android.view.View.layout(View.java:7175)
at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
at android.view.View.layout(View.java:7175)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1146)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1866)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3687)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
at dalvik.system.NativeStart.main(Native Method)

Tell me please, how can I avoid this?


Solution

  • I solved this issue, using Handler to add item to my listView, so this adding will be executing in the UI thread. I use the same public static ArrayList and add item to it with the Handler. Worked for me...

        private void addMethod(Order r)
        {
            mHandler.post(new sendUpdatings(r));
        }
    
     private class sendUpdatings implements Runnable {
            Order r;
    
            public sendUpdatings(Order r) {
                this.r = r;
            }
    
            public void run(){
                 DashboardActivityAlt.forPrint.add(0,r);
            }
        }