0

I have a default ListView of items created and am wanting to give the user the ability to add their own item by clicking on the Floating Action Button. Once they hit OK on the dialog, I am given a null pointer exception specifically on the line itemAdapter.notifyDataSetChanged(). I have spent a few hours researching this now and can so no reason as to why this doesn't work. If I remove this line I get no error but the list does not update when an item is added to the ArrayList.

This appears to have been marked as duplicate but the cause of this is entirely different in Android from a standard Java application like the linked question. I am getting this error specifically because of the way Android activities and fragments interact.

MainActivity.java

package com.example.josh.project3;

import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {
    private MainActivityFragment mainActivityFragment = new MainActivityFragment();
    private String m_Text = "";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        if (fab != null) {
            fab.setOnClickListener(new View.OnClickListener(){

                @Override
                public void onClick(View v) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                    builder.setTitle("Add Company");

                    final EditText input = new EditText(MainActivity.this);
                    input.setInputType(InputType.TYPE_CLASS_TEXT);
                    builder.setView(input);

                    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            m_Text = input.getText().toString();
                            String name = mainActivityFragment.getTitle(m_Text);
                            String desc = mainActivityFragment.getDescription(m_Text);
                            System.out.println(name);
                            System.out.println(desc);
                            mainActivityFragment.updateList(name, desc);
                        }
                    });

                    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.cancel();
                        }
                    });

                    builder.show();
                }
            });
        }
    }


    @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);
    }

    private class CallWebTask extends AsyncTask<String, Void, String>
    {
        String change, companySymbol, biddingPrice;


        protected String doInBackground(String... urls)
        {

            try {
                String jsonData = mainActivityFragment.run(urls[0]);
                JSONObject jsonObject = new JSONObject(jsonData);
                JSONObject query = jsonObject.getJSONObject("query");
                JSONObject results = query.getJSONObject("results");
                JSONObject quote = results.getJSONObject("quote");
                change = quote.getString("Change");
                companySymbol = quote.getString("symbol");
                biddingPrice = quote.getString("Bid");


            }
            catch (IOException e) {
                e.printStackTrace();
            }
            catch(JSONException e)
            {
                e.printStackTrace();
            }
            return companySymbol + "    " + change + "    (" + biddingPrice + ")";
        }

    }

}

MainActivityFragment.java

package com.example.josh.project3;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ListFragment;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.provider.Settings;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.Console;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * A simple {@link Fragment} subclass.
 */
public class MainActivityFragment extends ListFragment {

    OkHttpClient client = new OkHttpClient();
    String desc;
    public ArrayList<ListItems> items = new ArrayList<ListItems>();
    public ListItemsAdapter itemAdapter;
    public final static String EXTRA_TITLE = "com.example.josh.project3.title";
    public final static String EXTRA_MESSAGE =
            "com.example.josh.project3.message";
    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
 /*
 //You can use a simple array like this to populate the list:
 String [] values = new String [] {"Tennis", "Football", "Basketball", "Baseball",
"Vollyball", "Swimming"};
 ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout., values);
 setListAdapter(adapter);
 */
           //Here I am creating a list of objects from a class called ListItems using ArrayList
        items.add(new ListItems("Yahoo", getDescription("YHOO")));
        items.add(new ListItems("Google", getDescription("GOOG")));
        items.add(new ListItems("Apple", getDescription("AAPL")));
        items.add(new ListItems("Microsoft", getDescription("MSFT")));
        items.add(new ListItems("Netflix", getDescription("NFLX")));
        itemAdapter = new ListItemsAdapter(getActivity(), items);
        setListAdapter(itemAdapter);

    }
    //this is to create a simple response when a list item is clicked.

    @Override
    public void onListItemClick(ListView l, View v, int position, long id){
        super.onListItemClick(l, v, position, id);
        Intent intent = new Intent(getActivity(), SelectedItemActivity.class);
        ListItems item = (ListItems) getListAdapter().getItem(position);
        intent.putExtra(EXTRA_TITLE, item.getTitle());
        intent.putExtra(EXTRA_MESSAGE, item.getMessage());
        startActivity(intent);
    }

    public String run(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();

        Response response = client.newCall(request).execute();
        return response.body().string();
    }

    public String getDescription(String companySymbol)
    {
        try {
            desc = new CallWebTask().execute("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22" +
                    companySymbol + "%22%29&format=json&env=store://datatables.org/alltableswithkeys").get();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }

        return desc;

    }

    public String getTitle(String companySymbol)
    {
        try {
            desc = new CallWebTask().execute("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20%28%22" +
                    companySymbol + "%22%29&format=json&env=store://datatables.org/alltableswithkeys1").get();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }

        return desc;
    }

    public void updateList(String title, String desc)
    {
        ListItems listItem = new ListItems(title, desc);
        items.add(listItem);
        //itemAdapter.notifyDataSetChanged();
    }

private class CallWebTask extends AsyncTask<String, Void, String>
{
    String change, companySymbol, biddingPrice, name;


