i am using a view pager, with actionbar.
this action bar contains 3 tabs.
one of them is players, i called it like this:
#Override
public Fragment getItem(int arg0) {
switch (arg0) {
case 0:
return new TeamInformation();
case 1:
return new TeamPlayers();
default:
return new TeamInformation();
}
}
and the TeamPlayers class is :
public class TeamPlayers extends Fragment {
private ListView lv_players;
private TeamPlayersAdapter adapter;
private List<Player> players = new LinkedList<Player>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.team_players, container, false);
lv_players = (ListView) v.findViewById(R.id.lv_players);
adapter = new TeamPlayersAdapter(this.getActivity(), players);
lv_players.setAdapter(adapter);
new getTeamPlayers().execute(1);
return v;
}
when i call this screen, i got nothing, i mean not any data show, although, if you notice i call the getTeamPlayers which is:
private class getTeamPlayers extends
AsyncTask<Integer, Integer, List<Player>> {
#Override
protected List<Player> doInBackground(Integer... params) {
List<Player> players = new LinkedList<Player>();
Player player = new Player();
player.setID(1);
player.setEn_name("Totti");
players.add(player);
player = new Player();
player.setID(2);
player.setEn_name("De Rossi");
players.add(player);
return players;
}
#Override
protected void onPostExecute(List<Player> result) {
super.onPostExecute(result);
players = new LinkedList<Player>();
players.addAll(result);
adapter.notifyDataSetChanged();
}
}
see i put data in it. i make a log to check if the application called the onCreateView and i can see the log.
help appreciated
Set adapter when the list is loaded means on postExecute
#Override
protected void onPostExecute(List<Player> result) {
super.onPostExecute(result);
players = new LinkedList<Player>();
players.addAll(result);
adapter = new TeamPlayersAdapter(this.getActivity(), players);
lv_players.setAdapter(adapter);
}
this may help you... no need to set the Adapter to ListView multiple times...
#Override
protected void onPostExecute(List<Player> result) {
if(result != null) {
players.clear();
players.addAll(result);
adapter.notifyDataSetChanged();
}
}
Related
The title might be a little confusing so I hope that I can express my problem correctly. So I'm working on a simple workout log app. I have fragment ActiveWorkout as in Image 1. When I press the pink add button I am directed to another fragment, which contains different exercises as a List, which is shown in Image 2. Then I am to select an exercise(with the onItemClickListener) and the title of that exercise should be sent back to the ActiveWorkoutFragment and added to the Active Workout, so it should be like Image 3. So the problem here is, I don't exactly know how to keep my Active Workout 'alive', it should be updated if I want to add another exercise and not be blank when I press the pink add button again, so in the end it should be something like in Image 4. I was thinking about sending data with a Bundle, which I also tried in the code but the more difficult part is updating the Workout list without deleting the previous added exercises. Btw the reason I am trying to do something like this is because the data is actually in Firebase Database, so in a sense I'm trying to retrieve data from the Workout database.
Images:
Image 1 Image 2 Image 3 Image 4
This is the Exercise List or the Catalog:
public class ExercisesFragment extends Fragment {
private ListView lv;
private FirebaseListAdapter adapter;
private ArrayList<Exercise> exerciseList;
private ArrayList<String> nameList;
//private Adapter adapter;
public ExercisesFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_exercises, container, false);
lv = v.findViewById(R.id.lv);
Query query = FirebaseDatabase.getInstance().getReference().child("exerciseList");
FirebaseListOptions<ExerciseElement> options = new FirebaseListOptions.Builder<ExerciseElement>()
.setLayout(R.layout.exercise)
.setQuery(query, ExerciseElement.class)
.build();
adapter = new FirebaseListAdapter(options) {
#Override
protected void populateView(#NonNull View v, #NonNull Object model, int position) {
TextView bodypart = v.findViewById(R.id.bodypart);
TextView title = v.findViewById(R.id.title);
ExerciseElement el = (ExerciseElement) model;
bodypart.setText(el.getBodypart().toString());
title.setText(el.getTitle().toString());
}
};
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ExerciseElement el = (ExerciseElement) lv.getItemAtPosition(position);
String item = el.getTitle();
ActiveWorkoutFragment awf = new ActiveWorkoutFragment();
Bundle args = new Bundle();
args.putString("ExerciseTitle", item);
awf.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.nav_host_fragment, awf).commit();
//Navigation.findNavController(v).navigate(R.id.activeWorkoutFragment);
}
});
return v;
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
Then there is the ActiveWorkoutFragment, which is a little longer but the upper part is not the concern. The addNewExercise() method is being called when I click on the pink add button, so I was trying to retrieve the data somehow there.
public class ActiveWorkoutFragment extends Fragment {
private Workout workout;
private TextView emptyRecyclerView;
private RecyclerView exerciseRecyclerView;
private ExerciseRecyclerViewAdapter adapter;
private WorkoutHistory workoutHistory;
private FloatingActionButton fab;
private FirebaseAuth mAuth;
private DatabaseReference databaseWorkouts;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_active_workout, container, false);
fab = v.findViewById(R.id.fab);
fab.setOnClickListener(this::addNewExercise);
setHasOptionsMenu(true);
workout = new Workout("WORKOUT");
if(savedInstanceState != null) {
workout = savedInstanceState.getParcelable("key");
}
emptyRecyclerView = v.findViewById(R.id.empty_recycler_view);
//buildRecyclerView(workout);
exerciseRecyclerView = v.findViewById(R.id.recycler_view_exercise);
// improves performance if size of RecyclerView content is fixed
// taken from developer.android.com
exerciseRecyclerView.setHasFixedSize(true);
// use a linear layout manager for RecyclerView
LinearLayoutManager layoutManager = new LinearLayoutManager(this.getContext());
exerciseRecyclerView.setLayoutManager(layoutManager);
// add divider
RecyclerView.ItemDecoration itemDecoration = new
DividerItemDecoration(this.getContext(), DividerItemDecoration.VERTICAL);
exerciseRecyclerView.addItemDecoration(itemDecoration);
// Create adapter and set its data set to workout
adapter = new ExerciseRecyclerViewAdapter(workout, this);
// Set up swipe to dismiss and ability to move RecyclerView items around
// Create callback object for ItemTouchHelper
ItemTouchHelper.Callback callback = new CustomItemTouchHelperCallback(adapter);
// Implement object created above
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(exerciseRecyclerView);
if (adapter.getItemCount() == 0)
{
showEmptyRecyclerViewText();
}
else
{
exerciseRecyclerView.setAdapter(adapter);
}
return v;
}
// Adds save button (check mark) to action bar
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.active_workout_action_bar, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save: {
List<Exercise> exercises = workout.getExercises();
mAuth = FirebaseAuth.getInstance();
String user_id = mAuth.getCurrentUser().getUid();
databaseWorkouts = FirebaseDatabase.getInstance().getReference("Workouts").child(user_id);
String id = databaseWorkouts.push().getKey();
workout = new Workout("abc", user_id, exercises);
databaseWorkouts.child(id).setValue(workout);
Toast.makeText(getContext(), "Workout saved", Toast.LENGTH_SHORT).show();
return true;
}
case R.id.action_delete: {
exerciseRecyclerView.requestFocus();
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Confirm deletion").setMessage("Are you sure you want to delete" +
" this workout?");
builder.setPositiveButton(android.R.string.yes, (dialog, which) -> {
try {
workoutHistory.removeWorkout(workout);
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(getContext(), "Workout deleted", Toast.LENGTH_SHORT).show();
});
builder.setNegativeButton(android.R.string.no, (dialog, which) -> {
dialog.dismiss();
});
builder.show();
return true;
}
default:
// unrecognized button pressed
return super.onOptionsItemSelected(item);
}
}
public void showEmptyRecyclerViewText()
{
emptyRecyclerView.setVisibility(View.VISIBLE);
}
public void addNewExercise(View view) {
Bundle bundle = getArguments();
String value = "";
if(bundle != null) {
value = bundle.getString("ExerciseTitle");
}
System.out.println("lala");
System.out.println(value);
Exercise newExercise = new Exercise(value, -1, -1);
if (exerciseRecyclerView.getAdapter() == null) {
exerciseRecyclerView.setAdapter(adapter);
}
emptyRecyclerView.setVisibility(View.INVISIBLE);
workout.addExercise(newExercise);
adapter.notifyItemInserted(workout.getExercises().size() - 1);
}
private void hideKeyboard(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService
(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("key", workout);
}
}
Try this as a base for your project. add views to it and other necessary methods however it will provide you with the flow of module
//contract to update Framgents
public interface FragUpdater {
public void updateExerciseFrag(Exercise exercise);
}
public class ExerciseActiity extends AppCompatActivity implements FragUpdater {
FragmentManager fm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_exercise_actiity);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gotoActiveWorkoutFragment();
}
});
fm = getSupportFragmentManager();
gotoExercisesFragment();
}
private void gotoActiveWorkoutFragment() {
ActiveWorkoutFragment activeWorkoutFragment = new ActiveWorkoutFragment();
Bundle bundle = new Bundle();
activeWorkoutFragment.setArguments(bundle);
fm.beginTransaction().add(R.id.content_frame, activeWorkoutFragment, "ExerciseSelectionFrag").addToBackStack(null).commit();
}
private void gotoExercisesFragment() {
ExercisesFragment exercisesFragment = new ExercisesFragment();
Bundle bundle = new Bundle();
exercisesFragment.setArguments(bundle);
fm.beginTransaction().replace(R.id.content_frame, exercisesFragment, "ExerciseDisplayFrag").commit();
}
#Override
public void updateExerciseFrag(Exercise exercise) {
// Get Fragment ExercisesFragment
ExercisesFragment frag = (ExercisesFragment)
fm.findFragmentByTag("ExerciseDisplayFrag");
if (frag == null) {
return;
}
frag.updateList(exercise);
}
}
public class ExercisesFragment extends Fragment {
//here update your list in ExerciseFragment
public void updateList(Exercise exercise) {}
}
public class ActiveWorkoutFragment extends Fragment {
FragUpdater fragUpdater;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragUpdater = (ExerciseActiity) getActivity();
}
private void selectListItem(Exercise exercise) {
fragUpdater.updateExerciseFrag(exercise);
getActivity().getSupportFragmentManager().popBackStack();
}
}
So I have a Sections Pager Application in Android. On my fourth fragment, I run an asynctask that connects to a device via bluetooth and updates a custom list that I created (supposedly) However, the list either updates late or doesn't update at all. I'm not exactly sure what to do on the postexecute to allow update so I updated it outside of the asynctask.
Code is below:
public class FourthFragment extends Fragment {
private WeakReference<getBeacons> getBeaconTaskWeakRef;
ArrayList<ArtInfo> ArtList = new ArrayList<>();
;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
startNewBeaconsAsyncTask();
}
ArrayList<String> titles = new ArrayList<>();
ArrayList<String> artists = new ArrayList<>();
ArrayList<String> years = new ArrayList<>();
ArrayList<Integer> images = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
for (int i = 0; i < ArtList.size(); i++) {
titles.add(ArtList.get(i).getArtTitle());
artists.add(ArtList.get(i).getArtistName());
years.add(ArtList.get(i).getYear());
int resID = getResources().getIdentifier(ArtList.get(i).getImageFilename(), "drawable", "com.acuart.acumen.acuart");
images.add(resID);
}
View v = inflater.inflate(R.layout.frag_list, container, false);
ListView byTitleList = (ListView) v.findViewById(R.id.byTitleList);
byTitleList.setAdapter(new titleList(getActivity(), R.layout.custom_list, titles));
return v;
}
private void startNewBeaconsAsyncTask() {
getBeacons newbeacons = new getBeacons(this);
this.getBeaconTaskWeakRef = new WeakReference<getBeacons>(newbeacons);
newbeacons.execute();
}
class titleList extends ArrayAdapter<String> {
public titleList(Context context, int resource, ArrayList<String> objects) {
super(context, resource, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = ((Activity) getContext()).getLayoutInflater().inflate(R.layout.custom_list, null);
TextView title = (TextView) v.findViewById(R.id.row_title);
TextView artist = (TextView) v.findViewById(R.id.row_artist);
TextView year = (TextView) v.findViewById(R.id.row_year);
ImageView image = (ImageView) v.findViewById(R.id.row_image);
title.setText(titles.get(position));
artist.setText(artists.get(position));
year.setText(years.get(position));
image.setBackgroundResource(images.get(position));
return v;
}
}
private class getBeacons extends AsyncTask<Void, Void, Void> {
private WeakReference<FourthFragment> fragmentWeakReference;
private getBeacons(FourthFragment fragment) {
this.fragmentWeakReference = new WeakReference<FourthFragment>(fragment);
}
ProgressDialog dialog = new ProgressDialog(getActivity());
Context context = getApplicationContext();
int artCount = 0;
SQLHelper markerDBHelper = new SQLHelper(context);
#Override
protected void onPreExecute() {
dialog.setMessage("Loading, please wait...");
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
checkBluetooth();
}
#Override
protected void onPostExecute(Void v) {
dialog.dismiss();
}
} //processing bluetooth data and creating a query for database return.
}
Any help/comments/ideas are appreciated.
Code in onPostExecute() runs on the UI thread, so you should be able to update your list adapter there.
I'm a bit confused by your question, are you saying that it takes a long time for onPostExecute() to run? Did you have your code in there to update the list, and then moved it out because onPostExecute() took too long to be called?
Do you have a bunch of other async tasks running?
I didn't have time to test compile/test this, so there could very well be some syntax mistakes, but this is just to give you an idea
In titleList add a method to update the data backing the adapter list so:
public void updateAdapterData(ArrayList<String> newData) {
clear();
addAll(newData);
notifyDataSetChanged();
}
And the async task could do something like this
private titleList mTitleList; //Set this in your onCreateView
private class getBeacons extends AsyncTask<Void, Void, ArrayList<String>> {
#Override
protected void onPreExecute() {
dialog.setMessage("Loading, please wait...");
dialog.show();
}
#Override
protected ArrayList<Object> doInBackground(Void... params) {
//If checkbluetooth returns a list..
return checkBluetooth();
}
#Override
protected void onPostExecute(ArrayList<String> newList) {
mTitleList.updateAdapterData(newList)
dialog.dismiss();
}
}
At First set the ListView adapter as follows:
titleList adapter=new titleList(getActivity(), R.layout.custom_list, titles));
byTitleList.setAdapter(adapter);
After doing the background task if you get an List of "titles", then in "onPostExecute" method you can do the following:-
private class getBeacons extends AsyncTask<Void, Void, ArrayList<String> > {
ArrayList<String> titles = new ArrayList<String>();
private getBeacons() {
}
#Override
protected void onPreExecute() {
}
#Override
protected ArrayList<String> doInBackground(Void... params) {
//call a method for assigning values to titles
return titles;
}
#Override
protected void onPostExecute(ArrayList<String> titles) {
//Now assign this arraylist referrence to your actual titles arraylist
adapter.notifyDataSetChanged();
}
}
You just need to update the ArrayList in your titleList adapter and call notifyDataSetChanged() on the adapter. I suggest doing this with a setList() method in the titleList class. You also need to keep a reference of the adapter where it is accessible by your AsyncTask.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I am trying to parse an rss feed and since i'm a beginner in android i cannot find a way to do this through a fragment..
This is the activity i want to convert into a fragment
public class Clients extends Activity {
private Clients local;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
local = this;
GetRSSDataTask task = new GetRSSDataTask();
task.execute("http://www.itcuties.com/feed/");
Log.d("ITCRssReader", Thread.currentThread().getName());
}
private class GetRSSDataTask extends AsyncTask<String, Void, List<RssItem> > {
#Override
protected List<RssItem> doInBackground(String... urls) {
Log.d("ITCRssReader", Thread.currentThread().getName());
try {
RssReader rssReader = new RssReader(urls[0]);
return rssReader.getItems();
} catch (Exception e) {
Log.e("ITCRssReader", e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(List<RssItem> result) {
ListView itcItems = (ListView) findViewById(R.id.listView);
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(local,android.R.layout.simple_list_item_1,result);
itcItems.setAdapter(adapter);
itcItems.setOnItemClickListener(new ListListener(result, local));
}
}
}
I already have tried to convert it but the onItemClick is getting some errors.
public void onItemClick(AdapterView parent, View view, int pos, long id) {
Intent intent = new Intent(activity, Clients.class);
intent.putExtra("description", listItems.get(pos).getLink());
activity.startActivity(intent);
}
Can someone please help me???
You should call the fragment without ui. It is needed to add ui, but not to make it visible.
public class MyFragmet extends Fragment {
public static final String TAG = "MyFragmet";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.MY_FRAGMENT_NULL_VIEW,
container, false);
local = this;
GetRSSDataTask task = new GetRSSDataTask();
task.execute("http://www.itcuties.com/feed/");
Log.d("ITCRssReader", Thread.currentThread().getName());
return view;
}
private class GetRSSDataTask extends AsyncTask<String, Void, List<RssItem> > {
#Override
protected List<RssItem> doInBackground(String... urls) {
Log.d("ITCRssReader", Thread.currentThread().getName());
try {
RssReader rssReader = new RssReader(urls[0]);
return rssReader.getItems();
} catch (Exception e) {
Log.e("ITCRssReader", e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(List<RssItem> result) {
Intent intent = new Intent();
intent.setAction(TAG ); // also here you can add other information
sendBroadcast(intent);
}
}
}
and add this to activity
private BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ListView itcItems = (ListView) findViewById(R.id.listView);
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(local,android.R.layout.simple_list_item_1,result);
itcItems.setAdapter(adapter);
itcItems.setOnItemClickListener(new ListListener(result, local));
}
};
registerReceiver(receiver, new IntentFilter(MyFragmet.TAG));
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentByTag(MyFragmet.TAG);
if (fragment == null) {
getFragmentManager()
.beginTransaction()
.add(R.id.fragment, new MyFragmet(),MyFragmet.TAG)
.commit();
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
Ok, here's my attempt:
I've replaced your ArrayAdapter with a baseadapter (finer tuned control over what happens with your items) - define a layout similiar to the list item you have in your ArrayAdapter, point the BaseAdapter at it, and set up the views within the onCreateView block.
Other than that, I think it should drop in pretty well.
public class Clients extends Fragment implents ListView.OnItemClickListener {
private Clients local;
private ListView itcItems;
private RssItemBaseAdapter adapter;
private ArrayList<Rssitem> itemList = new ArrayList<RssItem>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
local = this;
GetRSSDataTask task = new GetRSSDataTask();
task.execute("http://www.itcuties.com/feed/");
Log.d("ITCRssReader", Thread.currentThread().getName());
}
#Override
public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view rootView = infalter.inflate(R.layout.activity_my,container,false);
itcItems = (ListView)findViewById(R.id.listView);
itcItems.setOnItemClickListener(this);
adapter = new RssItemBaseAdapter(getActivity(),itemList);
itcItems.setAdapter(adapter);
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i , long l){
RssItem item = adapter.getItem(i);
<Handle your Intent code here>
}
private class GetRSSDataTask extends AsyncTask<String, Void, List<RssItem> > {
#Override
protected List<RssItem> doInBackground(String... urls) {
Log.d("ITCRssReader", Thread.currentThread().getName());
try {
RssReader rssReader = new RssReader(urls[0]);
return rssReader.getItems();
} catch (Exception e) {
Log.e("ITCRssReader", e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(List<RssItem> result) {
itemList = result;
adapter.swapList(itemList);
adapter.notifyDataSetChanged();
}
}
private class RssItemBaseAdapter extends BaseAdapter(){
private Context mContext;
private ArrayList<RssItem> mRssList;
public RssItemBaseAdapter(Context context, ArrayList<RssItem> obj){
mContext = context;
mRssList = obj;
}
#Override
public int getCount() {return mRssList.size(); }
#Override
public RssItem getItem(int i) {return mRssList.get(i); }
#Override
public long getItemId(int i) { return i }
#Override
public view getView(int i, View convertView, ViewGroup parent){
View rootView = convertView;
if (rootView == null){
View rootView = Inflater.from(mContext).inflate(R.layout.YOUR_SIMPLE_LAYOUT_HERE,parent,false);
}
<do your view setting here>
return rootView;
}
public ArrayList<RssItem> swapList (ArrayList<RssItem> newList){
ArrayList<RssItem> oldList = mRssList;
mRssList = newList;
return oldList;
}
}
}
First, I'll preface my question with the fact that I'm not using a CursorLoader.
I'm pulling in data from a SQLlite database to populate a listview in a ListFragment. The initial load works well, but once the data is manipulated (i.e. an addition is made to the list), the listview NEVER refreshes to show the new data. I am implementing the Loader callbacks like so:
public class BillListingFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Bill>> {
private billListAdapter mAdapter;
private static final int LOADER_ID = 1;
private SQLiteDatabase mDatabase;
private BillsDataSource mDataSource;
private BillsStoreDatabaseHelper mDbHelper;
/**
* The fragment argument representing the fragment type (archive or outstanding)
*/
private static final String ARG_FRAGMENT_TYPE = "fragment_type";
/**
* Returns a new instance of this fragment based on type
*/
public static BillListingFragment newInstance(String type) {
// TODO: Make the fragment type an enum
BillListingFragment fragment = new BillListingFragment();
Bundle args = new Bundle();
args.putString(ARG_FRAGMENT_TYPE, type);
fragment.setArguments(args);
return fragment;
}
public BillListingFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.bill_view_layout, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDbHelper = new BillsStoreDatabaseHelper(getActivity());
mDatabase = mDbHelper.getWritableDatabase();
mDataSource = new BillsDataSource(mDatabase);
mAdapter = new billListAdapter(getActivity(), R.layout.bill_row_layout);
setListAdapter(mAdapter);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public Loader<List<Bill>> onCreateLoader(int id, Bundle args) {
BillDataLoader loader = new BillDataLoader(getActivity(), mDataSource);
return loader;
}
#Override
public void onLoadFinished(Loader<List<Bill>> loader, List<Bill> data) {
for(Bill bill: data){
mAdapter.add(bill);
}
setListAdapter(mAdapter);
}
#Override
public void onLoaderReset(Loader<List<Bill>> loader) {
mAdapter.clear();
}
#Override
public void onDestroy() {
super.onDestroy();
mDbHelper.close();
mDatabase.close();
mDataSource = null;
mDbHelper = null;
mDatabase = null;
}
public void reload(){
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
private class billListAdapter extends ArrayAdapter<Bill> {
Context context;
public billListAdapter(Context context, int resourceID){
super(context, resourceID);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.bill_row_layout, parent, false);
}
TextView payToField = (TextView) convertView.findViewById(R.id.nameField);
TextView dueDateField = (TextView) convertView.findViewById(R.id.overdueField);
payToField.setText(getItem(position).getPayTo());
// calculate days until due
Bill bill = getItem(position);
// TODO: Add how many days until bill in overdue field + add color
JodaTimeAndroid.init(getActivity());
DateTime dueDateDt = new DateTime(bill.getDateDue());
DateTime currentDt = new DateTime();
int daysDifference = Days.daysBetween(currentDt.toLocalDate(), dueDateDt.toLocalDate()).getDays();
// depending on what that differential looks like set text / color
if (daysDifference > 1) {
dueDateField.setText(Integer.toString(daysDifference) + " Days");
} else {
if (daysDifference == 0) {
dueDateField.setText("DUE TODAY");
} else {
if (daysDifference < 0) {
}
}
}
return convertView;
}
}
}
I have debugged my code so I know that the onLoadFinished callback is being made after the data has been manipulated. I also know that adapter contains the updated data at this point. I have tried resetting the adapter via setListAdapter(mAdatper) and every notifyDataChanged-like method I can find, but to no avail. What is going on here and how can I get the listview to update?
I have a ListView in a fragment which I can add to from a BroadcastReceiver. However, when the app is removed from the "recents" panel (swipe the thumbnail of the app away - NOT choosing Force Stop in Settings) the BroadcastReceiver still runs (as it is supposed to do do when an app is removed from recents) but I get a Force Close dialog when it tries to update the ListView.
What I have gathered about what happens when removing an app from recents is that it does not kill the app, it just stops all the activiites. This means that the BroadcastReceivers and Services keep running. This is where my problem lies - I try to update the ListView in an Activity which has been stopped.
EDIT: I think that removing from recents causes onStop() to be called.
Do I need to create a service that update the ListView and keeps the activity running? Will it make any difference?
What I am trying to do is similar to say an SMS app. In an SMS app, a Broadcast is received and the ListView with the messages is updated to show the new message.
EDIT: Added some code
This is the Fragment which contains the ListView:
public class HistoryFragment extends FragmentBase implements OnItemAddedHandler {
ListView lv;
HistoryAdapter simpleAdpt;
int mPosition;
int index;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View histView = inflater.inflate(R.layout.history_fragment, container,
false);
setHasOptionsMenu(true);
ListView lv = (ListView) histView.findViewById(R.id.h_listView);
simpleAdpt = new HistoryAdapter();
lv.setAdapter(simpleAdpt);
return histView;
}
private class HistoryAdapter extends BaseAdapter {
private List<Map<String, Object>> mPlanetsList;
public HistoryAdapter() {
mPlanetsList = DataModel.getInstance().getPlanetList();
}
#Override
public int getCount() {
return mPlanetsList.size();
}
#Override
public Object getItem(int position) {
return mPlanetsList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (null == convertView) {
convertView = LayoutInflater.from(getActivity()).inflate(
R.layout.history_item, null);
Log.i("convertView", "was null");
}
TextView tv_title = (TextView) convertView
.findViewById(R.id.hi_tv_title); // This is part of the layout of each item
HashMap<String, String> itemDataHashMap = (HashMap<String, String>) getItem(position);
tv_title.setText(itemDataHashMap.get("planet"));
return convertView;
}
}
#Override
public void onItemAdded(Object data) {
simpleAdpt.notifyDataSetChanged();
}
#Override
public void onItemRemove(int postion) {
simpleAdpt.notifyDataSetChanged();
}
}
This is the BroadcastReceiver that I am trying to use to add items to the ListView. It is fired using an AlarmManager. This means that there is time for the user to remove the app from the recents panel before the item is added to the ListView:
public class ReminderBroadcastReceiver extends BroadcastReceiver {
// This is declared in the manifest
#Override
public void onReceive(Context context, Intent intent) {
String title = "title";
DataModel.getInstance()
.addItem(title); // Add to History
}
}
In DataModel there is:
public static DataModel getInstance() {
if (null == instance) {
Log.i("getInstance", "null");
instance = new DataModel();
}
return instance;
}
private DataModel() {
initList();
}
private void initList() {
mHistoryList = History.getList();
for (int i = 0; i < mHistoryList.size(); i++) {
mPlanetsList.add(mHistoryList.get(i).createPlanet());
}
}
public void addItem(String title) {
History history = new History();
history.getDataHashMap().put("planet", title);
history.addToHistoryDB(); // This just adds to a Database
mHistoryList.add(0, history); // Help keep the orders the same
mPlanetsList.add(0, history.createPlanet());
if (null != mOnItemAddHandler) {
mOnItemAddHandler.onItemAdded(title);
}
}
If any more code is needed, please say