Reputation: 249
So I am making an app which pulls a story from a server. The story arrives split into parts. I want to put each story part on a different ViewPager page, but what I've tried so far either makes the app crash or just gives me a blank screen.
This is my code for that activity:
package com.firegaming.myfirstapp;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Parcelable;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ContinueStoryActivity extends FragmentActivity {
private ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();
private static int partCounter;
private static String storyID;
ArrayList<String> storyPartList = new ArrayList<>();
FragmentStatePagerAdapter adapter;
ViewPager pager;
JSONArray parts = null;
private static final String GET_STORY_URL = "http://firegaming.host56.com/get_story.php";
private static final String TAG_SUCCESS = "success";
private static final String TAG_MESSAGE = "message";
private static final String TAG_PARTS = "parts";
private static final String TAG_PARTCOUNT = "partCount";
private static final String TAG_STORYID = "storyID";
private static final String TAG_STORYTEXT = "storyText";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_continue_story);
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
new GetStory().execute();
}
@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_continue_story, 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.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class MyPagerAdapter extends FragmentStatePagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int pos) {
return StoryFragment.newInstance(storyPartList.get(pos).toString());
}
@Override
public int getCount() {
return storyPartList.size();
}
public int getItemPosition(Object object){
return POSITION_NONE;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
}
class GetStory extends AsyncTask<String, String, String>{
@Override
protected void onPreExecute(){
super.onPreExecute();
pDialog = new ProgressDialog(ContinueStoryActivity.this);
pDialog.setMessage("Getting Story...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... args){
int success;
try{
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("username", MainActivity.USERNAME));
Log.d("Request!", "Starting!");
JSONObject json = jsonParser.makeHttpRequest(GET_STORY_URL, "GET", params);
Log.d("Story Attempt", json.toString());
success = json.getInt(TAG_SUCCESS);
if (success == 1){
parts = json.getJSONArray(TAG_PARTS);
partCounter = Integer.parseInt(json.getString(TAG_PARTCOUNT));
storyID = json.getString(TAG_STORYID);
return json.getString(TAG_SUCCESS);
} else {
Log.d("Story Get Failure!", json.getString(TAG_MESSAGE));
return json.getString(TAG_MESSAGE);
}
} catch (JSONException ex){
ex.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String file_url) {
pDialog.dismiss();
if (file_url != null) {
try {
for (int i = 0; i < parts.length(); i++) {
JSONObject c = parts.getJSONObject(i);
int id = c.getInt(TAG_STORYID);
String storyText = c.getString(TAG_STORYTEXT);
storyPartList.add(id-1, storyText);
}
} catch (JSONException ex) {
ex.printStackTrace();
}
adapter.notifyDataSetChanged();
}
}
}
}
What am I doing wrong here?
EDIT: When not returning null, as was suggested, the app crashes again. These are all the errors that come up in logcat when the app crashes.
01-03 12:29:19.298 29861-29861/com.firegaming.myfirstapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.firegaming.myfirstapp, PID: 29861
java.lang.NullPointerException
at com.firegaming.myfirstapp.ContinueStoryActivity$MyPagerAdapter.getItem(ContinueStoryActivity.java:88)
at android.support.v4.app.FragmentStatePagerAdapter.instantiateItem(FragmentStatePagerAdapter.java:105)
at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:837)
at android.support.v4.view.ViewPager.populate(ViewPager.java:987)
at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java:447)
at com.firegaming.myfirstapp.ContinueStoryActivity$GetStory.onPostExecute(ContinueStoryActivity.java:163)
at com.firegaming.myfirstapp.ContinueStoryActivity$GetStory.onPostExecute(ContinueStoryActivity.java:99)
at android.os.AsyncTask.finish(AsyncTask.java:632)
at android.os.AsyncTask.access$600(AsyncTask.java:177)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5586)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
at dalvik.system.NativeStart.main(Native Method)
Upvotes: 1
Views: 2137
Reputation: 30611
Assuming that all is well with your web service and you're parsing the data correctly, add the following code to your MyPagerAdapter
class:
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
First try this and see if it works ... also please post the logcat of your crash.
Three more things you need to ensure:
Make sure that the android.support.v4.app.Fragment
and android.app.Fragment
classes are not used together. Use everything from the v4 support library only.
Make sure that getCount()
returns the actual number of fragments corresponding to your getItem(int index)
method: use storyPartList.size()
in getCount()
.
As cYrixmorten has suggested, make storyPartList
an ArrayList
and call storyPartList.add(...)
instead of storyPartList.put(...)
.
Upvotes: 0
Reputation: 7108
I have a list of suggestions:
I am suspicious of the fact that storyPartList is a hasmap with id's dictated be the incoming data. If the incoming id's for instance is [0,2,3] then getItem(1) will fail. What happens if you let storyPartListsimply be an arraylist (as the name sort of suggests that it is)?
The getCount
of adapter is similarly dictated by the incoming data:
@Override
public int getCount() {
return partCounter;
}
Instead let the counter depend on the actual size of storyPartList
:
@Override
public int getCount() {
return storyPartList.size();
}
Now, having the pager data being determined purely by the amount of data added to storyPartList
, I would suggest creating the pager once in onCreate()
instead of re-creating it each time you add a story:
ViewPager pager;
FragmentStatePagerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_continue_story);
new GetStory().execute();
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager())
pager.setAdapter(adapter);
}
And in onPostExecute
now simply do:
adapter.notifyDataSetChanged();
This will make the adapter refresh it's contents based on the content of storyPartList
. To make the adapter update correctly you might have to add this to MyPagerAdapter
:
public int getItemPosition(Object object){
return POSITION_NONE;
}
Summary of suggestions
Upvotes: 2