gpt4 book ai didi

android - FragmentTabHost : NullPointerException: Drawable. setState(int[]) 在空对象引用上

转载 作者:行者123 更新时间:2023-11-29 15:40:39 24 4
gpt4 key购买 nike

作为 Android 程序员的新手,我一直在尝试学习如何设置简单的选项卡式 UI。因为我认为这是当今的最佳实践,所以我决定将我的布局基于 FragmentTabHost,因为我正在处理 fragment 并且我的主要 Activity 也基于 FragmentActivity(通过扩展 AppCompatActivity)。

我的测试应用程序的结构如下:我有一个线性布局的主要 Activity ,其中包含一个 fragment ,该 fragment 将用于显示另一个布局文件中定义的不同选项卡。我扩展了 Fragment 以创建一个 TabsFragment 类,该类基于不同的布局使用 FragmentTabHost 实现此选项卡 UI。我想要两个选项卡:一个显示名称列表,一个仅显示文本(名称是通过我已经彻底测试过的类生成的)。

我使用的文件如下:

主 Activity .java

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;

public class MainActivity extends AppCompatActivity {
private String TAG = "MainActivity";
private Toolbar appToolbar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d ( TAG, "onCreate: setting content view" );
setContentView ( R.layout.activity_main );

appToolbar = ( Toolbar ) findViewById ( R.id.toolbar );
setSupportActionBar ( appToolbar );

Log.d ( TAG, "onCreate finished")
}

@Override
public boolean onCreateOptionsMenu ( Menu menu ) {
appToolbar.inflateMenu ( R.menu.menu_actions );

return ( true );
}
}

TabsFragment.java

import android.app.ListFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.support.v4.app.FragmentTabHost;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.TabHost;

/**
* Created by Joshua on 12/12/2016.
*/

public class TabsFragment extends Fragment implements TabHost.OnTabChangeListener {
private String TAG = "TabsFragment";

/* Fixed tags for the different tabs */
public static final String OVERVIEW_TAB_TAG = "TAB_OVERVIEW";
public static final String SEARCH_TAB_TAG = "TAB_SEARCH";

/* Objects necessary to build activity views
*/
private LayoutInflater mInflater; // Used for building View objects in memory from our XML-resources

/* The views and other fragments our fragment will contain and helper variables for accessing them
*/
private View mRoot; // A reference to the root vie of our fragment
private FragmentTabHost mFragmentTabHost; // A reference to the tab host ( tab controlling ) view of our fragment
private String labelOverviewTab = "Overview";
private String labelSearchTab = "Searhc";

private CustomListFragment overviewTabFragment;
private TextFragment searchTabFragment;

/* Other fragment bookkeeping variables
*/
private String mCurrentTab; // Stores the tag of the currently visible tag

/* Data and adapters for our views */
private Persons personsInfo;
private ListAdapter namesListAdapter;

/* This method will get executed when the system wants to recreate our view
i.e. when the user returns or enters our tabs interface
It will return a reference to the root node of the views tree
*/
@Override
public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) {
super.onCreateView ( inflater, container, savedInstanceState );
Log.d ( TAG, "onCreateView: starting ..." );

/* Create all the view objects we need in memory and make sure the references to them in our class are correct
*/
mRoot = inflater.inflate ( R.layout.tabs_fragment, container, false );
mFragmentTabHost = ( FragmentTabHost ) mRoot.findViewById ( android.R.id.tabhost );

Log.d ( TAG, "onCreateView: layouts inflated ... Attempting FragmentTabHost setup: ..." );
mFragmentTabHost.setup ( getContext ( ), getChildFragmentManager ( ), android.R.id.tabcontent );

Log.d ( TAG, "onCreateView: setup finished without errors ..." );

/* Initialize the tab host and make sure it's aware of all the tabs it has to manage
*/
TabHost.TabSpec overviewTabSpec = mFragmentTabHost.newTabSpec ( OVERVIEW_TAB_TAG );
TabHost.TabSpec searchTabSpec = mFragmentTabHost.newTabSpec ( SEARCH_TAB_TAG );
overviewTabSpec = overviewTabSpec.setContent ( R.id.overviewTab ).setIndicator ( labelOverviewTab );
searchTabSpec = searchTabSpec.setContent ( R.id.searchTab ).setIndicator ( labelSearchTab );

Log.d ( TAG, "onCreateView: created tab specs with TAG's " + overviewTabSpec.getTag ( ) + " & " + searchTabSpec.getTag ( ) );

Persons personsInfo = new Persons ( );
personsInfo.addPerson ( "Stanley", "Kubrick", 21 );
personsInfo.addPerson ( "Steven", "Spielberg", 20 );
personsInfo.addPerson ( "Quentin", "Tarantino", 18 );
personsInfo.addPerson ( "Joel", "Coen", 24 );
personsInfo.addPerson ( "Ethan", "Coen", 26 );

Log.d ( TAG, "onCreateView: initialized data" );

overviewTabFragment = new CustomListFragment ( );
overviewTabFragment.setFragmentContext ( getContext( ) );
overviewTabFragment.setDataSource ( personsInfo );

searchTabFragment = new TextFragment ( );
searchTabFragment.setUniqueTag ( "Search" );
searchTabFragment.setTabText ( "Here you will be able to SEARCH" );

Log.d ( TAG, "onCreateView: created fragments" );

mCurrentTab = OVERVIEW_TAB_TAG;

Log.d ( TAG, "onCreateView: set current tab variable to " + OVERVIEW_TAB_TAG );

getFragmentManager ( ).beginTransaction ( ).add ( overviewTabFragment, OVERVIEW_TAB_TAG ).commit ( );
mFragmentTabHost.addTab ( overviewTabSpec, CustomListFragment.class, null );
mFragmentTabHost.addTab ( searchTabSpec, TextFragment.class, null );

Log.d ( TAG, "onCreateView: added current tab to fragment manager and added tabs to FragmentTabHost" );

mFragmentTabHost.setCurrentTabByTag ( mCurrentTab );

Log.d ( TAG, "onCreateView: set current tab to " + mCurrentTab );

/* Make sure this fragment will listen to the user slecting a new ta
*/
Log.d ( TAG, "onCreateView: configuring tab host listener" );

mFragmentTabHost.setOnTabChangedListener ( this );

Log.d ( TAG, "onCreateView finished. Returning " + mRoot );

return ( mRoot );
}

