I'm trying to build an Activity that will serve as a Calendar Day View. When the user swipes left or right, they'll go to tomorrow or yesterday and so on through the calendar.
I decided to use ViewPager/PagerAdapter to handle the views and control the paging through days.
As part of setting up the Day View, the app will go to my API and request any appointments for that day. The appointments will be returned and displayed for that day. For retrieving data from the API, I'm using an AsyncTask. So basically, instantiateItem()
calls the API and sets up the empty listView. Then BroadcastReceiver
catches the response, parses the data and displays it.
The problem I'm having is that the first view displayed is always blank. The views to the left or right, are populated and if I go two positions in either direction, enough for the original view to get destroyed, then go back to the original view, it has data. Why? How to do get the first view to be populated without having to move over 2 swipes?
Here's my activity. I'm not currently parsing the data coming back from the API yet, just simulating with a list of strings in the mean time.
public class MyPagerActivity extends Activity {
private ViewPager myPager;
private static int viewCount = 1000;
private Context ctx;
private MyPagerAdapter myAdapter;
private static final String tag = "MyPagerActivity";
private static final String apiAction = "getAppointmentsForDate";
private static final String apiUri = "https://myAPI.com/api.php";
private static final String resource = "appointments";
private static final String action = "getappointmentsfordate";
private static final String date = "20120124";
private ProgressDialog progress;
private SharedPreferences loginPreferences;
private SharedPreferences.Editor loginPreferencesEditor;
private ListView v;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ctx = this;
myAdapter = new MyPagerAdapter();
myPager = (ViewPager) findViewById(R.id.myPager);
myPager.setAdapter(myAdapter);
myPager.setCurrentItem(500);
}
private class MyPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return viewCount;
}
@Override
public Object instantiateItem(View collection, int position) {
try {
Log.d(tag, "trying http connection");
loginPreferences = getSharedPreferences("loginPrefs", MODE_PRIVATE);
loginPreferencesEditor = loginPreferences.edit();
String authToken = loginPreferences.getString("authToken", "");
String staffOrRoomsId = loginPreferences.getString("staffOrRoomsId", "");
String staffOrRoomsIdName = loginPreferences.getString("staffOrRoomsIdName", "");
HttpPost apiRequest = new HttpPost(new URI(apiUri));
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("authToken", authToken));
parameters.add(new BasicNameValuePair("resource", resource));
parameters.add(new BasicNameValuePair("action", action));
parameters.add(new BasicNameValuePair("date", date));
parameters.add(new BasicNameValuePair(staffOrRoomsIdName, staffOrRoomsId));
apiRequest.setEntity(new UrlEncodedFormEntity(parameters));
RestTask task = new RestTask(ctx, apiAction);
task.execute(apiRequest);
//Display progress to the user
// progress = ProgressDialog.show(ctx, "Searching", "Waiting For Results...", true);
} catch (Exception e) {
e.printStackTrace();
}
Log.d(tag, "Creating another view! Position: " + position);
myPager.setTag(collection);
v = new ListView(ctx);
((ViewPager) collection).addView(v, 0);
return v;
}
@Override
public void destroyItem(View collection, int position, Object view) {
Log.d(tag, "Destroying position: " + position + "!");
((ViewPager) collection).removeView((ListView) view);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==((ListView)object);
}
@Override
public void finishUpdate(View arg0) {}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void startUpdate(View arg0) {}
}
@Override
public void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter(apiAction));
}
@Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//Clear progress indicator
if (progress != null) {
progress.dismiss();
}
Log.d(tag, "Broadcast received");
String[] from = new String[] { "str" };
int[] to = new int[] { android.R.id.text1 };
List<Map<String, String>> items = new ArrayList<Map<String, String>>();
for (int i = 0; i < 20; i++)
{
Map<String, String> map = new HashMap<String, String>();
map.put("str", String.format("Item %d", i + 1));
items.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(ctx, items, android.R.layout.simple_list_item_1, from, to);
v.setAdapter(adapter);
}
};
}
Thanks for taking the time to review this question!
By default, a ViewPager
not only loads only the currently visible page, but also the page to either side. This is the offscreenPageLimit
. The minimum value is 1.
instantiateItem
will be called for each page it wants to create. In your implementation of instantiateItem
, you are starting an AsyncTask
and assigning a value to v
. Only the last call to instantiateItem
(i.e. the last page upto the offscreenPageLimit
) will have the correct assignment of v
, and so the first page will not be populated initially.
You cannot rely on the last call to instantiateItem
to point you to the currently active page. I would switch to using a Fragment for each page, which maintains its own HTTP request and ListView
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With