【问题标题】:java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()java.lang.NullPointerException:尝试调用虚拟方法'android.content.res.Resources android.content.Context.getResources()
【发布时间】:2016-05-19 13:25:57
【问题描述】:

我正在从网上提取一个 html 页面。该页面包含图像,我使用 UILImageGetter 加载图像。

问题是,如果页面刚刚开始加载并且我多次旋转设备,应用程序会因 NPE 而崩溃。

UILImageGetter

public class UILImageGetter implements Html.ImageGetter{
    Context c;
    TextView container;
    UrlImageDownloader urlDrawable;


    public UILImageGetter(View textView, Context context) {
        this.c = context;
        this.container = (TextView) textView;
    }

    @Override
    public Drawable getDrawable(String source) {
        urlDrawable = new UrlImageDownloader(c.getResources(), source);
        if (Build.VERSION.SDK_INT >= 21) {
        urlDrawable.mDrawable = c.getResources().getDrawable(R.drawable.default_thumb,null);
        } else {
            urlDrawable.mDrawable = c.getResources().getDrawable(R.drawable.default_thumb);
        }
        ImageLoader.getInstance().loadImage(source, new SimpleListener(urlDrawable));
        return urlDrawable;
    }

    private class SimpleListener extends SimpleImageLoadingListener {
        UrlImageDownloader mUrlImageDownloader;

        public SimpleListener(UrlImageDownloader downloader) {
            super();
            mUrlImageDownloader= downloader;
        }

        @Override
        public void onLoadingStarted(String imageUri, View view) {
            Log.d("DEBUG", "onLoadingStarted called");
            //spinner.setVisibility(View.VISIBLE);

        }

        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            //spinner.setVisibility(View.GONE);

            int width = loadedImage.getWidth();
            int height = loadedImage.getHeight();

            int newWidth = width;
            int newHeight = height;

            if (width > container.getWidth()) {
                newWidth = container.getWidth();
                newHeight = (newWidth * height) / width;
            }

            if (view != null) {
                container.getLayoutParams().width = newWidth;
                container.getLayoutParams().height = newHeight;
            }

            Drawable result = new BitmapDrawable(c.getResources(), loadedImage);
            result.setBounds(0, 0, newWidth, newHeight);

            mUrlImageDownloader.setBounds(1, 1, newWidth, newHeight);
            mUrlImageDownloader.mDrawable = result;
            container.invalidate();

            container.setText(container.getText());

        }

        @Override
        public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
            String message = null;
            switch (failReason.getType()) {
                case IO_ERROR:
                    message = "Input/Output error";
                    break;
                case DECODING_ERROR:
                    message = "Image can't be decoded";
                    break;
                case NETWORK_DENIED:
                    message = "Downloads are denied";
                    break;
                case OUT_OF_MEMORY:
                    message = "Out Of Memory error";
                    break;
                case UNKNOWN:
                    message = "Unknown error";
                    break;
            }
            Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
            //spinner.setVisibility(View.GONE);
        }
    }

    private class UrlImageDownloader extends BitmapDrawable {
        public  Drawable mDrawable;

        public UrlImageDownloader(Resources resources, String filepath) {
            super(resources, filepath);
            mDrawable = new BitmapDrawable(resources, filepath);
        }

        @Override
        public void draw(Canvas canvas) {
            if (mDrawable != null) {
                mDrawable.draw(canvas);
            }
        }
    }
}

DetailsFragment

public class DetailsFragment extends Fragment implements ObservableScrollViewCallbacks{


    private AlertDialog internetDialog;
    private AlertDialog sthWrongAlert;
    private String url;

    private String birdData;

    private final String TAG = "DetailsFragment";
    protected com.nostra13.universalimageloader.core.ImageLoader mImageLoader;


    TextView birdContent;
    public DetailsFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        url = getArguments().getString("bird_link");

