0

I have code that gets an image by its name from drawables, but for some reason it can't update it.

package com.infonuascape.osrshelper.fragments;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.media.Image;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.toolbox.ImageLoader;
import com.infonuascape.osrshelper.R;
import com.infonuascape.osrshelper.activities.MainActivity;
import com.infonuascape.osrshelper.models.Account;

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

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class BankViewFragment extends OSRSFragment {
    private static final String TAG = "BankViewFragment";

    private static Account account;
    private ListView lv;
    private ImageView iv;
    Handler handler;

    ArrayList<HashMap<String, String>> ItemList;

    public static BankViewFragment newInstance(final Account account) {
        BankViewFragment fragment = new BankViewFragment();
        Bundle b = new Bundle();
        fragment.setArguments(b);
        return fragment;
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        View view = inflater.inflate(R.layout.bank_view, null);
        ItemList = new ArrayList<>();
        new GetItems().execute();
        lv = (ListView) view.findViewById(R.id.list);
        handler = new Handler(Looper.getMainLooper());
        SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
        String nikas = sharedPref.getString("bankname", "null");
        return view;
    }

    public static int getResId(String resourceName, Class<?> c) {
        try {
            Field idField = c.getDeclaredField(resourceName);
            return idField.getInt(idField);
        } catch (Exception e) {
            throw new RuntimeException("No resource ID found for: "
                    + resourceName + " / " + c, e);
        }
    }

    private class GetItems extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... arg0) {
            HttpHandler sh = new HttpHandler();
            SharedPreferences sharedpreferences = getContext().getSharedPreferences("minescape", Context.MODE_PRIVATE);
            String nikas = sharedpreferences.getString("bankname",  "null");
            String url = "https://api.minesca.pe/game/classic/stats?username=" + nikas;
            String jsonStr = sh.makeServiceCall(url);

            Log.e(TAG, "NIKAS: " + nikas);
            Log.e(TAG, "ACCOUNT: " + account);
            Log.e(TAG, "Response from url: " + jsonStr);
            if (jsonStr != null) {
                try {
                    JSONObject jsonObj = new JSONObject(jsonStr);
                    JSONObject items = jsonObj.getJSONObject("bank");
                    Iterator keys = items.keys();
                    while(keys.hasNext()) {
                        String dynamicKey = (String)keys.next();
                        JSONObject line = items.getJSONObject(dynamicKey);
                        String item = line.getString("item");
                        //Integer image = getResId(item, Drawable.class);
                        final Integer image = getResources().getIdentifier(item, "drawable", getActivity().getPackageName());
                        String amount = line.getString("amount");
                        Log.e(TAG, "DAIKTAS: " + item);
                        Log.e(TAG, "KIEKIS: " + amount);
                        HashMap<String, String> contact = new HashMap<>();
                        String itembank = item.replaceAll("i_", "");
                        String itembanks = itembank.replaceAll("_", " ");
                        contact.put("name", itembanks);
                        contact.put("email", amount);
                        LayoutInflater inflater = LayoutInflater.from(getContext());
                        View view = inflater.inflate(R.layout.bank_view, null);
                        lv = (ListView) view.findViewById(R.id.list);
                       // iv = (ImageView) view.findViewById(R.id.logo);
                        final ImageView ims = (ImageView) lv.findViewById(R.id.logo);
                        handler.post(new Runnable() {
                            public void run() {
                                if(image != null) {
                                    Log.e(TAG, "kas cia jam netinka?: " + image);
                                    if(image == 0) {
                                        ims.setImageResource(R.drawable.i_noted);
                                        Log.e(TAG, "kas cia jam netinka?: " + image);
                                    } else {
                                        Log.e(TAG, "kas cia jam netinka?: " + image);
                                        ims.setImageResource(image);
                                    }
                                } else {
                                    Log.e(TAG, "null?: " + image);
                                }
                            }
                        });
                        ItemList.add(contact);
                    }
                } catch (final JSONException e) {
                    Log.e(TAG, "Json parsing error: " + e.getMessage());
                    new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(getContext(),
                                    "Json parsing error: " + e.getMessage(),
                                    Toast.LENGTH_LONG).show();
                        }
                    };

                }

            } else {
                Log.e(TAG, "Couldn't get json from server.");
                new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getContext(),
                                "Couldn't get json from server!",
                                Toast.LENGTH_LONG).show();
                    }
                };
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            ListAdapter adapter = new SimpleAdapter(getContext(), ItemList,
                    R.layout.list_item, new String[]{ "email","name"},
                    new int[]{R.id.email, R.id.name});
            lv.setAdapter(adapter);
        }
    }

}