    protected String doInBackground(String... urls) {

        if (urls[0].endsWith("1")) {
            urls[0] = urls[0].substring(0, urls[0].length() - 1);
            try {
                String jsonData = run(urls[0]);
                JSONObject jsonObject = new JSONObject(jsonData);
                JSONObject query = jsonObject.getJSONObject("query");
                JSONObject results = query.getJSONObject("results");
                JSONObject quote = results.getJSONObject("quote");
                name = quote.getString("Name");


            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return name;
        } else {
            try {
                String jsonData = run(urls[0]);
                JSONObject jsonObject = new JSONObject(jsonData);
                JSONObject query = jsonObject.getJSONObject("query");
                JSONObject results = query.getJSONObject("results");
                JSONObject quote = results.getJSONObject("quote");
                change = quote.getString("Change");
                companySymbol = quote.getString("symbol");
                biddingPrice = quote.getString("Bid");


            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return companySymbol + "    " + change + "    (" + biddingPrice + ")";
        }
    }
}
}

ListItems.java

package com.example.josh.project3;

public class ListItems {
    private String title, message;

    public ListItems(String title, String message){
        this.title = title;
        this.message = message;
    }
    public String getTitle(){
        return title;
    }
    public String getMessage(){
        return message;
    }


}

ListItemsAdapter.java

package com.example.josh.project3;
import android.content.Context;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;


public class ListItemsAdapter extends ArrayAdapter<ListItems> {
    public ListItemsAdapter(Context context, ArrayList<ListItems> items){
        super(context, 0, items);
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        // Get the data item for this position
        ListItems note = getItem(position);
        // Check if an existing view is being reused, otherwise inflate a new view from// custom row layout
        if (convertView == null) {
            convertView =
                    LayoutInflater.from(getContext()).inflate(R.layout.row_item_layout, parent, false);
        }
        // Grab references of views so we can populate them with specific note row data
        TextView itemTitle = (TextView) convertView.findViewById(R.id.listItemTitle);
        TextView itemText = (TextView) convertView.findViewById(R.id.listItemBody);
        // Fill each new referenced view with data associated with note it's referencing
        itemTitle.setText(note.getTitle());
        itemText.setText(note.getMessage());
        // now that we modified the view to display appropriate data,
        //return it so it will be displayed.
        return convertView;
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.example.josh.project3.MainActivity">

    <fragment

        android:name="com.example.josh.project3.MainActivityFragment"
        android:id="@+id/MainActivityFrag"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_marginTop="45dp"
        tools:layout="@layout/row_item_layout" />

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>



    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_input_add" />

</android.support.design.widget.CoordinatorLayout>
390563959
  • 23
  • 6
  • You're not transacting `mainActivityFragment` into `MainActivity` anywhere, so none of its lifecycle methods are running. – Mike M. Apr 24 '16 at 02:46
  • How would I go about transacting it? – 390563959 Apr 24 '16 at 02:47
  • Where's it supposed to go? Post your layout for `MainActivity`. – Mike M. Apr 24 '16 at 02:51
  • 1
    OK, you've statically defined it in the layout, so you don't need to instantiate it with `new` in `MainActivity`. Instead, in `onCreate()` : `mainActivityFragment = (MainActivityFragment) getSupportFragmentManager().findFragmentById(R.id.MainActivityFrag);` – Mike M. Apr 24 '16 at 02:56
  • I get the error message that these are incompatible types and cannot be casted as such when attempting this. The reason I created a new object was so I could use the methods I have in the fragment. – 390563959 Apr 24 '16 at 03:02
  • I think it's because this class is extending a ListFragment and not a regular fragment? – 390563959 Apr 24 '16 at 03:03
  • Your `ListFragment` class needs to be imported from the support package: `import android.support.v4.app.ListFragment;`. – Mike M. Apr 24 '16 at 03:05
  • I added this to my main activity and am getting the same error – 390563959 Apr 24 '16 at 03:07
  • That's not where it goes. Look at where you're importing and using the `ListFragment` class. – Mike M. Apr 24 '16 at 03:09
  • Sorry I'm confused. Are you talking about in MainActivityFragment.java? It's already there. – 390563959 Apr 24 '16 at 03:10
  • 1
    No, it's not. `android.app.ListFragment` is there, which is why you're getting the incompatible types error. You need to replace that with the support import. – Mike M. Apr 24 '16 at 03:11
  • Oh I see now. I have done that but now I am unable to use any methods in the fragment class unless I declare this as final. I did that but now since I created the variable in the onCreate() method I cannot access methods in my private class at the bottom. – 390563959 Apr 24 '16 at 03:15
  • 1
    Leave the declaration where it was. Just initialize it in `onCreate()`, as shown in my previous comment. – Mike M. Apr 24 '16 at 03:17
  • 2
    Wow that worked! Thank you so much! You have no idea how much this has frustrated me. I greatly appreciate your help and your patience :) – 390563959 Apr 24 '16 at 03:20

0 Answers0