ANR, когда я нажимаю на элемент списка в listView

Я использую пользовательский listView и ArrayAdapter, который реализует sectionIndexer. Я использую Json для анализа данных с моего сервера. Я могу отобразить данные в listView, но когда я нажимаю на свой listView, он должен перейти к следующей подробной странице, но на данный момент он не работает.

Вот код

    public class CustomListView extends ListView {


private Context ctx;

private static int indWidth = 20;
private String[] sections;
private float scaledWidth;
private float sx;
private int indexSize;
private String section;
private boolean showLetter = true;
private Handler listHandler;

public CustomListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    ctx = context;
}
public CustomListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    ctx = context;

}

public CustomListView(Context context, String keyList) {
    super(context);
    ctx = context;

}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    scaledWidth = indWidth * getSizeInPixel(ctx);
    sx = this.getWidth() - this.getPaddingRight() - scaledWidth;

    Paint p = new Paint();
    p.setColor(Color.WHITE);
    p.setAlpha(100);

    canvas.drawRect(sx, this.getPaddingTop(), sx + scaledWidth,
            this.getHeight() - this.getPaddingBottom(), p);

    indexSize = (this.getHeight() - this.getPaddingTop() - getPaddingBottom())
            / sections.length;

    Paint textPaint = new Paint();
    textPaint.setColor(Color.DKGRAY);
    textPaint.setTextSize(scaledWidth / 2);

    for (int i = 0; i < sections.length; i++)
        canvas.drawText(sections[i].toUpperCase(),
                sx + textPaint.getTextSize() / 2, getPaddingTop()
                        + indexSize * (i + 1), textPaint);

    // We draw the letter in the middle
    if (showLetter & section != null && !section.equals("")) {

        Paint textPaint2 = new Paint();         
        textPaint2.setColor(Color.DKGRAY);
        textPaint2.setTextSize(2 * indWidth);

        canvas.drawText(section.toUpperCase(), getWidth() / 2,  getHeight() / 2, textPaint2);
    }
}
private static float getSizeInPixel(Context ctx) {
    return ctx.getResources().getDisplayMetrics().density;
}
@Override
public void setAdapter(ListAdapter adapter) {
    super.setAdapter(adapter);
    if (adapter instanceof SectionIndexer)
        sections = (String[]) ((SectionIndexer) adapter).getSections();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x = event.getX();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
        if (x < sx)
            return super.onTouchEvent(event);
        else {
            // We touched the index bar
            float y = event.getY() - this.getPaddingTop() - getPaddingBottom();
            int currentPosition = (int) Math.floor(y / indexSize);

            section = sections[currentPosition];
            this.setSelection(((SectionIndexer) getAdapter())
                    .getPositionForSection(currentPosition));
        }
        break;
    }
    case MotionEvent.ACTION_MOVE: {
        if (x < sx)
            return super.onTouchEvent(event);
        else {
            float y = event.getY();
            int currentPosition = (int) Math.floor(y / indexSize);
            section = sections[currentPosition];
            this.setSelection(((SectionIndexer) getAdapter())
                    .getPositionForSection(currentPosition));

        }
        break;

    }
    case MotionEvent.ACTION_UP: {

        listHandler = new ListHandler();
        listHandler.sendEmptyMessageDelayed(0, 30 * 1000);

        break;
    }
  }
    return true;
}


private class ListHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {            
        super.handleMessage(msg);           
        showLetter = false;
        //CustomListView.this.invalidate();
    }


}
}

Из этого класса я создаю просмотр списка в xml, активность

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context=".MainActivity" >

  <SearchView
    android:id="@+id/searchView1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" >
  </SearchView>

  <com.deiontech.masjidtimetableapp.CustomListView 
    android:id="@+id/listViewformasjid"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true" 
    android:layout_below="@+id/searchView1"
    android:clickable="true"/>
  </RelativeLayout>

Это xml для каждой строки в listView

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="3dp"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
    android:id="@+id/textView_name"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true"
    android:focusable="false"
    android:text="t1" />

<TextView
    android:id="@+id/textView_country"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/textView_name"
    android:layout_below="@+id/textView_name"
    android:layout_marginTop="19dp"
    android:focusable="false"
    android:text="t2" />

<TextView
    android:id="@+id/textView_localarea"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/textView_country"
    android:layout_below="@+id/textView_country"
    android:layout_marginTop="15dp"
    android:focusable="false"
    android:text="t3" />

</RelativeLayout>

Это мой класс адаптера массива