        // Inflate the layout for this fragment
        view =  inflater.inflate(R.layout.fragment_details, container, false);

        showDialog();
        sthWrongDialog();

        gadContent = (TextView) view.findViewById(R.id.gad_content);


        DisplayImageOptions defaultoptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getActivity())
                .defaultDisplayImageOptions(defaultoptions)
                .writeDebugLogs()
                .build();


        mImageLoader = com.nostra13.universalimageloader.core.ImageLoader.getInstance();
        mImageLoader.init(config);





        if (savedInstanceState != null) {
            birdData = savedInstanceState.getString("birdData");
            if (birdData != null) {
                parseHtml(birdData);
            } 
            } else if (NetworkCheck.isAvailableAndConnected(getActivity())){
                    loadBird();
                } 
            }
        } else {
            if (NetworkCheck.isAvailableAndConnected(getActivity())) {
                    loadGad();
                }
            } else {
                internetDialog.show();
            }
        }
        return view;
    }


    public interface OnLinkClickedListener {
        public void OnLinkClicked (String link);
    }

    private static OnLinkClickedListener sLinkCallbacks = new OnLinkClickedListener() {
        @Override
        public void OnLinkClicked(String link) {

        }
    };


    private void showDialog() {
        internetDialog = new AlertDialog.Builder(getActivity())
                // The usuals
                .create();
    }

    private void sthWrongDialog() {
        sthWrongAlert = new AlertDialog.Builder(getActivity())
                // The usuals
                .create();
    }

    private void loadBird() {
        Log.d(TAG, "loadBird called");

        final ProgressBar progressBar;
        progressBar = (ProgressBar) view.findViewById(R.id.progress_circle);
        progressBar.setVisibility(View.VISIBLE);


//        String news_id = getIntent().getStringExtra("BirdId");
        Log.d(TAG, "You clicked bird id " + url);

        StringRequest stringRequest = new StringRequest(url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        //Log.d("Debug", response.toString());
                        if (progressBar != null) {
                            progressBar.setVisibility(View.GONE);
                        }
                        parseHtml(response);
                        birdData = response;


                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        VolleyLog.d(TAG, "Error: " + error.getMessage());

                        if (progressBar != null) {
                            progressBar.setVisibility(View.GONE);
                        }
                        if (sthWrongAlert != null) {
                            sthWrongAlert.show();
                        }


                    }
                });

        //Creating requestqueue
        RequestQueue requestQueue = Volley.newRequestQueue(getActivity());

        //Adding request queue
        requestQueue.add(stringRequest);
    }

    private void parseHtml(String response) {
        Log.d(TAG, "parsinghtml");
        Document document = Jsoup.parse(response);
        bird_content = document.select("div.entry-content").first().html();
        setTextViewHTML(birdContent, bird_content);
    protected void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span)
    {
        int start = strBuilder.getSpanStart(span);
        int end = strBuilder.getSpanEnd(span);
        int flags = strBuilder.getSpanFlags(span);
        ClickableSpan clickable = new ClickableSpan() {
            public void onClick(View view) {
                Log.e(TAG, "on click" + span.getURL());
            }
        };
        strBuilder.setSpan(clickable, start, end, flags);
        strBuilder.removeSpan(span);
    }

    protected void setTextViewHTML(TextView text, String html) {
        CharSequence sequence = Html.fromHtml(html, new UILImageGetter(birdContent, getActivity()), null);
        SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence);
        URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class);
        for(URLSpan span : urls) {
            makeLinkClickable(strBuilder, span);
        }
        text.setText(strBuilder);
        text.setMovementMethod(LinkMovementMethod.getInstance());
    }

       @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (birdData != null) {
            outState.putString("birdData", birdData);
        }

        if (internetDialog != null) {
            outState.putBundle("internetDialog", internetDialog.onSaveInstanceState());
        }
        if (sthWrongAlert != null) {
            outState.putBundle("sthWrongAlert", sthWrongAlert.onSaveInstanceState());
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null) {
            if (internetDialog != null) {
                internetDialog.onRestoreInstanceState(savedInstanceState.getBundle("internetDialog"));
            }
            if (sthWrongAlert != null) {
                sthWrongAlert.onRestoreInstanceState(savedInstanceState.getBundle("sthWrongAlert"));

            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy called");
        if (mImageLoader.isInited()) {
            mImageLoader.destroy();
        }


        if (internetDialog != null){
            internetDialog.dismiss();
            internetDialog = null;
        }
        if (sthWrongAlert != null) {
            sthWrongAlert.dismiss();
            sthWrongAlert = null;
        }
    }

}

