@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);
List<PeopleInfo> myList = new ArrayList<PeopleInfo>(); MyAdapter ca = new MyAdapter(ListTest.this,myList); //ca.setNotifyOnChange(true); lv.setAdapter(ca);以上代码放到onCreate里面去。 AddListItem里面通过getAdapter得到数据适配器,然后添加数据。ca.notifyDataSetChanged(); 应该写在循环里面。
首先感谢你的回答。 我已经按照你说的改好了,但是还是一样报错,错误还是:Only the original thread that created a view hierarchy can touch its views
如果是我,我想我会这么写。不知道是不是符合你的要求。 @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(); }
补充两个定义: private ListView mListView; Handler mHandler = new Handler();
我的写法和上面的一样。。我的这这样的。。 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; } }希望能够帮助到你
你确定用的handler是UI线程的Handler?
文档上说,Handler运行在创建它的线程中,也就是主线程。
在非UI线程里面是不能更新UI控件的,你在这里通过HandlerThread创建了一个新的线程肯定是不行的。而Handler handler = new Handler() { public void handleMessage(Message msg) { }} 是跑在UI线程里面的,可以用来异步更新UI
还是给个例子吧,你这用法感觉非常奇怪(我说楼主): 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(); } });
按照你的要求修改了一下,你代码最大的问题就是在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(); } }
不好意思,First_Android是我的activity的名字,mh是我new出来的一个Handler,在onCreate里面如下: mh = new Handler(); 注意,它是个成员变量,否则在线程里面访问不了。
ListTest: public class ListTest extends Activity { //------------------------------------------------------------------- private Thread myThread = new Thread(){ @Override public void run () { AddListItem(); } }; //------------------------------------------------------------------
private MyHandler myHandler = new MyHandler(); private ListView lv;
附:非UI线程是不能“直接”对UI线程里面的组件进行操作的
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();
}
};
所以才无比蛋疼来提问的。
兄弟,你也一样,请稍微看一眼代码好吗?我就是在message handler里更新的UI
附:非UI线程是不能“直接”对UI线程里面的组件进行操作的
[/Quote]
MyAdapter ca = new MyAdapter(ListTest.this,myList);
//ca.setNotifyOnChange(true);
lv.setAdapter(ca);以上代码放到onCreate里面去。
AddListItem里面通过getAdapter得到数据适配器,然后添加数据。ca.notifyDataSetChanged();
应该写在循环里面。
首先感谢你的回答。 我已经按照你说的改好了,但是还是一样报错,错误还是:Only the original thread that created a view hierarchy can touch its views
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();
}
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;
}
}希望能够帮助到你
public void handleMessage(Message msg) {
}}
是跑在UI线程里面的,可以用来异步更新UI
我就不明白了,Android的这个所谓的Runnable类有什么用啊?这样写是不报错了,但是效果还是把ListView的100条数据全部添加完最后才一次性显示出来的,添加完之前程序会黑着半天,而如果是这样的话,那我直接调用我自己写的AddListItem()函数不就完了,反正都是会被阻塞住,我何必要用一个线程,再来一个Runable来做呢?完全没有达到效果,我希望的效果是,for循环里增加一条数据,这个数据就立马在ListView里显示出来,运行的效果应该是ListView显示一条数据,停顿一下,然后再显示下一条,然后再停顿一下,直到显示完所有100条数据为止,而且在这过程中不影响用户其他的操作。而现在按照文档的这个要求,用所谓的这个在主线程中调用Runable,和直接调用一个函数的效果是一样的。
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里面带了的。这里面有很多注意事项
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();
我刚写的。
把First_Android.this.mh.post改为irst_Android.this.runOnUiThread
谢谢你,朋友,可是你的例子里的First_Android.this.mh.pos和First_Android.this.runOnUiThread到底是什么意思啊?我在编译环境里无法识别First_Android
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();
}
}
不好意思,First_Android是我的activity的名字,mh是我new出来的一个Handler,在onCreate里面如下:
mh = new Handler();
注意,它是个成员变量,否则在线程里面访问不了。
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;
}
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的方法。