Reputation: 33
I am a newbie of android programming. After some study of ListView and ArrayAdapter, i decided to write a simple demo program just for practicing.
I want to display my custom view style ListView, so I override ArrayAdapter's getView() function. I know that for preventing memory leak, parameter convertView should be checked, and only inflate new object when convertView is null. I Also make a AsyncTask to keep adding data into ArrayAdapter in background(in doInBackground), and keep notifyDataChanged to ListView(in onProgressUpdate() ).
Here is the problem: when I set MAX_ITEM=50 (which means how many data i will add in AsyncTask), everything works fine. But when I set MAX_ITEM=500, logcat shows error message: "Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views." and application shut down. Can anyone tell me where the problem is? The following is my source code "MyTest.java" and my layout xml file "main.xml" and "layout_row.xml", thanks for your watching and helping.
MyTest.Java:
public class MyTest extends Activity {
private static final String TAG="Tany";
private static final int MAX_ITEM = 50;
private MyArrayAdapter adapter;
private ListView listview;
private int addCounter = 0;
public class MyData implements Comparable<MyData>{
public String str1;
public String str2;
public String str3;
public MyData(String str1, String str2, String str3){
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
}
@Override
public int compareTo(MyData data) {
// TODO Auto-generated method stub
int result = this.str1.compareTo(data.str1);
return result;
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
listview = (ListView)findViewById(R.id.listview);
adapter = new MyArrayAdapter(this, R.layout.layout_row);
//set adapter
listview.setAdapter(adapter);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// TODO Auto-generated method stub
Log.d(TAG, "position "+position+" is clicked");
Toast.makeText(parent.getContext(), adapter.getItem(position).str1+", "+adapter.getItem(position).str2, Toast.LENGTH_SHORT).show();
}
});
listview.setTextFilterEnabled(true);
}
public void onStart(){
super.onStart();
MyTask newTask = new MyTask();
newTask.execute();
}
public class MyTask extends AsyncTask<Void, Void, Void>{
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
for(int i = addCounter; i<MAX_ITEM; i++)
{
adapter.add(new MyData("str1="+i,"str2="+i,"str3="+i));
addCounter++;
publishProgress();
}
return null;
}
@Override
protected void onProgressUpdate(Void... progress ){
adapter.notifyDataSetChanged();
}
@Override
protected void onPostExecute(Void result){
Log.d(TAG, "AsyncTask MyTask finsish its work");
}
}
public class MyArrayAdapter extends ArrayAdapter<MyData>{
public MyArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row;
if(convertView == null){
LayoutInflater inflater = getLayoutInflater();
row = inflater.inflate(R.layout.layout_row, parent, false);
}else{
Log.d(TAG,"recycle view, pos="+position);
row = convertView;
}
TextView tv1 = (TextView) row.findViewById(R.id.textView1);
tv1.setText( ((MyData)getItem(position)).str1 );
TextView tv2 = (TextView) row.findViewById(R.id.textView2);
tv2.setText( ((MyData)getItem(position)).str2 );
TextView tv3 = (TextView) row.findViewById(R.id.textView3);
tv3.setText( ((MyData)getItem(position)).str3 );
return row;
}
}
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/vertical_container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="@string/list_title_start"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TextView>
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</ListView>
<TextView
android:text="@string/list_title_end"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
layout_row.xml:
<?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="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/linearLayout1"
android:orientation="horizontal">
<ImageView
android:layout_height="wrap_content"
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:src="@drawable/ic_launcher">
</ImageView>
<TextView
android:text="TextView1"
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dip"
android:layout_marginTop="6dip"
android:textAppearance="?android:attr/textAppearanceLarge">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="@+id/linearLayout1"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:text="TextView"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall">
</TextView>
<TextView
android:text="TextView"
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_marginLeft="6dip">
</TextView>
</LinearLayout>
</LinearLayout>
Upvotes: 3
Views: 675
Reputation: 25830
as Selvin rightly says You're modifying your Views
from the method doInBackground
which runs on another thread. In android this is forbidden, instead you should modify the views from the onPostExecute
method also.
Upvotes: 1