Reputation: 290
I was following along with some videos on making a weather app and somehow ended up trying to launch my AsyncTask
from a button pressed in a drop down from my actionbar. Right now the asynctask is a separate class and the application loads the aynctask fine the first time but when i try to refresh and re launch the async task from a button in my actionbar menu the app crashes with a 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.access$600(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)
Its getting a nullPointer exception when trying to access the adapter again. Essentially there is a refresh button in my drop down in my Main activity that extends ActionBar. When i click that button it calls a method from the MainActivityFragment
class that calls the execute method of the ForeCastLoader asynctask
. In the onPostExecute()
method the results are passed back to the fragment through a processFinish()
method. Back in that method in ActivityFragment, when trying to use the adapter i get a null pointer exception. Any ideas as to what im doing wrong?
MainActivity
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);
}
I left out the aSyncTask class because i already know its returning values correctly and i dont think the problem could be anywhere there. Thanks for your help, im sure its something im just overlooking.
Upvotes: 0
Views: 335
Reputation: 1362
Well, I can see you create a new MainActivityFragment
when the NavigationItem clicked. In this way the newly created MainActivityFragment
is not the one that you added to your MainActivity
when you first launch the app. The new one's onCreate
method is not called, so you can't access the adapter
in it.
The right way to access a previously added Fragment
in an Activity
is to use the findFragmentByTag
method of the FragmentManager
.
I assume you add your MainActivityFragment
with a tag like this.
transaction.add(id, maf, MainActivityFragmentTag);
After adding it, you can access it like this.
if(position==2)
{
mfa = getSupportFragmentManager().findFragmentByTag(MainActivityFragmentTag);
mfa.update();
}
Upvotes: 1
Reputation: 3274
When you click the refresh button, I assume you are calling the onNavigationItemSelected()
method in MainActivity
with position =2
.Inside the if condition, you are creating a new instance of MainActivityFragment
and calling it's update()
method.But your adapter is getting initialised in createView()
method in MainActivityFragment
and it wont be called since you haven't called show()
on this new fragment instance.Try calling update()
method on the existing fragment itself.
Upvotes: 0