@Override
public void onActivityCreated ( Bundle savedInstanceState ) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);

Log.d(TAG, "onActivityCreated finished" );
}

@Override
public void onTabChanged ( String tabID ) {
/* Get the fragment manager associated with the tab controlling fragment
*/
Log.d ( TAG, tabID );
FragmentManager fragmentManager = this.getFragmentManager ( );
if ( fragmentManager.findFragmentByTag ( tabID ) == null && mCurrentTab.equals ( OVERVIEW_TAB_TAG ) ) {
fragmentManager.beginTransaction ( ).replace ( android.R.id.tabcontent, searchTabFragment, SEARCH_TAB_TAG ).commit ( );
mCurrentTab = SEARCH_TAB_TAG;
} else if ( fragmentManager.findFragmentByTag ( tabID ) == null && mCurrentTab.equals ( SEARCH_TAB_TAG ) ) {
fragmentManager.beginTransaction ( ).replace ( android.R.id.tabcontent, overviewTabFragment, OVERVIEW_TAB_TAG ).commit ( );
mCurrentTab = OVERVIEW_TAB_TAG;
}
}
}

自定义列表 fragment .java

package com.joshuaindustries.tabtest;

import android.support.v4.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

/**
* Created by Joshua on 18/12/2016.
*/

public class CustomListFragment extends ListFragment {
String TAG = "CustomListFragment";

Context fragmentContext;

Persons persons;
ArrayAdapter namesListAdapter;

public void setFragmentContext ( Context fragmentContext ) {
this.fragmentContext = fragmentContext;
}

public void setDataSource ( Persons persons ) {
this.persons = persons;
namesListAdapter = new ArrayAdapter ( fragmentContext, R.layout.tab_content_list, R.id.list_item_text_view, persons.getFirstNameArray ( ) );
setListAdapter ( namesListAdapter );
}

@Override
public void onListItemClick ( ListView listView, View itemView, int position, long id ) {
Intent showDetails = new Intent ( fragmentContext, details.class );

listView.getItemAtPosition ( position );
persons.putFieldsInIntent ( showDetails, position );

startActivity ( showDetails );
}
}

文本 fragment .java

package com.joshuaindustries.tabtest;

import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TextView;

/**
* Created by Joshua on 15/12/2016.
*/

public class TextFragment extends Fragment {
String TAG = "TextFragment";
String UNIQUE_TAG;

private String mTabText;

private View mRoot;
private TextView mTextView;

public void setTabText ( String tabText ) {
mTabText = tabText;
}

@Override
public View onCreateView ( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState ) {
/* Create all the view objects we need in memory and make sure the references to them in our class are correct
*/
mRoot = inflater.inflate ( R.layout.tab_content, container, false );
mTextView = ( TextView ) mRoot.findViewById ( R.id.tabTextView );
mTextView.setText ( mTabText );

return ( mRoot );
}

public void setUniqueTag ( String tag ) { UNIQUE_TAG = tag; }
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// this is really important in order to save the state across screen
// configuration changes for example
setRetainInstance(true);
}
}

Persons.java

package com.joshuaindustries.tabtest;

import android.content.Intent;

import java.util.ArrayList;

/**
* Created by Joshua on 17/12/2016.
*/

