Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Eric Perozich
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Eric Perozich
Front End Web Development Techdegree Graduate 23,536 Points

Null pointer exception in ListingAdapter overrides

I have tried every recommendation found in previous questions and still cannot get past this null pointer exception. I even tried to update Picasso to the latest version that replaced the with() method with the get() method which caused another error. Idk what else to say about it. maybe someone else can point me in the right direction. here is all the code I can provide already updated with the fixes suggested in other threads:

Logcat error:

2022-01-23 13:08:39.085 4169-4169/com.example.recommendations E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.recommendations, PID: 4169
    java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.recommendations.MainActivity.showList()' on a null object reference
        at com.example.recommendations.ListingAdapter.success(ListingAdapter.java:65)
        at com.example.recommendations.ListingAdapter.success(ListingAdapter.java:21)
        at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:45)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

ListingAdapter.java where Logcat error was found:

    @Override
    public void success(ActiveListings activeListings, Response response) {
        this.activeListings = activeListings;
        notifyDataSetChanged();
        this.activity.showList(); 
// this.activity is causing the null pointer exception.
//which leads me to believe the context "this" is the part that's not functioning correctly
//but I have no idea what to do about it or how to point it to something that returns != null
    }

full ListingAdapter class:

package com.example.recommendations;


import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.example.recommendations.model.ActiveListings;
import com.example.recommendations.model.Listing;
import com.squareup.picasso.Picasso;

import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;

public class ListingAdapter extends RecyclerView.Adapter<ListingAdapter.ListingHolder>
implements Callback<ActiveListings> {

    private MainActivity activity;
    private LayoutInflater inflater;
    private ActiveListings activeListings;

    public ListingAdapter(MainActivity activity) {
        inflater = LayoutInflater.from(activity);
    }

    @NonNull
    @Override
    public ListingHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        return new ListingHolder(inflater.inflate(R.layout.layout_listing, viewGroup, false));
    }

    @Override
    public int getItemCount() {
        if (activeListings == null)
            return 0;

        if (activeListings.results == null)
            return 0;

        return activeListings.results.length;
    }

    @Override
    public void onBindViewHolder(@NonNull ListingHolder holder, int i) {
        final Listing listing = activeListings.results[i];
        holder.titleView.setText(listing.title);
        holder.priceView.setText(listing.price);
        holder.shopNameView.setText(listing.shop.shop_name);

        Picasso.get().load(listing.images[0].url_570xN)
                .into(holder.imageView);
// Picasso.get() is the updated method to match Picasso 2.8 it replaced the 
//.with() method I have tried both and neither fixes the 
//NullPointerException causing the app to crash
    }


    @Override
    public void success(ActiveListings activeListings, Response response) {
        this.activeListings = activeListings;
        notifyDataSetChanged();
        this.activity.showList(); //<--- Logcat error occurs here
    }

    @Override
    public void failure(RetrofitError error) {
        this.activity.showError();
    }

    public ActiveListings getActiveListings() {
        return activeListings;
    }

    public class ListingHolder extends RecyclerView.ViewHolder {
        public ImageView imageView;
        public TextView titleView;
        public TextView shopNameView;
        public TextView priceView;

        public ListingHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.listing_image);
            titleView = itemView.findViewById(R.id.listing_title);
            shopNameView = itemView.findViewById(R.id.listing_shop_name);
            priceView = itemView.findViewById(R.id.listing_price);

        }
    }
}

Full Etsy class (renamed etsy.java to ApiKeys.java since I'm storing the google+ Api key in the same file):

package com.example.recommendations.api;

import com.example.recommendations.model.ActiveListings;

import retrofit.Callback;
import retrofit.RequestInterceptor;
import retrofit.RestAdapter;

public class ApiKeys {
    public static final String ETSY_API_KEY = "5ysmw6833yd5cnfqy40wzoqu";
        // google is no longer using the method described in the videos
        // and now generates a normal API key which I have added below
    public static final String GOOGLE_API_KEY = "AIzaSyBfJuMQuFaiiapN42kmUUSkEQWXWcnimrs";

    private static RequestInterceptor getInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void intercept(RequestFacade request) {
                request.addEncodedQueryParam("api_key", ETSY_API_KEY);
            }
        };
    }

    private static Api getApi() {
        return new RestAdapter.Builder()
                .setEndpoint("https://openapi.etsy.com/v2")
                .setRequestInterceptor(getInterceptor())
                .build()
                .create(Api.class);
    }

    public static void getActiveListings(Callback<ActiveListings> callback) {
        getApi().activeListings("Shop,Images", callback);
    } // tried the fix where someone suggested changing "Images,Shop" to "Shop,Images" neither works to fix the error.
}

Full Interface class:

package com.example.recommendations.api;

import com.example.recommendations.model.ActiveListings;

import retrofit.Callback;
import retrofit.http.GET;
import retrofit.http.Query;


public interface Api {

    @GET("/listings/active")
    void activeListings(@Query("includes") String includes,
                        Callback<ActiveListings> callback);
}

Full Shop class:

package com.example.recommendations.model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by jhuson on 1/22/15.
 */
public class Shop implements Parcelable {

    public int shop_id;
    public String shop_name;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(shop_id);
        dest.writeString(shop_name);
    }

    public static final Creator<Shop> CREATOR = new Creator<Shop>() {
        @Override
        public Shop createFromParcel(Parcel source) {
            Shop shop = new Shop();
            shop.shop_id = source.readInt();
            shop.shop_name = source.readString();
            return shop;
        }

        @Override
        public Shop[] newArray(int size) {
            return new Shop[size];
        }
    };
}

Full Listing Class:

package com.example.recommendations.model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by jhuson on 1/22/15.
 */
public class Listing implements Parcelable {

    public int listing_id;
    public String title;
    public String description;
    public String price;
    public String url;
    public Shop shop;
    public Image[] images;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(listing_id);
        dest.writeString(title);
        dest.writeString(description);
        dest.writeString(price);
        dest.writeString(url);
        dest.writeParcelable(shop, 0);
        dest.writeParcelableArray(images, 0);
    }

    public static final Creator<Listing> CREATOR = new Creator<Listing>() {
        @Override
        public Listing createFromParcel(Parcel source) {
            Listing listing = new Listing();
            listing.listing_id = source.readInt();
            listing.title = source.readString();
            listing.description = source.readString();
            listing.price = source.readString();
            listing.url = source.readString();
            listing.shop = source.readParcelable(Shop.class.getClassLoader());
            listing.images = (Image[]) source.readParcelableArray(Image.class.getClassLoader());
            return listing;
        }

        @Override
        public Listing[] newArray(int size) {
            return new Listing[size];
        }
    };
}

Full ActiveListings class:

package com.example.recommendations.model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by jhuson on 1/22/15.
 */
public class ActiveListings implements Parcelable {

    public int count;
    public Listing[] results;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(count);
        dest.writeParcelableArray(results, 0);
    }

    public static final Creator<ActiveListings> CREATOR = new Creator<ActiveListings>() {
        @Override
        public ActiveListings createFromParcel(Parcel source) {
            ActiveListings activeListings = new ActiveListings();
            activeListings.count = source.readInt();
            activeListings.results = (Listing[]) source.readParcelableArray(Listing.class.getClassLoader());
            return activeListings;
        }

        @Override
        public ActiveListings[] newArray(int size) {
            return new ActiveListings[size];
        }
    };
}

Full Image class:

package com.example.recommendations.model;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by jhuson on 1/22/15.
 */
public class Image implements Parcelable {

    public int rank;
    public int full_height;
    public int full_width;
    public String hex_code;
    public String url_75x75;
    public String url_170x135;
    public String url_570xN;
    public String url_fullxfull;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(rank);
        dest.writeInt(full_height);
        dest.writeInt(full_width);
        dest.writeString(hex_code);
        dest.writeString(url_75x75);
        dest.writeString(url_170x135);
        dest.writeString(url_570xN);
        dest.writeString(url_fullxfull);
    }

    public static final Creator<Image> CREATOR = new Creator<Image>() {
        @Override
        public Image createFromParcel(Parcel source) {
            Image image = new Image();
            image.rank = source.readInt();
            image.full_height = source.readInt();
            image.full_width = source.readInt();
            image.hex_code = source.readString();
            image.url_75x75 = source.readString();
            image.url_170x135 = source.readString();
            image.url_570xN = source.readString();
            image.url_fullxfull = source.readString();
            return image;
        }

        @Override
        public Image[] newArray(int size) {
            return new Image[size];
        }
    };
}

Full MainActivity class:

package com.example.recommendations;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.recommendations.api.ApiKeys;
import com.example.recommendations.model.ActiveListings;
import com.google.android.gms.common.api.Api;

public class MainActivity extends AppCompatActivity {

    private static final String STATE_ACTIVE_LISTINGS = "StateActiveListings";

    private RecyclerView recyclerView;
    private View progressBar;
    private TextView errorView;
    private ListingAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        recyclerView = findViewById(R.id.recyclerView);
        progressBar = findViewById(R.id.progressBar);
        errorView = findViewById(R.id.error_view);

        recyclerView.setLayoutManager(new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL));
        adapter = new ListingAdapter(this);

        recyclerView.setAdapter(adapter);

        if(savedInstanceState == null) {
            showLoading();
            ApiKeys.getActiveListings(adapter);
        } else {
            if(savedInstanceState.containsKey(STATE_ACTIVE_LISTINGS)) {
                adapter.success(savedInstanceState.getParcelable(STATE_ACTIVE_LISTINGS), null);
                showList();
            } else {
                showLoading();
                ApiKeys.getActiveListings(adapter);
            }
        }
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        ActiveListings activeListings = adapter.getActiveListings();
        if(activeListings != null) {
            outState.putParcelable(STATE_ACTIVE_LISTINGS, activeListings);
        }
    }

    public void showLoading() {
        progressBar.setVisibility(View.VISIBLE);
        recyclerView.setVisibility(View.GONE);
        errorView.setVisibility(View.GONE);
    }

    public void showList() {
        progressBar.setVisibility(View.GONE);
        recyclerView.setVisibility(View.VISIBLE);
        errorView.setVisibility(View.GONE);
    }

    public void showError() {
        progressBar.setVisibility(View.GONE);
        recyclerView.setVisibility(View.GONE);
        errorView.setVisibility(View.VISIBLE);
    }
}