Переход между Activity в ActivityGroup(в табах)?

При переходе между активити(используется ActivityGroup в табах) возникает ошибка:
04-26 08:46:04.599: ERROR/AndroidRuntime(992): java.lang.StackOverflowError<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.text.Layout.measureText(Layout.java:1601)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.text.Layout.getLineMax(Layout.java:655)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.text.Layout.draw(Layout.java:311)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.text.BoringLayout.draw(BoringLayout.java:365)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.widget.TextView.onDraw(TextView.java:4052)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.view.View.draw(View.java:6535)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.view.ViewGroup.drawChild(ViewGroup.java:1531)<br/>
04-26 08:46:04.599: ERROR/AndroidRuntime(992): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)<br/>
 ...<br/>



код:
...<br/>
private ListView _lv;<br/>
...<br/>
@Override<br/>
 public void onCreate(Bundle savedInstanceState) {<br/>
 super.onCreate(savedInstanceState);<br/>
 ...<br/>
 List cats = Category.getAllCategories(this);<br/>
 _lv = (ListView)findViewById(android.R.id.list);<br/>
 _lv.setAdapter(new CategoryAdapter(getBaseContext(),R.layout.list_item_layout, cats)); <br/>
 _lv.setOnItemClickListener(new ListClickListener());<br/>
 ...<br/>
}<br/>
public void replaceContentView(String id, Intent newIntent/*,int result*/) {<br/>
 View view = getLocalActivityManager().startActivity(id,newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)) <br/>
 .getDecorView(); <br/>
 this.setContentView(view);<br/>
 } <br/>
<br/>
<br/>
Нужный кусок взят отсюда: <a href="http://www.gamma-point.com/content/android-how-have-multiple-activities-under-single-tab-tabactivity">www.gamma-point.com/content/android-how-have-multiple-activities-under-single-tab-tabactivity</a><br/>
<br/>
Код лэйаутов:<br/>
<code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;<br/>
&lt;LinearLayout<br/>
 xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;<br/>
 android:id=&quot;@+id/recipes_in_cat_list&quot;<br/>
 android:orientation=&quot;vertical&quot;<br/>
 android:layout_width=&quot;fill_parent&quot;<br/>
 android:layout_height=&quot;fill_parent&quot;&gt;<br/>
 &lt;LinearLayout<br/>
 android:layout_width=&quot;fill_parent&quot;<br/>
 android:layout_height=&quot;wrap_content&quot;<br/>
 android:gravity=&quot;left&quot; <br/>
 android:background=&quot;@drawable/tab_upper_bar&quot;&gt;<br/>
 &lt;Button<br/>
 android:id=&quot;@+id/back_to_cats_button&quot;<br/>
 android:layout_width=&quot;wrap_content&quot;<br/>
 android:layout_height=&quot;wrap_content&quot;<br/>
 android:layout_marginLeft=&quot;5dip&quot;<br/>
 android:background=&quot;@drawable/android_info_button&quot; /&gt;<br/>
 </code><br/>
 &lt;ListView<br/>
 android:id=&quot;@android:id/list&quot;<br/>
 android:layout_width=&quot;fill_parent&quot;<br/>
 android:layout_height=&quot;fill_parent&quot;<br/>
 android:gravity=&quot;center&quot;<br/>
 android:divider = &quot;#00000000&quot;<br/>
 android:cacheColorHint=&quot;#00000000&quot; /&gt;<br/>



и лэйаут для списка:


<?xml version=«1.0» encoding=«utf-8»?>

<LinearLayout

xmlns:android=«schemas.android.com/apk/res/android»

android:orientation=«horizontal»

android:layout_width=«fill_parent»

android:layout_height=«40dip»

android:layout_weight=«1»

android:padding = «10dip»

android:background ="@drawable/list_item_bg"

android:layout_centerHorizontal=«true»>

<ImageView

android:id="@+id/recipe_list_left"

android:layout_width=«wrap_content»

android:layout_height=«fill_parent»

android:src="@drawable/list_left"

android:layout_weight=«0» />

<TextView

android:id="@+id/recipe_list_text"

android:layout_width=«fill_parent»

android:layout_height=«fill_parent»

style = "@style/RecipeListText"

android:layout_weight=«1»

android:gravity=«center_horizontal» />

<ImageView

android:id="@+id/recipe_list_right"

android:layout_width=«wrap_content»

android:layout_height=«fill_parent»

android:src="@drawable/list_right"

android:layout_weight=«0» />




Из-за чего может возникнуть такая ошибка и в какую сторону копать?

Слишком большая вложенность вью?
  • Вопрос задан
  • 3552 просмотра
