Связь между TabActivity и встроенной активностью - PullRequest
3 голосов
/ 28 июня 2010

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

В моем TabActivity есть кнопка.Когда кнопка нажата, я хочу, чтобы дочерняя активность, встроенная в эту функцию TabActivity, была обновлена.Я написал код, как показано ниже, и просто удивляюсь, хорошая ли это практика.Спасибо.

MyTabActivity.java

public class MyTabActivity extends TabActivity implements OnClickListener {
    private TabHost m_tabHost;

  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.ff_tab_activity);

    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    m_tabHost = getTabHost(); 
    TabHost.TabSpec spec; 
    Intent intent; 

    intent = new Intent().setClass(this, ChildActivity.class);
    spec = m_tabHost.newTabSpec("Tab 1");
    spec.setContent(intent);
    tabView = (TextView) inflater.inflate(R.layout.tab_indicator, null);
    spec.setIndicator(tabView);
    m_tabHost.addTab(spec);

    m_tabHost.setCurrentTab(0);
    ImageView nextButtonIv = (ImageView) findViewById(R.id.next_button);
    nextButtonIv.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {
    switch (v.getId()) {
    case R.id.next_button:
        synchronized (ChildActivity.class) {
            if (null != ChildActivity.s_childActivity) {
                ChildActivity.s_childActivity.changeUI();
            }
        }
        break;
    }
}

ChildActivity.java

public class ChildActivity extends Activity {
    public static ChildActivity s_childActivity;

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

        synchronized (MatchupsActivity.class) {
            s_childActivity = this;
        }
        setContentView(R.layout.child_activity);
    }

    public void changeUi() {
        code that changes UI
    }

    protected void onDestroy() {
        super.onDestroy();

        synchronized (MatchupsActivity.class) {
            s_childActivity = null;
        }
}

Ответы [ 5 ]

7 голосов
/ 28 сентября 2010

Поскольку TabActivity является ActivityGroup, я бы использовал одно из следующих:

  • getCurrentActivity ()

Возвращает отображаемую активность дочерней вкладки. В вашем случае этот метод вернет используемый экземпляр ChildActivity.

ChildActivity childActivity = (ChildActivity) getCurrentActivity();
  • getLocalActivityManager (). GetActivity (String)

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

ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1");

Я предлагаю переопределить onNewIntent (Intent) в вашем ChildActivity:

Intent intent = new Intent();
intent.putExtra("xyz", "whatever"); // or a serializable

ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1");
childActivity.onNewIntent(intent);

Дайте мне знать, если это работает!

2 голосов
/ 20 мая 2011

Способ выше с

ChildActivity childActivity = (ChildActivity) getLocalActivityManager().getActivity("Tab 1");
childActivity.onNewIntent(intent);

не очень приятно. Вместо непосредственного вызова метода активности (он может быть нулевым !!!) лучше сделать это следующим образом:

Intent intent = new Intent(this, ChildActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(AlbumBrowser.INTENT_EXTRA_FILTER, mediaTitle);
getLocalActivityManager().startActivity("activityIdHere", intent);
2 голосов
/ 28 июня 2010

Кажется, хорошо.Пара замечаний:
- я не вижу причин для синхронизации.
- я бы заменил

ChildActivity.s_childActivity.changeUI();

на

if(ChildActivity.s_childActivity != null){
    ChildActivity.s_childActivity.changeUI();
}

или даже

try{
    ChildActivity.s_childActivity.changeUI();
} catch(Exception e){
    //log
}

для дополнительной параноидальной безопасности.:)

1 голос
/ 20 августа 2011

Вы можете использовать getParent (), чтобы избежать необходимости делать что-либо из этого.

Вот мой дочерний класс запуска с кнопками, которые переключаются между действиями, обрабатываемыми вкладкой:

public class LaunchPadActivity extends Activity implements OnClickListener {

private static final int ICON_PROFILE = 0;

private static final int ICON_SEARCH = 1;

private static final int ICON_MAP = 2;

private static final int FAVOURITES = 3;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.launchpad);

    GridView launchPad = (GridView) findViewById(R.id.launchpad);
    launchPad.setAdapter(new LaunchIconAdapter(this));
}

public class LaunchIconAdapter extends BaseAdapter {
    private Context mContext;