Error:

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: com.infonuascape.osrshelper, PID: 31024
              java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference
                  at com.infonuascape.osrshelper.fragments.BankViewFragment$GetItems$1.run(BankViewFragment.java:128)
                  at android.os.Handler.handleCallback(Handler.java:815)
                  at android.os.Handler.dispatchMessage(Handler.java:104)
                  at android.os.Looper.loop(Looper.java:194)
                  at android.app.ActivityThread.main(ActivityThread.java:5637)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at java.lang.reflect.Method.invoke(Method.java:372)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:959)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:754)

The problem is that there's a lot of items, and most of them have the resources, but some don't and i would like to just skip those who don't have, but the main problem is that the app crashes while trying to see the bank.

  • 2
    The `doInBackground()` method run on a background thread. You cannot do any UI related work from there. There are millions of example on how to handle that properly. – Distwo Feb 07 '18 at 19:30

2 Answers2

2

You can't change Views in a non UI thread.
So in order to fix your problem just access UI related stuff in the UI thread, e.g. in onPostExecute()

Bö macht Blau
  • 12,820
  • 5
  • 40
  • 61
Jarik Eng
  • 310
  • 2
  • 10
  • Thanks, this does help, but now i get `java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageResource(int)' on a null object reference ` error. – Rokas Ščesnavičius Feb 08 '18 at 08:45
  • You'r trying to find view R.id.logo on list view ImageView ims = (ImageView) lv.findViewById(R.id.logo); but as far as I see you've already bind it in onCreateView which is 'iv' – Jarik Eng Feb 08 '18 at 08:51
  • Thanks, I have updated the code and error I get in the original post. – Rokas Ščesnavičius Feb 08 '18 at 09:16
  • Why do you need in while loop inflate view and then on that view find listView? You should move than code to onCreateView all view inflate related code should not be in AsyncTask – Jarik Eng Feb 08 '18 at 10:25
  • And what ImageView your trying to find on ListView? Please explain what you'r trying to achieve – Jarik Eng Feb 08 '18 at 10:26
  • Im getting images from string, so that's why they're in loop. Why i am trying to do is display different image for each item in bank. – Rokas Ščesnavičius Feb 08 '18 at 10:30
  • Yes, but there is no need to do it all in background. Just find all you Views in onCreateView method, then in your loop collect all your items , image ,identifiers or whatever your iterating through to ArrayList and then return it from doInBackground method to onPostExecute, afterwards pass it to ListView`s adapter .e.g ArrayAdapter – Jarik Eng Feb 08 '18 at 11:32
0

Do not do this : View should not be touched in another thread except UI thread.

@Override protected void onPostExecute(Void result) { -->>>>> DONOT DO THIS --->>>>>lv.setAdapter(adapter); }

niketshah09
  • 470
  • 3
  • 8
  • This is wrong. While it is true that views should not be touched in another thread than the UI one, what you propose is wrong. AsyncTasks are meant to be used this way. The onPostExecute will run on the UI Thread. Please take a look at the documentation https://developer.android.com/reference/android/os/AsyncTask.html – Charles Feb 08 '18 at 21:52