Пригласить эксперта
Ответы на вопрос 3
Assoulter
@Assoulter
В общем-то, я имел ввиду, выложить архив проекта, если он не секретный, куда-нибудь для скачивания, или на github какой-нибудь :) Разбираться в отрывках кода для поиска того, что вызывает переполнение стека, без отладки и чтения логов, тяжело. Но все же есть несколько замечаний:

  1. использование вложенных LinearLayout в большом количестве вместо RelativeLayout дорого обходится для памяти и производительности. При достижении определенного числа узлов в иерархии Views возможно переполнение стека. Особенно актуально для версий 1.5-1.6. Следует избавляться от LinearLayout и оптимизировать шаблоны, как я писал выше.
  2. немного не понял, зачем вы используете destroyDrawingCache. Почитайте про ускорение работы listview с помощью паттерна ViewHolder тут или тут
  3. не понятна причина вызова контекста с помощью getBaseContext(). Activity уже имеет контекст, достаточно использовать this.
  4. к проблеме не относится, но все же. Обработчики событий, чтобы не городить лишний код и улучшить читабельность, можно внести в анонимные функции, например
    _btBack.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v){
    //блаблабла
    }
    });
Ответ написан
Assoulter
@Assoulter
Увы, из приведенного кода мало что понятно. Пример с сайта работает на ура, значит, проблема у вас. Возможно, использование слишком большого количества LinearLayout вместо RelativeLayout, вкупе с отсутствием кеширования ваших View в методе getView адаптера CategoryAdapter (я не вижу, как он у вас реализован), приводит к переполнению стека. Либо попробуйте провести оптимизацию ваших шаблонов, либо выложите куда-нибудь более полную версию проекта для дальнейшей помощи.
Ответ написан
Pyjamec
@Pyjamec Автор вопроса
Обещанный код:
CategoryAdapter полностью:
public class CategoryAdapter extends ArrayAdapter {

private List _items;

public CategoryAdapter(Context context, int textViewResourceId,
List items) {
super(context, textViewResourceId, items);
_items = items;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.list_item_layout, null);
v.destroyDrawingCache();
}

Category cat = _items.get(position);
if (cat != null) {
TextView listText = (TextView) v.findViewById(R.id.list_text);
listText.setText(cat.getName());
}
return v;
}

@Override
public Category getItem(int position) {
return _items.get(position);
}
}

Отсюда(таб) мы начинаем переход:
public class RecipeTab extends ActivityGroup {

private ListView _lv;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

setContentView(R.layout.recipe_tab);

List cats = Category.getAllCategories(this);
_lv = (ListView)findViewById(android.R.id.list);
_lv.setAdapter(new CategoryAdapter(getBaseContext(),R.layout.list_item_layout, cats));
_lv.setOnItemClickListener(new ListClickListener());
}

public void replaceContentView(String id, Intent newIntent/*,int result*/) {
View view = getLocalActivityManager().startActivity(id,newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
.getDecorView();
this.setContentView(view);
}
...


код обработчика при нажатии на элемент списка:

private class ListClickListener implements ListView.OnItemClickListener {

public void onItemClick(AdapterView parent, View v, int position, long l){
Category selectedItem = (Category)_lv.getItemAtPosition(position);
int catId = selectedItem.getId();
Intent intent = new Intent(RecipeTab.this,CategoryActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("catId", catId);
intent.putExtras(bundle);
replaceContentView("categoryActivity", intent);
}
}
...
}

В данный активити мы переходим и потом обратно на RecipeTab
public class CategoryActivity extends Activity{

private ListView _lv;
private Button _btBack;
private LocalActivityManager lam;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

setContentView(R.layout.category_activity_layout);
_btBack = (Button)findViewById(R.id.back_to_cats_button);
_btBack.setOnClickListener(new BackButtonListener());

List recps = Recipe.getRecipesByCatId(this, catId);

_lv = (ListView)findViewById(android.R.id.list);
_lv.setAdapter(new RecipeAdapter(getBaseContext(),R.layout.recipe_list_item, recps));
}

и код обработчика:
class BackButtonListener implements View.OnClickListener {
public void onClick(View v){
Intent intent = new Intent(v.getContext(), RecipeTab.class);
RecipeTab parentActivity = (RecipeTab)getParent();
parentActivity.replaceContentView("recipeTab", intent);
}
}

Код лэйаутов для CategoryAcivity и элемента списка находится в вопросе выше.
По-моему, много букв получилось, так что остальное по требованию.
Кстать, кнопка назад в эмуляторе почему-то переходит не на предидущий активити, а на рабочий стол.
Почему так?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы