本帖最后由 treachery 于 2011-03-10 12:07:57 编辑

解决方案 »

  1.   

    发消息,在message handler里边更新
      

  2.   

    你线程处理的有点诡异...用Java原生态的Thread,然后发消息给handler,在handler里面更新你的listView
    附:非UI线程是不能“直接”对UI线程里面的组件进行操作的
      

  3.   

     
    Runnable add=new Runnable(){
     
    @Override
    public void run() {
    List<PeopleInfo> myList = new ArrayList<PeopleInfo>();
            MyAdapter ca = new MyAdapter(ListTest.this,myList);
            //ca.setNotifyOnChange(true);
            lv.setAdapter(ca);
            
            for(int i=1;i<=100;i++){
                
                //增加记录
                PeopleInfo pe = new PeopleInfo();
                pe.setPeoleName("Fucker"+Integer.toString(i));
                pe.setPeopleNum(Integer.toString(i));
                System.out.println("i:"+Integer.toString(i));
                System.out.println("PeopleInfo-->Name:"+pe.peopleName);
                System.out.println("PeopleInfo-->Num :"+pe.peopleNum);
                ca.add(pe);
                
                SystemClock.sleep(50L); //为了看到效果,故意增加一个延迟
            }
            ca.notifyDataSetChanged();
    }   
        };
      

  4.   

    message handler 才可以更UI的
      

  5.   

    这位兄弟是不是更本就没有过目代码,我就是在message handler里更新的
       所以才无比蛋疼来提问的。
      

  6.   


    兄弟,你也一样,请稍微看一眼代码好吗?我就是在message handler里更新的UI
      

  7.   

    如果不是"用Java原生态的Thread,然后发消息给handler,在handler里面更新你的listView",那应该怎么做呢?
      

  8.   

    你线程处理的有点诡异...用Java原生态的Thread,然后发消息给handler,在handler里面更新你的listView
    附:非UI线程是不能“直接”对UI线程里面的组件进行操作的
    [/Quote]
      

  9.   

    List<PeopleInfo> myList = new ArrayList<PeopleInfo>();
            MyAdapter ca = new MyAdapter(ListTest.this,myList);
            //ca.setNotifyOnChange(true);
            lv.setAdapter(ca);以上代码放到onCreate里面去。
    AddListItem里面通过getAdapter得到数据适配器,然后添加数据。ca.notifyDataSetChanged();
    应该写在循环里面。
      

  10.   


    首先感谢你的回答。  我已经按照你说的改好了,但是还是一样报错,错误还是:Only the original thread that created a view hierarchy can touch its views
      

  11.   

    如果是我,我想我会这么写。不知道是不是符合你的要求。    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mListView = (ListView)findViewById(R.id.list);        new Thread(new Runnable() {
                public void run() {
                    mHandler.postDelayed((new Runnable() {
                        public void run() {
                            AddListItem();
                        }
                    }), 1000);
                }
            }).start();
        }
      

  12.   

    补充两个定义:    private ListView mListView;    Handler mHandler = new Handler();
      

  13.   

    我的写法和上面的一样。。我的这这样的。。
    ublic Handler handler = new Handler() {
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1:
    mDateBase.delete(modelname);
    mCursor = mDateBase.select();
    listView.invalidateViews();
    break;
    }
    super.handleMessage(msg);
    }
    };
    public class MyAdapter extends BaseAdapter { private LayoutInflater inflater;
    private View myView;
    public MyAdapter(Context c) {
    this.inflater = LayoutInflater.from(c);
    }
    public int getCount() {
    return mCursor.getCount() - 8;
    }
    public Object getItem(int position) {
    return null;
    }
    public long getItemId(int position) {
    return 0;
    } public View getView(int position, View convertView, ViewGroup parent) {
    if (strOpt.equals("480*800")) {
     myView = inflater.inflate(R.layout.modeldelectlist, null);
    }
    if (strOpt.equals("320*480")) {
     myView = inflater.inflate(R.layout.modeldelectlistone, null);
    }
    final TextView textView = (TextView) myView
    .findViewById(R.id.name_deletelist);
    final int c = position;
    mCursor.moveToPosition(8 + position);
    textView.setText(mCursor.getString(1));
    ImageButton button = (ImageButton) myView
    .findViewById(R.id.ImageButton_deletelist);
    button.setFocusable(false);
    button.setOnClickListener(new OnClickListener() {

    public void onClick(View v) {
    modelname = textView.getText().toString();
    mCursor.moveToPosition(8 + c);
    AlertDialog.Builder dialogBuilder = new Builder(
    ModelDeleteActivity.this);
    dialogBuilder.setTitle("你真的要删除吗");
    String[] strarrStrings = new String[] { "YES", "NO" };
    dialogBuilder.setItems(strarrStrings,
    new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog,
    int which) {
    switch (which) {
    case 0:
    if (mCursor.getInt(8) == 2) {
    mDateBase.update("经典", 2);
    }
    Message message = new Message();
    message.what = 1;
    handler.sendMessage(message);
    Toast.makeText(
    ModelDeleteActivity.this,
    "模式已删除!", Toast.LENGTH_SHORT)
    .show();
    break;
    case 1:
    break;
    default:
    break;
    }
    }
    });
    dialogBuilder.show();
    }
    });
    return myView;
    }
    }希望能够帮助到你
      

  14.   

    你确定用的handler是UI线程的Handler?
      

  15.   

    文档上说,Handler运行在创建它的线程中,也就是主线程。
      

  16.   

    在非UI线程里面是不能更新UI控件的,你在这里通过HandlerThread创建了一个新的线程肯定是不行的。而Handler handler = new Handler() {
    public void handleMessage(Message msg) {
    }}
    是跑在UI线程里面的,可以用来异步更新UI
      

  17.   


    我就不明白了,Android的这个所谓的Runnable类有什么用啊?这样写是不报错了,但是效果还是把ListView的100条数据全部添加完最后才一次性显示出来的,添加完之前程序会黑着半天,而如果是这样的话,那我直接调用我自己写的AddListItem()函数不就完了,反正都是会被阻塞住,我何必要用一个线程,再来一个Runable来做呢?完全没有达到效果,我希望的效果是,for循环里增加一条数据,这个数据就立马在ListView里显示出来,运行的效果应该是ListView显示一条数据,停顿一下,然后再显示下一条,然后再停顿一下,直到显示完所有100条数据为止,而且在这过程中不影响用户其他的操作。而现在按照文档的这个要求,用所谓的这个在主线程中调用Runable,和直接调用一个函数的效果是一样的。
      

  18.   

    给你2例子,google上的
    1.用View.post的方法.
     new Thread(new Runnable() {
            public void run() {
                final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");
                mImageView.post(new Runnable() {
                    public void run() {
                        mImageView.setImageBitmap(bitmap);
                    }
                });
            }
        }).start();public void onClick(View v) {
        new DownloadImageTask().execute("http://example.com/image.png");
    }
    2.用AsyncTask队列处理
    private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
        protected Bitmap doInBackground(String... urls) {
            return loadImageFromNetwork(urls[0]);
        }
        protected void onPostExecute(Bitmap result) {
            mImageView.setImageBitmap(result);
        }
    }
    新手多看看文档
    file:///D:/android-sdk-windows/docs/guide/topics/fundamentals/processes-and-threads.html
    sdk里面带了的。这里面有很多注意事项
      

  19.   

    还是给个例子吧,你这用法感觉非常奇怪(我说楼主):    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);        ArrayAdapter<String> ad = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, new Vector<String>());
            
            mlv = new ListView(this);
            mlv.setAdapter(ad);        setContentView(mlv);
            
            mh = new Handler();
            new Thread() {
    @Override
    public void run() {
    // TODO Auto-generated method stub
    for (int i = 0; i < 5; ++i) {
    First_Android.this.mh.post(new Runnable() {
    public void run() {
    // TODO Auto-generated method stub
    int n = new Random().nextInt();

    @SuppressWarnings("unchecked")
    ArrayAdapter<String> ad = (ArrayAdapter<String>) First_Android.this.mlv.getAdapter();
    ad.add(Integer.toString(n));
    ad.notifyDataSetChanged();
    }
    });

    try {
    sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
            }.start();
    我刚写的。
      

  20.   

    更简单的,把mh = new Handler();去掉
    把First_Android.this.mh.post改为irst_Android.this.runOnUiThread
      

  21.   


    谢谢你,朋友,可是你的例子里的First_Android.this.mh.pos和First_Android.this.runOnUiThread到底是什么意思啊?我在编译环境里无法识别First_Android
      

  22.   

    按照你的要求修改了一下,你代码最大的问题就是在Handler的处理过程中加入了Sleep,等于把主线程阻塞了,导致界面绘制不畅。
    public class ListTest extends Activity {    private ListView mListView;    Handler mHandler = new Handler();    List<PeopleInfo> mList = null;
        MyAdapter mAdapter = null;    /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            mListView = (ListView)findViewById(R.id.list);        mList = new ArrayList<PeopleInfo>();        mAdapter = new MyAdapter(ListTest.this, mList);        mListView.setAdapter(mAdapter);        new Thread(new Runnable() {
                public void run() {
                    while (true) {
                        mHandler.post(new Runnable() {
                            public void run() {
                                AddListItem();
                            }
                        });
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }    // 循环增加100个列表项
        protected void AddListItem() {
            // 增加记录
            PeopleInfo pe = new PeopleInfo();
            int number = (int)(Math.random() * 1000);
            pe.setPeoleName("Haha " + Integer.toString(number));
            pe.setPeopleNum(Integer.toString(number));
            System.out.println("i:" + Integer.toString(number));
            System.out.println("PeopleInfo-->Name:" + pe.peopleName);
            System.out.println("PeopleInfo-->Num :" + pe.peopleNum);
            mAdapter.add(pe);//        SystemClock.sleep(1000); // 为了看到效果,故意增加一个延迟
            mAdapter.notifyDataSetChanged();
        }
    }
      

  23.   


    不好意思,First_Android是我的activity的名字,mh是我new出来的一个Handler,在onCreate里面如下:
    mh = new Handler();
    注意,它是个成员变量,否则在线程里面访问不了。
      

  24.   

    ListTest:
    public class ListTest extends Activity {
    //-------------------------------------------------------------------
        private Thread myThread = new Thread(){
         @Override
         public void run () {
         AddListItem();
         }
        };
        //------------------------------------------------------------------
        
        private MyHandler myHandler = new MyHandler();
        private ListView lv;
     
    @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            lv = (ListView)findViewById(R.id.list);
            
            
    //        //创建新线程用来显示列表
    //        HandlerThread handlerThread = new HandlerThread("hthread_readcontact");
    //        handlerThread.start(); //异步启动线程
    //        //创建Handler
    //        MyHandler myHandler = new MyHandler(handlerThread.getLooper());
    //        //创建消息对象
    //        Message msg = myHandler.obtainMessage();
    //        
    //        //取出消息并执行
    //        msg.sendToTarget();       //----------------------------------------------------------------------
           
            List<PeopleInfo> myList = new ArrayList<PeopleInfo>();
            MyAdapter ca = new MyAdapter(this, myList);
            lv.setAdapter(ca);
            
            myThread.start();
            //------------------------------------------------------------------------
        }
        
        //循环增加100个列表项
        protected void AddListItem(){
    //       List<PeopleInfo> myList = new ArrayList<PeopleInfo>();
    //          MyAdapter ca = new MyAdapter(ListTest.this,myList);
    //          //ca.setNotifyOnChange(true);
    //          lv.setAdapter(ca);    
            for(int i=1;i<=100;i++){
                
                //增加记录
    //            PeopleInfo pe = new PeopleInfo();
    //            pe.setPeopleName("Fucker"+Integer.toString(i));
    //            pe.setPeopleNum(Integer.toString(i));
    //            System.out.println("i:"+Integer.toString(i));
    //            System.out.println("PeopleInfo-->Name:"+pe.peopleName);
    //            System.out.println("PeopleInfo-->Num :"+pe.peopleNum);
                
             //-----------------------------------------------------------------------
                Message m = new Message();
                Bundle data = new Bundle();
                data.putString("name", "Fucker" + i);
                data.putString("number", "" + i);
                m.setData(data);
                myHandler.sendMessage(m);
                //------------------------------------------------------------------------
                
                SystemClock.sleep(200L); //为了看到效果,故意增加一个延迟
            }
            //ca.notifyDataSetChanged();    }
        class MyHandler extends Handler{
            
            public MyHandler(){
                
            }
            
            public MyHandler(Looper looper){
                super(looper);
            }        @Override
            public void handleMessage(Message msg) {
    //         AddListItem();
    //            System.out.println("Thread is runed!");
            
             //----------------------------------------------------------------------
             if (null == msg) 
             return;
             PeopleInfo pe = new PeopleInfo();
             Bundle data = msg.getData();
             pe.setPeopleName(data.getString("name"));
             pe.setPeopleNum(data.getString("number"));
             Log.v("================", data.getString("name")+"  "+data.getString("number"));
             MyAdapter ad = (MyAdapter) lv.getAdapter();
             ad.add(pe);
             ad.notifyDataSetChanged();
             //-------------------------------------------------------------------------
            }
        }
    }MyAdapter:
     @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            
            if(convertView == null){
            ViewHolder holder;
            holder = new ViewHolder();
            
                convertView = inflater.inflate(R.layout.contact_list, null);
                //convertView = inflater.inflate(R.layout.listitem, null);
     
                holder.PhoneName = (TextView)convertView.findViewById(R.id.mname);
                holder.PhoneNum = (TextView)convertView.findViewById(R.id.msisdn);
                
                convertView.setTag(holder);
                holder.PhoneName.setText(itemList.get(position).getPeopleName());
                holder.PhoneNum.setText(itemList.get(position).getPeopleNum());
                
            }
            //-------------------------------------------------------------------------
            else {
             ViewHolder h = (ViewHolder) convertView.getTag();
             h.PhoneName.setText(itemList.get(position).getPeopleName());
             h.PhoneNum.setText(itemList.get(position).getPeopleNum());
            }
            //-------------------------------------------------------------------------
            return convertView;
        }
      

  25.   

    public class AsyncImageLoader {
    private static AsyncImageLoader asyncImageLoader = new AsyncImageLoader(); private AsyncImageLoader() {
    } public static void setAsyncImage(ImageView view, final String url) {
    asyncImageLoader.setItem(view, url);
    } private HashMap<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); public void setItem(final ImageView view, final String url) {
    if (imageCache.containsKey(url)) {
    SoftReference<Bitmap> softReference = imageCache.get(url);
    Bitmap drawableStore = softReference.get();
    if (drawableStore != null) {
    view.setImageBitmap(drawableStore);
    return;
    }
    } imageQuery.clean(view);
    ImageLoadItem item = new ImageLoadItem(view, url);
    synchronized (imageQuery.waitList) {
    imageQuery.waitList.push(item);
    imageQuery.waitList.notifyAll();
    } // start thread if it's not started yet
    if (loadThread.getState() == Thread.State.NEW)
    loadThread.start();
    } public Bitmap loadImageFromUrl(String url) {
    URL m;
    InputStream i = null;
    try {
    m = new URL(url);
    i = (InputStream) m.getContent();
    return BitmapFactory.decodeStream(i);
    } catch (MalformedURLException e1) {
    e1.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    return null;
    } private class ImageLoadItem {
    private String url;
    private ImageView view; private ImageLoadItem(ImageView v, String u) {
    url = u;
    view = v;
    }
    } private ImageQuery imageQuery = new ImageQuery(); private class ImageQuery {
    private Stack<ImageLoadItem> waitList = new Stack<ImageLoadItem>(); private void clean(ImageView v) {
    for (int j = 0; j < waitList.size();) {
    if (waitList.get(j).view == v)
    waitList.remove(j);
    else
    ++j;
    }
    }
    } private ImageLoadThread loadThread = new ImageLoadThread(); private class ImageLoadThread extends Thread {
    public void run() {
    try {
    while (true) {
    if (imageQuery.waitList.size() == 0) {
    synchronized (imageQuery.waitList) {
    imageQuery.waitList.wait();
    }
    } else {
    ImageLoadItem item;
    final ImageView view;
    String url;
    synchronized (imageQuery.waitList) {
    item = imageQuery.waitList.pop();
    }
    view = item.view;
    url = item.url;
    final Bitmap bmp = loadImageFromUrl(url);
    imageCache.put(url, new SoftReference<Bitmap>(bmp));
    Activity a = (Activity) view.getContext();
    a.runOnUiThread(new Runnable() {
    public void run() {
    view.setImageBitmap(bmp);
    }
    });
    }
    if (Thread.interrupted())
    break;
    }
    } catch (InterruptedException e) {
    // allow thread to exit
    }
    }
    }
    }这是我写的一个开辟单线程处理图片异步设置的一个类,不会阻塞程序,由于是单线程处理请求队列,程序也不会卡。另外加入SoftReference缓冲图片,因为listview在滚动时会不停的调用绘制imageview的方法。