包含来自异步任务的数据的 Viewpager
Viewpager with data from asynctask
所以我正在制作一个从服务器提取故事的应用程序。故事分为几个部分。我想将每个故事部分放在不同的 ViewPager 页面上,但到目前为止我所做的尝试要么使应用程序崩溃,要么只给我一个空白屏幕。
这是我的活动代码:
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();
}
}
}
}
我做错了什么?
编辑:
当没有像建议的那样返回 null 时,应用程序再次崩溃。
这些是应用程序崩溃时 logcat 中出现的所有错误。
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.access0(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)
假设您的网络服务一切正常并且您正在正确解析数据,请将以下代码添加到您的 MyPagerAdapter
class:
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
首先尝试这个,看看它是否有效......也请 post 你的崩溃 logcat。
您还需要确保三件事:
确保 android.support.v4.app.Fragment
和 android.app.Fragment
class 没有一起使用。仅使用 v4 支持库中的所有内容。
确保getCount()
returns实际片段数对应你的getItem(int index)
方法:在getCount()
中使用storyPartList.size()
.
正如 cYrixmorten 所建议的那样,将 storyPartList
设为 ArrayList
并调用 storyPartList.add(...)
而不是 storyPartList.put(...)
。
我有一个建议列表:
我怀疑 storyPartList 是一个 hasmap,其 id 指示为传入数据。例如,如果传入的 id 是 [0,2,3],则 getItem(1) 将失败。如果让 storyPartList 简单地成为一个数组列表(顾名思义)会发生什么?
适配器的getCount
同样由传入数据决定:
@Override
public int getCount() {
return partCounter;
}
而是让计数器取决于 storyPartList
:
的实际大小
@Override
public int getCount() {
return storyPartList.size();
}
现在,如果寻呼机数据完全由添加到 storyPartList
的数据量决定,我建议在 onCreate()
中创建一次寻呼机,而不是每次添加时都重新创建一个故事:
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);
}
在 onPostExecute
中,现在只需执行:
adapter.notifyDataSetChanged();
这将使适配器根据 storyPartList
的内容刷新其内容。要使适配器正确更新,您可能必须将其添加到 MyPagerAdapter
:
public int getItemPosition(Object object){
return POSITION_NONE;
}
建议汇总
- 将 storyPartList 设为 List 而不是 Map
- 让getCount return storyPartList.size()
- 在 onCreate 中创建分页器,并在添加故事时调用 notifyDataSetChanged
- 最后在适配器中实现 getItemPosition 使其正确更新
所以我正在制作一个从服务器提取故事的应用程序。故事分为几个部分。我想将每个故事部分放在不同的 ViewPager 页面上,但到目前为止我所做的尝试要么使应用程序崩溃,要么只给我一个空白屏幕。
这是我的活动代码:
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();
}
}
}
}
我做错了什么?
编辑: 当没有像建议的那样返回 null 时,应用程序再次崩溃。 这些是应用程序崩溃时 logcat 中出现的所有错误。
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.access0(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)
假设您的网络服务一切正常并且您正在正确解析数据,请将以下代码添加到您的 MyPagerAdapter
class:
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
//do nothing here! no call to super.restoreState(arg0, arg1);
}
首先尝试这个,看看它是否有效......也请 post 你的崩溃 logcat。
您还需要确保三件事:
确保
android.support.v4.app.Fragment
和android.app.Fragment
class 没有一起使用。仅使用 v4 支持库中的所有内容。确保
getCount()
returns实际片段数对应你的getItem(int index)
方法:在getCount()
中使用storyPartList.size()
.正如 cYrixmorten 所建议的那样,将
storyPartList
设为ArrayList
并调用storyPartList.add(...)
而不是storyPartList.put(...)
。
我有一个建议列表:
我怀疑 storyPartList 是一个 hasmap,其 id 指示为传入数据。例如,如果传入的 id 是 [0,2,3],则 getItem(1) 将失败。如果让 storyPartList 简单地成为一个数组列表(顾名思义)会发生什么?
适配器的getCount
同样由传入数据决定:
@Override
public int getCount() {
return partCounter;
}
而是让计数器取决于 storyPartList
:
@Override
public int getCount() {
return storyPartList.size();
}
现在,如果寻呼机数据完全由添加到 storyPartList
的数据量决定,我建议在 onCreate()
中创建一次寻呼机,而不是每次添加时都重新创建一个故事:
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);
}
在 onPostExecute
中,现在只需执行:
adapter.notifyDataSetChanged();
这将使适配器根据 storyPartList
的内容刷新其内容。要使适配器正确更新,您可能必须将其添加到 MyPagerAdapter
:
public int getItemPosition(Object object){
return POSITION_NONE;
}
建议汇总
- 将 storyPartList 设为 List 而不是 Map
- 让getCount return storyPartList.size()
- 在 onCreate 中创建分页器,并在添加故事时调用 notifyDataSetChanged
- 最后在适配器中实现 getItemPosition 使其正确更新