    // references to our images
    private Integer[] mThumbIds = { R.drawable.user, R.drawable.find,
            R.drawable.map, R.drawable.favourites, R.drawable.reviews,
            R.drawable.news, R.drawable.tutorial, R.drawable.info,
            R.drawable.options, };

    public String[] texts = { "Profile", "Search", "Map", "Favourites",
            "Reviews", "News", "Tutorial", "Info", "Options" };

    public LaunchIconAdapter(Context c) {
        mContext = c;
    }

    // Number of thumbs determines number of GridView items
    public int getCount() {
        return mThumbIds.length;
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return 0;
    }

    // create a new ImageView for each item referenced by the Adapter
    public View getView(int position, View convertView, ViewGroup parent) {
        // Icon elements
        LinearLayout launchIcon;
        ImageView launchImage;
        TextView launchText;

        if (convertView == null) {
            launchIcon = (LinearLayout) ((LayoutInflater) mContext
                    .getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(
                    R.layout.launchicon, null);

        } else {
            launchIcon = (LinearLayout) convertView;
        }

        // Add ClickListener with metadata
        launchIcon.setTag(new Integer(position));
        launchIcon.setOnClickListener(LaunchPadActivity.this);

        // Get subviews
        launchImage = (ImageView) launchIcon
                .findViewById(R.id.launch_image);
        launchText = (TextView) launchIcon.findViewById(R.id.launch_text);

        // Configure subviews
        launchImage.setImageResource(mThumbIds[position]);
        launchText.setText(texts[position]);

        return launchIcon;
    }

}

@Override
public void onClick(View v) {
    int position = ((Integer) v.getTag()).intValue();
    switch (position) {
    case ICON_PROFILE:
        Toast.makeText(this, "Profile", Toast.LENGTH_LONG).show();
        break;

    case ICON_SEARCH:
        Toast.makeText(this, "Search", Toast.LENGTH_LONG).show();
        ((TabActivity) getParent()).getTabHost().setCurrentTab(1);
        break;

    case ICON_MAP:
        Toast.makeText(this, "Map", Toast.LENGTH_LONG).show();
        ((TabActivity) getParent()).getTabHost().setCurrentTab(2);
        break;

    case FAVOURITES:
        Toast.makeText(this, "Map", Toast.LENGTH_LONG).show();
        ((TabActivity) getParent()).getTabHost().setCurrentTab(3);
        break;

    }

}

}

Работает как шарм.

1 голос
/ 28 июня 2010

Пара проблем дизайна с этим, но в целом это кажется разумным.

Я бы отказался от статического экземпляра в классе ChildActivity. Зачем? Ну, подумай об отношениях, которые ты моделируешь. A TabActivity имеет ChildActivity. Это составление учебника, и оно будет достигнуто путем добавления поля ChildActivity в класс TabActivity, например:

 public class TabActivity {

    private ChildActivity child;

    //remember to initialize child in onCreate

    //then, call methods using child.changeUI();, for example

} 

Это лучше, потому что A) теперь у меня может быть несколько экземпляров TabActivity и ChildActivity, которые не будут мешать друг другу (раньше это была просто статическая переменная, поэтому можно было использовать только одну ChildActivity), и B) ChildActivity инкапсулируется внутри класса TabActivity ... раньше это было открытое поле, означающее, что все могут использовать и изменять его (может быть нежелательно; часто это может привести к некоторым странным ошибкам во время выполнения, а также к грязному, связанному коду) - мы изменили его на приватное поле, потому что на самом деле мы не хотим, чтобы другие классы обращались к нему неожиданным образом.

Единственное, к чему вам может понадобиться доступ от ChildActivity - это родитель (TabActivity). Для этого добавьте следующие методы и поле в класс ChildActivity и вызовите метод registerParent () после создания ChildActivity:

public class ChildActivity ...{

private TabActivity parent;

public void registerParent(TabActivity newParent){
    if (newParent != null){
        parent = newParent;
    }
}
}

Итак, если вам нужен доступ к родительскому элементу TabActivity от дочернего элемента, просто вызовите parent.someMethod ();

Было бы также разумно обращаться к таким полям, как parent и child через геттеры и сеттеры; это может сэкономить вам время в долгосрочной перспективе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...