-1

I know there are some identical questions but I just couldn't figure out what I'm doing wrong.

public class MainActivity extends AppCompatActivity {
...
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       ...
       new JsonHandler().execute(this, collection, gridArray, customGridAdapter);
       ...
   }
}

So in my main activity I need to query an API which gives back JSON and I have to process that to build my database.

Then in doInBackground() I call getAllCards() which gets the first JSON. Because the JSON includes URLs for more JSON requests, I have a few methods each querying a more detailed JSON.

public final class JsonHandler extends AsyncTask {
private final String urlCards = "https://api.gwentapi.com/v0/cards/";
private final String urlSpecificCard = "https://api.gwentapi.com/v0/cards/:id";

private Context context;
private Collection collection;
private ArrayList<Card> gridArray;
private CustomGridViewAdapter customGridAdapter;

public JsonHandler(Context context, Collection collection, ArrayList<Card> gridArray, CustomGridViewAdapter customGridAdapter){
    this.context = context;
    this.collection = collection;
    this.gridArray = gridArray;
    this.customGridAdapter = customGridAdapter;
}

public JsonHandler(){
    this.context = null;
    this.collection = null;
    this.gridArray = null;
    this.customGridAdapter = null;
}

private void getAllCards() throws RuntimeException {
    JsonObjectRequest arrayRequest = new JsonObjectRequest(Request.Method.GET, urlCards, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            generateCollection(response);
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError e) {
            throw new RuntimeException(e.getMessage());
        }
    });

    Volley.newRequestQueue(context).add(arrayRequest);
}

private void getSpecificCard(final String cardURL) throws RuntimeException {
    JsonObjectRequest arrayRequest = new JsonObjectRequest(Request.Method.GET, cardURL, null, new Response.Listener<JSONObject>() {

        @Override
        public void onResponse(JSONObject response) {
            processCard(response, collection);
        }
    }, new Response.ErrorListener() {

        @Override
        public void onErrorResponse(VolleyError e) {
            throw new RuntimeException(e.getMessage());
        }
    });

    Volley.newRequestQueue(context).add(arrayRequest);
}

private void generateCollection(JSONObject response) throws RuntimeException {
    try {
        JSONArray array = response.getJSONArray("results");
        for(int i = 0; i < array.length();i++){
            JSONObject object = array.getJSONObject(i);
            String cardURL = object.getString("href");
            getSpecificCard(cardURL);
        }
    } catch (Exception e) {
        throw new RuntimeException(e.getMessage());
    }
}

private void processCard(JSONObject response, Collection collection){
    try {
        String id = response.getString("id");
        EnumFaction faction = EnumFaction.valueOf(response.getJSONObject("faction").getString("name").toUpperCase());
        EnumType type = null;
        EnumRarity rarity = null;
        EnumLane lane = null;
        EnumLoyalty loyalty = null;
        String name = response.getString("name");
        String text = response.getString("text");
        String imagePath = "https://api.gwentapi.com/media/\" + id + \"_small.png";

        URL url = new URL(imagePath);
        InputStream inputStream = url.openConnection().getInputStream();
        Bitmap image = BitmapFactory.decodeStream(inputStream);

        Card card = new Card(id, faction, type, rarity, lane, loyalty, name, text, null, imagePath, 0);
        collection.addCard(card);
        gridArray.add(card);
        customGridAdapter.notifyDataSetChanged();
    } catch (Exception e){
        throw new RuntimeException(e.getMessage());
    }
}

@Override
protected Object doInBackground(Object[] params) {
    context = (Context) params[0];
    collection = (Collection) params[1];
    gridArray = (ArrayList<Card>) params[2];
    customGridAdapter = (CustomGridViewAdapter) params[3];
    getAllCards();
    return null;
}

}

So now on to the problem:

When the programm reaches processCard() when I've gathered enough information, I get a NetworkOnMainThreadException when I create the InputStream.

I've tried so many different methods to get a Bitmap from my URL and different methods to do an asynchronous task - all leading to the same result.

If you could show me how to resolve this issue, I'd be sooo happy.

Edit: Since it got marked as duplicate: I AM USING ASYNCTASK! I have looked at many questions and tried what they did there, it doesn't work!

  • You are using Volley. You do not need AsyncTask... – OneCricketeer Nov 04 '16 at 16:10
  • Well I started AsyncTask because it gave me this exception. So I searched the Internet and everybody was saying it needs to be an AsyncTasc. The error still is the same with or without AsyncTask... – Darkmessage Nov 05 '16 at 11:27
  • Your error is because Volleys onResponse happens back on the Main UI... You call `processCard` outside of an AsyncTask. This post **is** a duplicate. The only part `getAllCards` done in the background is adding to the Volley queue. – OneCricketeer Nov 05 '16 at 14:58
  • Ah, ok, I thought if I call a method in an AsyncTask, it would stay there... – Darkmessage Nov 05 '16 at 15:08
  • No worries. All part of learning... You don't need the AsyncTask, like I said, though. The getAllCards method starts a chain of Volley requests, and that's fine. You need to load the Bitmap from a url, so I'd suggest that you look into Volleys ImageLoader https://developer.android.com/training/volley/request.html#request-image – OneCricketeer Nov 05 '16 at 15:12
  • Though, I don't see why you are loading a Bitmap there in your code... You should be doing that from the `getView` method of `customGridAdapter` – OneCricketeer Nov 05 '16 at 15:16
  • Wow, thanks for the tipp with the ImageRequest. I've got the feeling that it loads much quicker now! And I need to get the Bitmaps there because I want to add them to the Cards so that I can save them and don't have to get them from the internet everytime the app starts. So I don't need them solely for the View. – Darkmessage Nov 06 '16 at 11:13
  • I think you just need the image URL string saved on the card, not the whole bitmap. Volley can cache the Bitmap on its own. – OneCricketeer Nov 06 '16 at 13:26
  • But does it cache it even when I close the app (not just put it in the background, but actually killing the process)? – Darkmessage Nov 06 '16 at 15:20
  • That I'm not sure about. Unless you have saved the Bitmap to disk, then neither will storing the Bitmap as part of the object, though – OneCricketeer Nov 06 '16 at 15:27
  • I'm saving my cards to a SQLite DB, meaning the Bitmap is saved as a blob. Then when the user starts the app, I can simply check if he has things in the DB and if not, I can run the JSON. Retrieving the informations from a local DB is faster than always getting it from the internet and also goes easy on the users dataplan. – Darkmessage Nov 06 '16 at 17:42
  • **Don't** save the image as BLOB , save it as real file and stores only the Uri. – Enzokie Nov 12 '16 at 05:45

1 Answers1

0

Not really familiar with how volley works but onResponse but be on the main thread so you need to start a new thread to make that call too

tyczj
  • 71,600
  • 54
  • 194
  • 296
  • But the Json-methods get called from doInBackground which is in a new thread? – Darkmessage Nov 05 '16 at 11:26
  • @Darkmessage the only thing that gets called in the background is your `getAllCards` the callback `onResponse` is called back on the main thread – tyczj Nov 07 '16 at 16:18