public class SelectMasjidAdapter extends ArrayAdapter< MasjidForListClass> implements
 SectionIndexer{

private List< MasjidForListClass> itemList;
private Context context;
private static String sections = "abcdefghilmnopqrstuvz";

ArrayList< MasjidForListClass> data;

public SelectMasjidAdapter(List< MasjidForListClass> itemList, Context ctx) {
    super(ctx,R.layout.select_masjid_list_row, itemList);
    this.itemList = itemList;
    this.context = ctx;     
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return itemList.size();
}

@Override
public MasjidForListClass getItem(int position) {
    // TODO Auto-generated method stub
    return super.getItem(position);
}

@Override
public long getItemId(int arg0) {
    return itemList.get(arg0).hashCode();

}

@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
    LayoutInflater inflater = (LayoutInflater)    
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View vi=arg1;
    if(arg1==null)

        vi = inflater.inflate(R.layout.select_masjid_list_row, null);

    TextView masjid_name_text = (TextView)vi.findViewById(R.id.textView_name); 
    TextView masjid_country_text = (TextView)vi.findViewById(R.id.textView_country); 
    TextView masjid_localarea_text = 
   (TextView)vi.findViewById(R.id.textView_localarea); 



    MasjidForListClass m = itemList.get(arg0);

    masjid_name_text.setText(m.getMasjidname());
    masjid_country_text.setText(m.getMasjidcountry());
    masjid_localarea_text.setText(m.getMasjidlocalarea());

    return vi;
}
@Override
public int getPositionForSection(int sectionIndex) {
    Log.d("ListView", "Get position for section");
    for (int i=0; i < this.getCount(); i++) {
        String item = this.getItem(i).getMasjidname().toLowerCase();
        if (item.charAt(0) == sections.charAt(sectionIndex))
            return i;
    }
    return 0;
}
@Override
public int getSectionForPosition(int position) {
    Log.d("ListView", "Get section");
    return 0;
}
@Override
public Object[] getSections() {
    Log.d("ListView", "Get sections");
    String[] sectionsArr = new String[sections.length()];
    for (int i=0; i < sections.length(); i++)
        sectionsArr[i] = "" + sections.charAt(i);

    return sectionsArr;
}

}

И это мой класс деятельности

public class SelectMasjid extends Activity{

SelectMasjidAdapter adapter;
ListView masjidListView;
 List <MasjidForListClass> masjidnames;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.select_masjid_activity);
    GetJsonList l = new GetJsonList();
    masjidnames = l.getlistOfMasjids();


    Collections.sort(masjidnames, new Comparator<MasjidForListClass>() {
        public int compare(MasjidForListClass result1, MasjidForListClass 
 result2) {
            return result1.getMasjidname().compareTo(result2.getMasjidname());
        }
    });

    masjidListView = (ListView)findViewById(R.id.listViewformasjid);
    adapter = new SelectMasjidAdapter(masjidnames,this);
    masjidListView.setAdapter(adapter);


    masjidListView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {

            Intent i = new Intent(SelectMasjid.this, 
 MasjidDetailedActivity.class);
            i.putParcelableArrayListExtra("selected", (ArrayList<? 
extends Parcelable>) masjidnames);
            i.putExtra("index", arg2);
            startActivity(i);
        }



    });


}
}

Я не получаю никаких сведений об ошибке в logcat или приложение неожиданно не закрывается, поэтому я не могу решить эту проблему

Пожалуйста, помогите мне с этим, спасибо заранее.

3 ответа

Решение

ANR происходит потому, что вы выполняете длинную задачу в главном потоке SelectMasjid деятельность. GetJsonList код должен быть перемещен в асинхронной задаче.

Вот документация AsyncTask

Для настраиваемого listView полезно использовать AsyncTask при получении данных с сервера в виде:

/**
 * Background Async Task to Load all product by making HTTP Request
 * */
class LoadAllItems extends AsyncTask<String, String, String> {
    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(YourActivityName.this);
        pDialog.setMessage("Loading Items. Please wait...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * getting All products from url
     * */
    protected String doInBackground(String... args) {
        //your method that get data from server which getlistOfMasjids() 
        //Then save them in arrays or ArrayList, after that you can save them in listview 
                  return null;                    
    }

    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) {
        // dismiss the dialog after getting all products
        listview();
        pDialog.dismiss();
    }
}

Как вы отметили в методе doInBackground, вы можете использовать вашу функцию getlistOfMasjids(), после этого вы можете сохранить данные в массивах или Arraylist, чтобы поместить их в просмотр списка.

для списка в методе onPostExecute() это выглядит так:

public void listview(){
    adapter =new SelectMasjidAdapter(this, array1, array2,array3);
    lv.setAdapter(adapter);
}

для списка просмотра списка действий:

lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            showInfo(position); // here you can put the call for another class or details  item for specific position

        }
    }); 

Надеюсь, что это будет полезно,

Android выложил очень хорошую документацию по ANR и тому, как заставить приложение реагировать... Я часто ссылаюсь на этот документ, когда нажимаю ANR.

http://developer.android.com/training/articles/perf-anr.html

Я установил правило для себя, так как оставить поток пользовательского интерфейса только для обработки пользовательского интерфейса, дБ, IO, сети должны быть выполнены на потоке, не являющемся пользовательским интерфейсом... Я использую поток и обработчики... Тем не менее, иногда необходимо создать поток пользовательского интерфейса подождите, в этом случае у вас нет выбора, но по возможности избегайте такой ситуации...

Вы также можете использовать метод runOnUiThread для обновления пользовательского интерфейса из других не-пользовательских потоков...

Другие вопросы по тегам