堆栈跟踪

05-19 13:37:14.936 12213-12213/com.pexample.birds E/AndroidRuntime: FATAL EXCEPTION: main
                                                                     Process: com.pexample.birds, PID: 12213
                                                                     java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
                                                                         at com.pexample.birds.UILImageGetter.getDrawable(UILImageGetter.java:39)
                                                                         at android.text.HtmlToSpannedConverter.startImg(Html.java:634)
                                                                         at android.text.HtmlToSpannedConverter.handleStartTag(Html.java:520)
                                                                         at android.text.HtmlToSpannedConverter.startElement(Html.java:761)
                                                                         at org.ccil.cowan.tagsoup.Parser.push(Parser.java:794)
                                                                         at org.ccil.cowan.tagsoup.Parser.rectify(Parser.java:1061)
                                                                         at org.ccil.cowan.tagsoup.Parser.stagc(Parser.java:1016)
                                                                         at org.ccil.cowan.tagsoup.HTMLScanner.scan(HTMLScanner.java:624)
                                                                         at org.ccil.cowan.tagsoup.Parser.parse(Parser.java:449)
                                                                         at android.text.HtmlToSpannedConverter.convert(Html.java:442)
                                                                         at android.text.Html.fromHtml(Html.java:136)
                                                                         at com.pexample.birds.DetailsFragment.setTextViewHTML(DetailsFragment.java:400)
                                                                         at com.pexample.birds.DetailsFragment.parseHtml(DetailsFragment.java:350)
                                                                         at com.pexample.birds.DetailsFragment.access$500(DetailsFragment.java:48)
                                                                         at com.pexample.birds.DetailsFragment$6.onResponse(DetailsFragment.java:291)
                                                                         at com.pexample.birds.DetailsFragment$6.onResponse(DetailsFragment.java:284)
                                                                         at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60)
                                                                         at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30)
                                                                         at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
                                                                         at android.os.Handler.handleCallback(Handler.java:739)
                                                                         at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                         at android.os.Looper.loop(Looper.java:135)
                                                                         at android.app.ActivityThread.main(ActivityThread.java:5910)
                                                                         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:1405)
                                                                         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)

从堆栈跟踪中,UILImageGetter 中的第 39 行是 urlDrawable = new UrlImageDownloader(c.getResources(), source);,第 400 行对应于 CharSequence sequence = Html.fromHtml(html, new UILImageGetter(birdContent, getActivity()), null); 行 在DetailsFragment中。

请问,我该如何解决这个问题?

请不要a duplicate of this question。我知道什么是 NPE 以及导致它的原因,也许我错了,但我也知道我必须在 urlDrawable = new UrlImageDownloader(c.getResources(), source); 行之前检查资源是否为空,但我只是不知道该怎么做。我在这里迷路了,请帮助我。


编辑

