I'm trying to implement the following:
In the tab "List" (Fragment) of the activity, I need to show a custom ListView with some "Topics" saved in the SQLite local DB. I want to show, like, 10 of them and give the user the chance to scroll down and auto-add other "Topics" if they are present.
I've tried to help myself with shontauro's LoadMore project but I can't figure out what's the problem.
ListFragment
public class ListFragment extends Fragment {
private List<Topic> values;
private static int offset = 0;
private static int increment = 10;
ArrayList<Topic> adapter;
public boolean isLoading = false;
TopicListView postList;
public Handler mHandler;
CustomAdapter cAdapter;
View ftView;
boolean alreadyCreated = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_list, container, false);
MainActivity activity = (MainActivity) this.getActivity();
values = activity.getDatasource().getAllTopics();
Collections.reverse(values);
adapter = new ArrayList<Topic>(values);
cAdapter = new CustomAdapter(this.getContext(), adapter);
postList = new TopicListView(getContext());
postList = (TopicListView) rootView.findViewById(R.id.topic_list);
postList.setAdapter(cAdapter);
postList.setOnLoadMoreListener(new TopicListView.OnLoadMoreListener() {
public void onLoadMore() {
new LoadDataTask().execute();
}
});
postList.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
Topic pickedTopic = null;
pickedTopic = (Topic) parent.getItemAtPosition(position);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
StringBuilder topic = new StringBuilder();
topic.append("Topic: ").append(pickedTopic.getTopic_type()).append("\n");
topic.append("Estimated time: ").append(pickedTopic.getEstimatedTime()).append("\n");
topic.append("Severity: ").append(pickedTopic.getSeverity()).append("\n");
topic.append("Message: ").append(pickedTopic.getMessage()).append("\n");
builder.setMessage("Post: \n\n" + topic.toString())
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
});
return rootView;
}
private class LoadDataTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
if (isCancelled()) {
return null;
}
// Should I do something here?
return null;
}
@Override
protected void onPostExecute(Void result) {
// notify the adapter that the data have been changed
((BaseAdapter) cAdapter).notifyDataSetChanged();
// Call onLoadMoreComplete when the LoadMore task, has finished
((TopicListView) postList).onLoadMoreComplete();
super.onPostExecute(result);
}
@Override
protected void onCancelled() {
// Notify the loading more operation has finished
((TopicListView) postList).onLoadMoreComplete();
}
}
}
TopicDataSource
/**
* TopicsDataSource class contains all data related to the SQLite database.
*
*/
public class TopicsDataSource {
/**
* Database fields
*/
private SQLiteDatabase database;
private DBHelper dbHelper;
private String[] allColumns =
{
DBHelper.ID,
DBHelper.ID_MONGO,
DBHelper.TOPIC_TYPE,
DBHelper.ESTIMATED_TIME,
DBHelper.SEVERITY,
DBHelper.MESSAGE
};
/**
* Constructor.
* @param context app's context
*/
public TopicsDataSource(Context context) { dbHelper = new DBHelper(context);}
/**
* The method opens the db.
* @throws SQLException
*/
public void open() throws SQLException { database = dbHelper.getWritableDatabase(); }
/**
* The method closes the db.
* @throws SQLException
*/
public void close()
{
dbHelper.close();
}
/**
* The function returns a Topic to be created.
* @param id_mongo mongoDB's primary key
* @param topic_type type of the topic
* @param estimatedTime estimated time of the topic
* @param severity severity of the topic
* @param message message of the topic
* @return the created topic
*/
public Topic createTopic(String id_mongo, String topic_type, int estimatedTime, int severity, String message)
{
ContentValues values = new ContentValues();
values.put(DBHelper.ID_MONGO, topic_type);
values.put(DBHelper.TOPIC_TYPE, topic_type);
values.put(DBHelper.ESTIMATED_TIME, estimatedTime);
values.put(DBHelper.SEVERITY, severity);
values.put(DBHelper.MESSAGE, message);
values.put(DBHelper.CREATED_AT, getDateTime());
long insertId = database.insert(DBHelper.TABLE, null, values);
Cursor cursor = database.query( DBHelper.TABLE,
allColumns,
DBHelper.ID + " = " + insertId,
null, null, null, null);
cursor.moveToFirst();
Topic newTopic = cursorToName(cursor);
cursor.close();
return newTopic;
}
/**
* The functions returns the timestamp.
* @return the current time timestamp
*/
private String getDateTime() {
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault());
Date date = new Date();
return dateFormat.format(date);
}
/**
* The method deletes a topic from the database.
* @param topic to be deleted
*/
public void deleteTopic(Topic topic)
{
long id = topic.getId();
System.out.println("User deleted with id: " + id);
database.delete(DBHelper.TABLE, DBHelper.ID + " = '" + id + "'", null);
}
/**
* The function returns all the data of the database.
* @return list of all the Topics
*/
public List<Topic> getAllTopics()
{
List<Topic> topics = new ArrayList<Topic>();
Cursor cursor = database.query(DBHelper.TABLE, allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
Topic topic = cursorToName(cursor);
topics.add(topic);
cursor.moveToNext();
}
cursor.close();
return topics;
}
/**
* The function returns the Topic pointed by the cursor.
* @param cursor cursor
* @return pointed Topic
*/
private Topic cursorToName(Cursor cursor)
{
Topic user = new Topic();
user.setId(cursor.getLong(0));
user.setId_Mongo(cursor.getString(1));
user.setTopic_type(cursor.getString(2));
user.setEstimatedTime(cursor.getInt(3));
user.setSeverity(cursor.getInt(4));
user.setMessage(cursor.getString(5));
return user;
}
}
TopicListView
public class TopicListView extends ListView implements AbsListView.OnScrollListener {
/**
* Listener that will receive notifications every time the list scrolls.
*/
private OnScrollListener mOnScrollListener;
/**
* Reader for the XML file for creating the UI layout.
*/
private LayoutInflater mInflater;
/**
* Footer View
*/
private RelativeLayout mFooterView;
/**
* Progress bar
*/
private ProgressBar mProgressBarLoadMore;
/**
* Listener to process load more items when user reaches the end of the list.
*/
private OnLoadMoreListener mOnLoadMoreListener;
/**
* Boolean To know if the list is loading more items.
*/
private boolean mIsLoadingMore = false;
/**
* State of the scroll.
*/
private int mCurrentScrollState;
/**
* Constructor.
* @param context app'scontext
*/
public TopicListView(Context context) {
super(context);
init(context);
}
/**
* Constructor.
* @param context app's context
* @param attrs attributes
*/
public TopicListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* Constructor.
* @param context app's context
* @param attrs attributes
* @param defStyle style definition
*/
public TopicListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
* The method initialize all the UI components.
* @param context app's context
*/
private void init(Context context) {
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mFooterView = (RelativeLayout) mInflater.inflate(
R.layout.progress_layout, this, false);
mProgressBarLoadMore = (ProgressBar) mFooterView
.findViewById(R.id.load_more_progressBar);
addFooterView(mFooterView);
super.setOnScrollListener(this);
}
/**
* The method sets the adapter.
*/
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
}
/**
* The method sets the listener that will receive notifications every time the list
* scrolls.
* @param l the scroll listener
*/
@Override
public void setOnScrollListener(AbsListView.OnScrollListener l) {
mOnScrollListener = l;
}
/**
* The method registers a callback to be invoked when this list reaches the end (last
* item be visible).
* @param onLoadMoreListener The callback to run.
*/
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
mOnLoadMoreListener = onLoadMoreListener;
}
/**
* The method sets what to do in case of scrolling the list.
* @param view current view
* @param firstVisibleItem first item of the list
* @param visibleItemCount number of visible items of the list
* @param totalItemCount number of items
*/
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(view, firstVisibleItem,
visibleItemCount, totalItemCount);
}
if (mOnLoadMoreListener != null) {
if (visibleItemCount == totalItemCount) {
mProgressBarLoadMore.setVisibility(View.GONE);
return;
}
boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;
if (!mIsLoadingMore && loadMore
&& mCurrentScrollState != SCROLL_STATE_IDLE) {
mProgressBarLoadMore.setVisibility(View.VISIBLE);
mIsLoadingMore = true;
onLoadMore();
}
}
}
/**
* The method sets what to do in case of a change in ste scroll status.
* @param view current view
* @param scrollState status of the scrolling
*/
public void onScrollStateChanged(AbsListView view, int scrollState) {
if ( scrollState == OnScrollListener.SCROLL_STATE_IDLE ) { view.invalidateViews(); }
mCurrentScrollState = scrollState;
if (mOnScrollListener != null) {
mOnScrollListener.onScrollStateChanged(view, scrollState);
}
}
/**
* The method invokes onLoadMore.
*/
public void onLoadMore() {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
}
/**
* The method notifies the 'loading more' operation has finished.
*/
public void onLoadMoreComplete() {
mIsLoadingMore = false;
mProgressBarLoadMore.setVisibility(View.GONE);
}
/**
* Interface definition for a callback to be invoked when list reaches the
* last item (the user load more items in the list)
*/
public interface OnLoadMoreListener {
/**
* Called when the list reaches the last item (the last item is visible
* to the user)
*/
public void onLoadMore();
}
}
**Topic**
public class Topic {
/**
* Attributes
*/
private long id;
private String id_mongo;
private String topic_type;
private int estimatedTime;
private int severity;
private String message;
/**
* Constructor.
*/
public Topic() {}
/**
* Constructor.
* @param id_Mongo mongoDB's primary key
* @param topic_type type of the topic
* @param estimatedTime estimated time of the topic
* @param severity severity of the topic
* @param message message of the topic
*/
public Topic(String id_Mongo, String topic_type, int estimatedTime, int severity, String message) {
this.id_mongo = id_Mongo;
this.topic_type = topic_type;
this.estimatedTime = estimatedTime;
this.severity = severity;
this.message = message;
}
/**
* Get {@see #id}.
* @return SQLite's primary key of the topic
*/
public long getId() {
return id;
}
/**
* Set {@see #id}.
*/
public void setId(long id) { this.id = id; }
/**
* Get {@see #id_mongo}.
* @return mongoDB's primary key of the topic
*/
public String getId_Mongo() {
return id_mongo;
}
/**
* Set {@see #id_mongo}.
*/
public void setId_Mongo(String id_mongo) { this.id_mongo = id_mongo; }
/**
* Get {@see #topic_type}.
* @return type of the topic
*/
public String getTopic_type() {
return topic_type;
}
/**
* Set {@see #topic_type}.
*/
public void setTopic_type(String topic_type) {
this.topic_type = topic_type;
}
/**
* Get {@see #estimatedTime}.
* @return estimated amount of time of the topic to be worked
*/
public int getEstimatedTime() {
return estimatedTime;
}
/**
* Set {@see #estimatedTime}.
*/
public void setEstimatedTime(int estimatedTime) {
this.estimatedTime = estimatedTime;
}
/**
* Get {@see #severity}.
* @return severity of the topic
*/
public int getSeverity() {
return severity;
}
/**
* Set {@see #severity}.
*/
public void setSeverity(int severity) {
this.severity = severity;
}
/**
* Get {@see #message}.
* @return message of the topic
*/
public String getMessage() {
return message;
}
/**
* Set {@see #message}.
*/
public void setMessage(String message) {
this.message = message;
}
}
List_item.xml
<?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" >
<TextView
android:id="@+id/topic_type"
android:layout_width="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:text="Topic type: "
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_height= "wrap_content"/>
<TextView
android:id="@+id/estimatedTime"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/topic_type"
android:text="Estimated Time: "
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/severity"
android:layout_marginLeft="35dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/topic_type"
android:layout_toRightOf="@+id/estimatedTime"
android:text="Severity: "
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/message"
android:layout_marginLeft="55dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/topic_type"
android:layout_toRightOf="@+id/severity"
android:text="Click for more info..."
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
What I am missing?