public class Persons {
public final static String PERSON_FIRST_NAME = "PERSON_FIRST_NAME";
public final static String PERSON_LAST_NAME = "PERSON_LAST_NAME";
public final static String PERSON_AGE = "PERSON_AGE";

public class Person {
String firstName;
String lastName;
int age;

public Person ( String firstName, String lastName, int age ) {
this.firstName = firstName; this.lastName = lastName; this.age = age;
}

public void setFirstName ( String newFirstName ) { firstName = newFirstName; }
public void setLastName ( String newLastName ) { lastName = newLastName; }
public void setAge ( int newAge ) { age = newAge; }

public String getFirstName ( ) { return ( firstName ); }
public String getLastName ( ) { return ( lastName ); }
public int getAge ( ) { return ( age ); }
}

ArrayList<Person> listOfPersons;

public Persons ( ) {
listOfPersons = new ArrayList<Person> ( );
}

public void addPerson ( String firstName, String lastName, int age ) { listOfPersons.add ( new Person ( firstName, lastName, age ) ); }

public String[] getFirstNameArray ( ) {
String[] firstNamesArray = new String [ listOfPersons.size ( ) ];
int index = 0;

for ( Person person : listOfPersons ) {
firstNamesArray [ index ] = person.getFirstName ( );
++ index;
}

return ( firstNamesArray );
}

public void putFieldsInIntent ( Intent intent, int position ) {
Person personAskedFor = listOfPersons.get ( position );
intent.putExtra ( PERSON_FIRST_NAME, personAskedFor.getFirstName ( ) );
intent.putExtra ( PERSON_LAST_NAME, personAskedFor.getLastName ( ) );
intent.putExtra ( PERSON_AGE, personAskedFor.getAge ( ) );
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
tools:context="com.joshuaindustries.tabtest.MainActivity">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

<SearchView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment
class="com.joshuaindustries.tabtest.TabsFragment"
android:id="@+id/tabs_fragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>

tabs_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TabWidget
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tabStripEnabled="true" />

<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<fragment
class="com.joshuaindustries.tabtest.CustomListFragment"
android:id="@+id/overviewTab"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:name="com.joshuaindustries.tabtest.TextFragment"
android:id="@+id/searchTab"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.joshuaindustries.tabtest">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".details"></activity>
</application>

</manifest>

当我构建我的程序并运行它时,我在运行控制台中得到以下输出:

12/19 14:33:22: Launching app
Cold swapped changes.
$ adb shell am start -n "com.joshuaindustries.tabtest/com.joshuaindustries.tabtest.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Client not ready yet..Connected to process 3007 on device emulator-5554
I/art: Not late-enabling -Xcheck:jni (already on)
W/art: Unexpected CPU variant for X86 using defaults: x86
W/System: ClassLoader referenced unknown path: /data/app/com.joshuaindustries.tabtest-1/lib/x86
I/InstantRun: Instant Run Runtime started. Android package is com.joshuaindustries.tabtest, real application class is null.
W/System: ClassLoader referenced unknown path: /data/app/com.joshuaindustries.tabtest-1/lib/x86
W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
D/MainActivity: onCreate: setting content view
D/TabsFragment: onCreateView: starting ...
D/TabsFragment: onCreateView: layouts inflated ... Attempting FragmentTabHost setup: ...
D/TabsFragment: onCreateView: setup finished without errors ...
D/TabsFragment: onCreateView: created tab specs with TAG's TAB_OVERVIEW & TAB_SEARCH
D/TabsFragment: onCreateView: initialized data
D/TabsFragment: onCreateView: created fragments
D/TabsFragment: onCreateView: set current tab variable to TAB_OVERVIEW
D/TabsFragment: onCreateView: added current tab to fragment manager and added tabs to FragmentTabHost
D/TabsFragment: onCreateView: set current tab to TAB_OVERVIEW
D/TabsFragment: onCreateView: configuring tab host listener
D/TabsFragment: onCreateView finished. Returning android.support.v4.app.FragmentTabHost{8031d7c VFE...... ......I. 0,0-0,0 #1020012 android:id/tabhost}
D/TabsFragment: onActivityCreated finished
W/gralloc_ranchu: Gralloc pipe failed

[ 12-19 13:33:24.114 3007: 3007 D/ ]
HostConnection::get() New Host Connection established 0x9b1a10c0, tid 3007
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.joshuaindustries.tabtest, PID: 3007
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.drawable.Drawable.setState(int[])' on a null object reference
at android.widget.TabWidget.dispatchDraw(TabWidget.java:375)
at android.view.View.draw(View.java:17071)
at android.view.View.updateDisplayListIfDirty(View.java:16050)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.updateDisplayListIfDirty(View.java:16045)
at android.view.View.draw(View.java:16834)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.draw(View.java:17071)
at com.android.internal.policy.DecorView.draw(DecorView.java:751)
at android.view.View.updateDisplayListIfDirty(View.java:16050)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:656)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:662)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:770)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2796)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2604)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2211)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6301)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
at android.view.Choreographer.doCallbacks(Choreographer.java:683)
at android.view.Choreographer.doFrame(Choreographer.java:619)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Application terminated.

我完全不知道是什么导致了这个 NullPointerException,因为我已经确认我所有的布局都正确地膨胀了,而且我在网上其他地方找不到任何有类似问题的人。我将非常感谢您的帮助,尤其是如果您能解释为什么我的做法是错误的。

提前致谢,约书亚

最佳答案

通过删除 TabWidget 中的 android:tabStripEnabled="true" 解决了问题

关于android - FragmentTabHost : NullPointerException: Drawable. setState(int[]) 在空对象引用上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41224315/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com