onCreate of hosting Activity

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


        getWindow().getDecorView().setBackgroundColor(Color.WHITE);

        String bird_id = getIntent().getStringExtra("BirdId");
        Log.d(TAG,  bird_id);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        if (savedInstanceState == null) {
            Bundle bundle = new Bundle();
            Fragment fragment;

            fragment = new DetailsFragment();
            bundle.putString("bird_link", bird_id);
            fragment.setArguments(bundle);

            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.setCustomAnimations(android.R.anim.slide_out_right, android.R.anim.slide_in_left, android.R.anim.slide_out_right, android.R.anim.slide_in_left);
            ft.add(R.id.post_frame, fragment);
            ft.commit();
        }

        if (savedInstanceState != null) {
            mContent = getSupportFragmentManager().getFragment(savedInstanceState, "mContent");
        }



    }

【问题讨论】:

  • 问题是你的上下文本身是空的。你在传递什么作为上下文?
  • @RageshRamesh,上下文在哪里,片段或实用程序类?
  • 问题是您的DetailsFragment.getActivity() 正在返回null。这可能是出于多种不同的原因,因此最好的办法是将代码发布到您将片段附加到活动的位置。
  • @exantas 我对此表示怀疑。即使在一个 Activity 中,当我在数据完全加载之前多次旋转时,我仍然会得到这个 NPE。
  • 但以防万一,我在活动的onCreate 中进行片段事务。

标签: android nullpointerexception


【解决方案1】:

当您从纵向转移到横向时,您的活动将重新开始。当您第一次启动时,您的上下文不为空,但是当您更改屏幕时,您的上下文将为空,您的应用程序将崩溃。我建议您只需在清单文件中设置屏幕方向肖像。 像这样

<activity
        android:name="..."
        android:label="@string/app_name"
        android:screenOrientation="portrait"/>

【讨论】:

  • 我不想绕过这个问题;而是我想修复它。
  • 然后我想当你在menifest.xml 中设置肖像时,它是否有效?我认为当你从 url 下载图片时,毕加索图书馆会更好
  • 我希望活动轮换,先生
【解决方案2】:

由于您的上下文在某些事件中为空,因此您需要在片段的onAttach(mcontext) 中更新上下文,还有其他方法可以解决此问题:

1) 使用Fragment.setRetainInstance(true)保留片段实例

2) 在清单中针对活动使用此标志以摆脱它android:configChanges="orientation|screenSize|keyboardHidden"

【讨论】:

    【解决方案3】:

    我创建了新的类来检查网络连接是否可用,并且还使用了 BroadcastReceiver。

    ConnectivityStatus.java

     public class ConnectivityStatus extends ContextWrapper {
    public ConnectivityStatus(Context base) {
        super(base);
    }
    
    //checking for network connection
    public static boolean isNetworkAvailable(Context context) {
        try {
            ConnectivityManager connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        /*
                if connected or connecting in network then return true
         */
            return networkInfo != null && networkInfo.isConnectedOrConnecting();
        }
       catch (NullPointerException e)
       {
           return false;
       }
    }}
    

    DealerLocator.java

    public class DealerLocator extends Fragment {
    FragmentDealerLocatorBinding fragmentDealerLocatorBinding;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        getContext().registerReceiver(broadcastReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); //for checking network connection
    
        // Inflate the layout for this fragment
        fragmentDealerLocatorBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_dealer_locator, container, false);
        return fragmentDealerLocatorBinding.getRoot();
    }
    
    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (!ConnectivityStatus.isNetworkAvailable(getContext())) {
                Toast.makeText(context,"No Connection is available", Toast.LENGTH_SHORT).show();
            } else {
                    //if connection available then write your code here
            }
        }
    };
    }
    

    DealerLocator 是扩展 Fragment 的类,我在此类中检查了网络连接的条件。 通常在 Toast 中第一个参数是 getContext(),但对于扩展 Fragment 的类,我已将该参数更改为上下文,可从 public void onReceive(Context context, Intent intent) 方法访问。因此,使用此代码,我的应用程序可以完美运行。

    我在 Manifest 文件中添加了三个权限用于检查网络连接

     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-12
      • 2020-03-08
      • 2018-04-03
      • 2020-10-31
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 2015-12-10
      相关资源
      最近更新 更多