异步任务刷新后尝试访问适配器时出现 nullPointer 异常

nullPointer exception when trying to access adapter after asynctask refresh

我正在观看一些关于制作天气应用程序的视频,但不知何故,我最终试图从我的操作栏下拉菜单中按下的按钮启动我的 AsyncTask。现在 asynctask 是一个单独的 class 并且应用程序第一次加载 aynctask 很好但是当我尝试刷新并从我的操作栏菜单中的按钮重新启动异步任务时应用程序崩溃并显示 NullPointerException :

07-18 00:45:05.615    5849-5849/johnpark.sunshine E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.NullPointerException
            at johnpark.sunshine.MainActivityFragment.processFinish(MainActivityFragment.java:70)
            at johnpark.sunshine.ForeCastLoader.onPostExecute(ForeCastLoader.java:39)
            at johnpark.sunshine.ForeCastLoader.onPostExecute(ForeCastLoader.java:23)
            at android.os.AsyncTask.finish(AsyncTask.java:631)
            at android.os.AsyncTask.access0(AsyncTask.java:177)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4745)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

再次尝试访问适配器时出现空指针异常。本质上,我的 Main activity 下拉菜单中有一个刷新按钮,它扩展了 ActionBar。当我单击该按钮时,它会调用 MainActivityFragment class 中的一个方法,该方法会调用 ForeCastLoader asynctask 的执行方法。在 onPostExecute() 方法中,结果通过 processFinish() 方法传回片段。回到 ActivityFragment 中的那个方法,当尝试使用适配器时,我得到一个空指针异常。关于我做错了什么有什么想法吗?

主要活动

public class MainActivity extends ActionBarActivity
                implements OnNavigationListener, android.support.v7.app.ActionBar.OnNavigationListener {

private final String TAG = this.getClass().getSimpleName();
private boolean mNaviFirstHit = true;
MainActivityFragment mfa;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String[] dropdownValues = getResources().getStringArray(R.array.nav_list);

    android.support.v7.app.ActionBar actionBar = getSupportActionBar();

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(actionBar.getThemedContext(),
            android.R.layout.simple_spinner_item, android.R.id.text1,
            dropdownValues);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    actionBar.setDisplayShowTitleEnabled(false);
    actionBar.setNavigationMode(NAVIGATION_MODE_LIST);
    actionBar.setListNavigationCallbacks(adapter, this);
}

@Override
public boolean onNavigationItemSelected(int position, long id) {
    if (mNaviFirstHit) {
        mNaviFirstHit = false;
        return true;
    }

    if(position==1)
    {
        Intent in = new Intent(getApplicationContext(),SettingsActivity.class);
        startActivity(in);
    }
    if(position==2)
    {
        mfa = new MainActivityFragment();
        mfa.update();
    }
    return true;
}
}

MainActivityFragment

public class MainActivityFragment extends Fragment implements AsyncResponse{

private ArrayList <String> list = new ArrayList<>();
static ListView lv;
ForeCastLoader  f = new ForeCastLoader(); 
ArrayAdapter<String> adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);       
    f.delegate = this;
    adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),
            R.layout.list_item_forecast,
            R.id.list_item_forecast_textview, list);

    f.execute("94043");
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState)
{
    View v = inflater.inflate(R.layout.fragment_main, container, false);
    lv = (ListView)v.findViewById(R.id.listview_forecast);
    lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Intent in = new Intent(getActivity().getApplicationContext(), DetailView.class);
            in.putExtra("tempData", adapter.getItem(position));
            startActivity(in);
        }
    });
    lv.setAdapter(adapter);
    return v;
}

public void update()
{
    f.delegate = this;
    f.execute("97865");
}

public void processFinish(String[] output)
{
    list.clear();
    for(String s:output)
    {
        list.add(s);
    }
    adapter.notifyDataSetChanged();
    lv.setAdapter(adapter);
}

我遗漏了 aSyncTask class 因为我已经正确知道它的返回值而且我不认为问题可能出在任何地方。 感谢您的帮助,我确定它只是忽略了一些东西。

当您单击刷新按钮时,我假设您正在使用 position =2 调用 MainActivity 中的 onNavigationItemSelected() 方法。在 if 条件内,您正在创建 MainActivityFragment 并调用它 update() method.But 你的适配器正在 MainActivityFragment 中的 createView() 方法中初始化,它不会被调用,因为你没有调用 show() 在这个新片段上 instance.Try 调用现有片段本身的 update() 方法。

好吧,我可以看到您在单击 NavigationItem 时创建了一个新的 MainActivityFragment。这样,新创建的 MainActivityFragment 不是您第一次启动应用程序时添加到 MainActivity 的那个。新的onCreate方法没有被调用,所以无法访问里面的adapter

Activity 中访问先前添加的 Fragment 的正确方法是使用 FragmentManager.

findFragmentByTag 方法

我假设您使用这样的标签添加 MainActivityFragment

transaction.add(id, maf, MainActivityFragmentTag);

添加后可以这样访问

if(position==2)
{
    mfa = getSupportFragmentManager().findFragmentByTag(MainActivityFragmentTag);
    mfa.update();
}