如何使用 viewpager 和片段为我的 ListView 设置适配器
Posted
技术标签:
【中文标题】如何使用 viewpager 和片段为我的 ListView 设置适配器【英文标题】:How to set an adapter to my ListView with a viewpager and fragment 【发布时间】:2016-11-21 17:32:55 【问题描述】:我的代码中出现以下错误:
FATAL EXCEPTION: main
Process: com.herprogramacin.hermosaprogramacion, PID: 6541
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
at com.herprogramacin.hermosaprogramacion.UI.MainActivity$LoadData.onPostExecute(MainActivity.java:215)
at
com.herprogramacin.hermosaprogramacion.UI.MainActivity$LoadData.onPostExecute(MainActivity.java:195)
at android.os.AsyncTask.finish(AsyncTask.java:651)
at android.os.AsyncTask.access$500(AsyncTask.java:180)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
我正在使用我的 Activity 的以下代码来获取提要,一旦获得提要,我就使用函数 LoadData 将适配器设置为视图。
public class MainActivity extends AppCompatActivity
private static final String TAG = MainActivity.class.getSimpleName();
public static final String URL_FEED = "http://www.forbes.com/most-popular/feed";
private ListView listView;
private FeedAdapter adapter;
/*
ViewPager
*/
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
private ViewPagerAdapter viewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Obtener la lista
listView = (ListView)findViewById(R.id.lista);
ConnectivityManager connMgr = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected())
VolleySingleton.getInstance(this).addToRequestQueue(
new XmlRequest<>(
URL_FEED,
Rss.class,
null,
new Response.Listener<Rss>()
@Override
public void onResponse(Rss response)
// Caching
FeedDatabase.getInstance(MainActivity.this).
sincronizarEntradas(response.getChannel().getItems());
// Carga inicial de datos...
new LoadData().execute();
,
new Response.ErrorListener()
@Override
public void onErrorResponse(VolleyError error)
Log.d(TAG, "Error Volley: " + error.getMessage());
)
);
else
Log.i(TAG, "La conexi�n a internet no est� disponible");
adapter= new FeedAdapter(
this,
FeedDatabase.getInstance(this).obtenerEntradas(),
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
listView.setAdapter(adapter);
/*
Assigning view variables to thier respective view in xml
by findViewByID method
*/
toolbar = (Toolbar) findViewById(R.id.tool_bar);
tabLayout = (TabLayout) findViewById(R.id.tabs);
viewPager = (ViewPager) findViewById(R.id.viewpager);
/*
Creating Adapter and setting that adapter to the viewPager
setSupportActionBar method takes the toolbar and sets it as
the default action bar thus making the toolbar work like a normal
action bar.
*/
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(viewPagerAdapter);
setSupportActionBar(toolbar);
/*
TabLayout.newTab() method creates a tab view, Now a Tab view is not the view
which is below the tabs, its the tab itself.
*/
final TabLayout.Tab noticas = tabLayout.newTab();
final TabLayout.Tab eventos = tabLayout.newTab();
final TabLayout.Tab trabajo = tabLayout.newTab();
/*
Setting Title text for our tabs respectively
*/
noticas.setText("Noticias");
eventos.setText("Eventos");
trabajo.setText("Trabajo");
/*
Adding the tab view to our tablayout at appropriate positions
As I want home at first position I am passing home and 0 as argument to
the tablayout and like wise for other tabs as well
*/
tabLayout.addTab(noticas, 0);
tabLayout.addTab(eventos, 1);
tabLayout.addTab(trabajo, 2);
/*
TabTextColor sets the color for the title of the tabs, passing a ColorStateList here makes
tab change colors in different situations such as selected, active, inactive etc
TabIndicatorColor sets the color for the indiactor below the tabs
*/
// tabLayout.setTabTextColors(ContextCompat.getColorStateList(this, R.color.tab_selector));
// tabLayout.setSelectedTabIndicatorColor(ContextCompat.getColor(this, R.color.indicator));
/*
Adding a onPageChangeListener to the viewPager
1st we add the PageChangeListener and pass a TabLayoutPageChangeListener so that Tabs Selection
changes when a viewpager page changes.
*/
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
@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_main, 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 LoadData extends AsyncTask<Void, Void, Cursor>
@Override
protected Cursor doInBackground(Void... params)
// Carga inicial de registros
return FeedDatabase.getInstance(MainActivity.this).obtenerEntradas();
@Override
protected void onPostExecute(Cursor cursor)
super.onPostExecute(cursor);
// Crear el adaptador
adapter = new FeedAdapter(
MainActivity.this,
cursor,
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
// Relacionar la lista con el adaptador
listView.setAdapter(adapter);
这是我的 ViewPager
public class ViewPagerAdapter extends FragmentStatePagerAdapter
public ViewPagerAdapter(FragmentManager fm)
super(fm);
@Override
public Fragment getItem(int position)
return new TabFragment();
@Override
public int getCount()
return 3; // As there are only 3 Tabs
以及我使用 ListFragment 实现列表视图的 Fragment
public class TabFragment extends ListFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
return inflater.inflate(R.layout.tabs, container, false);
当我在我的活动中将适配器设置为 listview 时,这似乎是一个问题。我需要在我的 MainActivity 中设置它,因为有我的 LoadData 函数。我应该在我的片段中使用适配器吗?如何?那我怎么实现 LoadData 呢?
谢谢
编辑:
这是我的 tabs.xml,我在其中获取“lista”id
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:id="@+id/lista"
android:divider="@null"
android:dividerHeight="0dp"
android:background="#F1F5F8"
android:padding="6dp"/>
编辑 2:
我想我应该在 LoadData 中创建寻呼机并发送一个带有“新”功能的 Bundle,然后再将 args 从 viewpager 发送到片段。我试过了,但创建捆绑包时出错。
这是我的 feedAdapter。
public class FeedAdapter extends CursorAdapter
/*
Etiqueta de Depuración
*/
private static final String TAG = FeedAdapter.class.getSimpleName();
/**
* View holder para evitar multiples llamadas de findViewById()
*/
static class ViewHolder
TextView titulo;
TextView descripcion;
int tituloI;
int descripcionI;
public FeedAdapter(Context context, Cursor c, int flags)
super(context, c, flags);
public View newView(Context context, Cursor cursor, ViewGroup parent)
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_layout, null, false);
ViewHolder vh = new ViewHolder();
// Almacenar referencias
vh.titulo = (TextView) view.findViewById(R.id.titulo);
vh.descripcion = (TextView) view.findViewById(R.id.descripcion);
// Setear indices
vh.tituloI = cursor.getColumnIndex(ScriptDatabase.ColumnEntradas.TITULO);
vh.descripcionI = cursor.getColumnIndex(ScriptDatabase.ColumnEntradas.DESCRIPCION);
view.setTag(vh);
return view;
public void bindView(View view, Context context, Cursor cursor)
final ViewHolder vh = (ViewHolder) view.getTag();
// Setear el texto al titulo
vh.titulo.setText(cursor.getString(vh.tituloI));
// Obtener acceso a la descripción y su longitud
int ln = cursor.getString(vh.descripcionI).length();
String descripcion = cursor.getString(vh.descripcionI);
// Acortar descripción a 77 caracteres
vh.descripcion.setText(descripcion);
如果我使用 adapter=new FeedAdapter(context,cursor,flag),我必须在捆绑包中使用什么样的“放置”? .putserializable,.putString?
// Crear el adaptador
adapter = new FeedAdapter(
MainActivity.this,
cursor,
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
Bundle arguments = new Bundle();
arguments.put(adapter);
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), arguments);
viewPager.setAdapter(viewPagerAdapter);
【问题讨论】:
listView = (ListView)findViewById(R.id.lista);
之后,你能做一个if(listView == null)
检查吗?确保 xml 中的 id 与您调用的内容相匹配 (lista)
你是对的。我做了 if(listView == null) System.out.println("There is not listView");并且它可以工作,所以这意味着它还没有创建或者什么?
您也可以分享您的 .xml 文件吗? findViewById
如果找不到,则返回 null
。
我用那个 xml 编辑了我的原始帖子。我找不到解决方案
【参考方案1】:
您需要将 ListView
从 tabs.xml
移动到 activity_main.xml
(当您调用 findViewById
时,它正在寻找它。然后,
将<ListView android:id="@+id/lista"
更改为<ListView android:id="@android:id/list"
。更多信息可以在here找到。
如果xml文件需要自己做,可以参考这个SOanswer。
【讨论】:
我必须使用该 xml,因为我正在使用寻呼机适配器,并且选项卡将是框架的 xml。非常感谢该线程的链接。【参考方案2】:lv.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(), R.layout.my_layout, R.id.just_an_id, MyList1));
这是我用于片段列表的适配器,效果很好
【讨论】:
您使用扩展 ListFragment 还是仅使用 Fragment?以上是关于如何使用 viewpager 和片段为我的 ListView 设置适配器的主要内容,如果未能解决你的问题,请参考以下文章
如何从(和替换)TabLayout 和 ViewPager 移动到新片段?
选择片段 A 时如何在 ViewPager 上不一起启动所有片段