Ich versuche, diese einfache App zu bekommen, um vergeblich zu arbeiten.Android-Fragment tablayout Aktualisierung von ListView-Problemen
Diese Aktivität soll eine Reihe von Tabs anzeigen, die Staffeln einer Serie enthalten. Die erste Registerkarte enthält ihre Beschreibung und die nächsten enthalten ihre Episoden in ListRows.
Jede Episodenzeile kann angeklickt werden, um einen booleschen Wert in der Datenbank umzuschalten. Wenn true bedeutet, hat der Benutzer diese Episode beobachtet, die ein Symbol rechts in der Zeile in der ListView ändert. Wird beobachtet und ein Symbol ändert sich in der Reihe. Ich habe Probleme beim Aktualisieren der ListViews. Für die erste Saison-Registerkarte funktioniert es perfekt, Sie klicken auf eine Zeile und das Symbol ändert sich. Aber wenn ich auf einen Tab rechts von dem aktuellen gehe, werden die Dinge ausgeflippt, das Icon wird nicht aktualisiert (obwohl der Wert in der Datenbank aktualisiert wird) und wenn ich jetzt zu einem anderen Tab wische, wird dieser den Wert halten Der letzte und das Symbol haben den richtigen Wert.
Ich bin verloren so
Die Aktivität:
class ListEpisodes extends ListAbstract {
private long seriesId; // Identifier of current Series
private String seriesTitle; // Title of current Series
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a {@link FragmentPagerAdapter}
* derivative, which will keep every loaded fragment in memory.
* If this becomes too memory intensive, it may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SeasonPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_episodes);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
try {
seriesId = (Long) this.getIntent().getExtras().get("sid");
} catch (NullPointerException e) {
seriesId = 0;
}
mDbAdapter = new DbAdapter(this);
mDbAdapter.open();
list();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_list_episodes, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
switch (item.getItemId()) {
case R.id.create_new_episode:
create();
return true;
case R.id.edit_series:
editSeries();
return true;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume() {
super.onResume();
mViewPager.getAdapter().notifyDataSetChanged();
}
/////////////////////////////////////// ListAbstract ///////////////////////////////////////
/**
* Fetches and shows all episodes from the database.
*/
protected void list() {
Cursor series = mDbAdapter.fetchSeries(seriesId);
seriesTitle = series.getString(series.getColumnIndexOrThrow(DbAdapter.SERIES_KEY_TITLE));
getSupportActionBar().setTitle(seriesTitle);
Cursor eCursor = mDbAdapter.getSeasons(seriesId);
ArrayList<Integer> seasons = new ArrayList<>();
eCursor.moveToFirst();
for (int i = 0; i < eCursor.getCount(); i++) {
seasons.add(eCursor.getInt(eCursor.getColumnIndex(DbAdapter.EPISODE_KEY_SEASON_NUM)));
eCursor.moveToNext();
}
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SeasonPagerAdapter(getSupportFragmentManager(),
seasons, seriesId);
mSectionsPagerAdapter.notifyDataSetChanged();
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
}
/**
* Starts an activity to create a new episode.
*/
protected void create() {
Intent i = new Intent(this, EditEpisodes.class);
i.putExtra(DbAdapter.EPISODE_KEY_ID, Long.valueOf(0));
i.putExtra(DbAdapter.EPISODE_KEY_SERIES, seriesId);
startActivityForResult(i, ACTIVITY_CREATE);
}
/**
* Starts an activity to edit an episode.
*
* @param elementId id of the episode that will be edited.
*/
protected void edit(long elementId) {
Intent i = new Intent(this, EditEpisodes.class);
i.putExtra(DbAdapter.EPISODE_KEY_SERIES, seriesId);
i.putExtra(DbAdapter.EPISODE_KEY_ID, elementId);
startActivityForResult(i, ACTIVITY_EDIT);
}
/**
* Deletes the episode elementId.
*
* @param elementId id of the episode that will be deleted.
*/
protected void delete(long elementId) {
// Episodes are refreshed if the current episode has been correctly deleted.
if (mDbAdapter.deleteEpisode(elementId)) {
list();
}
}
/**
* Starts an activity to edit the current series (with identifier [seriesId]).
*/
protected void editSeries() {
Intent i = new Intent(this, EditSeries.class);
i.putExtra(DbAdapter.SERIES_KEY_ID, seriesId);
startActivityForResult(i, ACTIVITY_EDIT);
}
////////////////////////////////////////////////////////////////////////////////////////////
/**
* Fragment containing all episodes that correspond to the same season of a given
* series.
*/
public static class SeasonFragment extends Fragment {
/**
* These arguments can only be passed via bundle. They match to season number and series Id.
*/
private static final String ARG_TAB_NUMBER = "section_number";
private static final String ARG_SERIES_ID = "series_id";
private static final String ARG_SEASONS_ARRAY = "seasons_array";
private ArrayList<Integer> seasons;
private int season = -1;
private int tab = -1;
public SeasonFragment() {
}
/**
* Returns a new instance of this fragment for the given season.
*/
protected static SeasonFragment newInstance(ArrayList<Integer> seasons, int tabNumber,
long seriesId) {
SeasonFragment fragment = new SeasonFragment();
Bundle args = new Bundle();
args.putIntegerArrayList(ARG_SEASONS_ARRAY, seasons);
args.putInt(ARG_TAB_NUMBER, tabNumber);
args.putLong(ARG_SERIES_ID, seriesId);
fragment.setArguments(args);
return fragment;
}
/**
* Fetches and shows all episodes on this fragment
*
* @param inflater to instantiate the season view
* @param container to match the tabs (internal to android)
* @param savedInstanceState argument container, since this class' constructor can't have
* parameters
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
DbAdapter mDbAdapter = new DbAdapter(this.getActivity());
mDbAdapter.open();
tab = getArguments().getInt(ARG_TAB_NUMBER);
long series = getArguments().getLong(ARG_SERIES_ID);
if (tab == 0) {
View rootView = inflater.inflate(R.layout.fragment_description, container, false);
Cursor descriptionCursor = mDbAdapter.fetchSeries(series);
//getActivity().startManagingCursor(descriptionCursor);
String description = descriptionCursor.getString(
descriptionCursor.getColumnIndexOrThrow(DbAdapter.SERIES_KEY_DESCRIPTION));
((TextView) rootView.findViewById(R.id.description)).setText(description);
return rootView;
} else {
seasons = getArguments().getIntegerArrayList(ARG_SEASONS_ARRAY);
assert seasons != null;
season = seasons.get(tab - 1);
View rootView = inflater.inflate(R.layout.fragment_list_episodes, container, false);
// Get seriesId and fetch episodes for the season.
Cursor episodes = mDbAdapter.fetchEpisodesFromSeason(getArguments().getLong(ARG_SERIES_ID),
season);
//getActivity().startManagingCursor(episodes);
EpisodeListViewAdapter adapter = new EpisodeListViewAdapter(this.getContext(), R.layout.episode_row, episodes, 0);
ListView episodeList = (ListView) rootView.findViewById(R.id.episode_list);
episodeList.setAdapter(adapter);
registerForContextMenu(episodeList);
episodeList.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
toggleWatched(id);
}
});
return rootView;
}
}
private void toggleWatched(long episodeId) {
DbAdapter mDbAdapter = new DbAdapter(this.getActivity());
mDbAdapter.open();
mDbAdapter.toggleWatched(episodeId);
// Get seriesId and fetch episodes for the season.
Cursor episodes = mDbAdapter.fetchEpisodesFromSeason(getArguments().getLong(ARG_SERIES_ID),
season);
ListView episodeList = (ListView) this.getActivity().findViewById(R.id.episode_list);
EpisodeListViewAdapter lva = ((EpisodeListViewAdapter) episodeList.getAdapter());
// Sometimes this works sometimes it doesn't
lva.swapCursor(episodes);
lva.notifyDataSetChanged();
episodeList.setAdapter(lva);
}
/**
* Method that creates an options menu when a user clicks and holds on a series.
*/
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.clear();
menu.add(Menu.NONE, EDIT_ID, Menu.NONE, R.string.edit_episode);
menu.add(Menu.NONE, DELETE_ID, Menu.NONE, R.string.delete_episode);
}
/**
* Method called when a ContextMenu option is selected.
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
int i = item.getItemId();
if (i == DELETE_ID) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
((ListAbstract) getActivity()).delete(info.id);
return true;
} else if (i == EDIT_ID) {
AdapterView.AdapterContextMenuInfo info =
(AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
((ListAbstract) getActivity()).edit(info.id);
return true;
}
return super.onContextItemSelected(item);
}
/**
* Adapter class specific to populate the listView in ListSeries from a cursor.
*/
static class EpisodeListViewAdapter extends ResourceCursorAdapter {
public EpisodeListViewAdapter(Context context, int layout, Cursor c, int flags) {
super(context, layout, c, flags);
}
@Override
public void changeCursor(Cursor cursor){
super.changeCursor(cursor);
}
/**
* Will be automatically called by android to populate the list view.
* To do that it extracts the information from the cursor and transforms it to
* something usable in the case of the rating images.
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView numberView = (TextView) view.findViewById(R.id.episode_number);
String episode_number = cursor.getString(cursor.getColumnIndex(DbAdapter.EPISODE_KEY_EPISODE_NUM));
numberView.setText(episode_number);
TextView nameView = (TextView) view.findViewById(R.id.episode_name);
String episode_name = cursor.getString(cursor.getColumnIndex(DbAdapter.EPISODE_KEY_NAME));
if (episode_name.length() > 17) {
try{
int cut = episode_name.indexOf(" ", 5);
episode_name = episode_name.substring(0, cut) + "\n" + episode_name.substring(cut + 1);
}catch(Exception e){
episode_name = episode_name.substring(0,10)+"...";
}
}
nameView.setText(episode_name);
ImageView image = (ImageView) view.findViewById(R.id.episode_watched);
String wasWatched = cursor.getString(cursor.getColumnIndexOrThrow(DbAdapter.EPISODE_KEY_WATCHED));
wasWatched = wasWatched == null ? "0" : wasWatched;
int watched_img = 0;
switch (wasWatched) {
case ("0"):
watched_img = R.drawable.unwatched;
break;
case ("1"):
watched_img = R.drawable.watched;
break;
}
image.setImageResource(watched_img);
}
}
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the seasons.
*/
protected class SeasonPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Integer> seasons; // Holds all the seasons for the series
private long seriesId; // Id of the series
public SeasonPagerAdapter(FragmentManager fm, ArrayList<Integer> seasons, long seriesId) {
super(fm);
this.seasons = seasons;
this.seriesId = seriesId;
}
@Override
public Fragment getItem(int seasonNum) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
return SeasonFragment.newInstance(seasons, seasonNum, seriesId);
}
/**
* Forces all fragments to reload on update
*/
@Override
public int getItemPosition(Object object) {
// There are more efficient implementations.
return POSITION_NONE;
}
/**
* @return amount of tabs in the view.
*/
public int getCount() {
// Since the description is in the first tab the count is one more
// than the number of seasons
return seasons.size() + 1;
}
@Override
public CharSequence getPageTitle(int position) {
// The first tab holds the description
if (position == 0) return "Description";
else {
// The title contains the number of the season for the tab
int season = seasons.get(position - 1);
if (season >= 10) return "S" + season;
else return "S0" + season;
}
}
}
}
Die Tätigkeit des Layouts:
<LinearLayout
android:id="@+id/test"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
app:tabMode="scrollable"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout>
(Inhalt Layout)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
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"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".activities.ListEpisodes"
tools:showIn="@layout/activity_list_episodes">
<LinearLayout
android:orientation="vertical"
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text=""
android:id="@+id/series_title" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text=""
android:id="@+id/series_description" />
</LinearLayout>
</RelativeLayout>
eine einzelne Zeile Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/EDot"
android:textSize="25sp" />
<TextView
android:id="@+id/episode_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/space"
android:textSize="25sp" />
<TextView
android:id="@+id/episode_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp" />
</LinearLayout>
<ImageView
android:id="@+id/episode_watched"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
Ich habe versucht, in SeasonFragment toggleWatched viele Dinge, die in dem Verfahren zu ändern, die am Ende auf dem EpisodeListViewAdapter die Methode Bindview android nennen machen (tatsächlich, ich habe überprüft, dass die Methode für eine bestimmte Episode mehrmals aufgerufen wird), aber die Ansicht wird nicht aktualisiert. Vielleicht stimmt etwas nicht mit der Art und Weise, wie der Adapter wählt, welche Registerkarte welche Daten enthält? Aber warum sollte es in einigen Fällen funktionieren?