我正在从网上抓一个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)
在堆栈跟踪中,第39行在 UILImageGetter 中为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");
}
}
答案 0 :(得分:0)
当您从纵向转移到横向时,您的活动将重新启动。当你第一次开始时,你的上下文不是null,但是当你更改屏幕时,你的上下文将为null,你的应用程序将崩溃。我建议你只需在清单文件中设置屏幕方向肖像。 像这样
<activity
android:name="..."
android:label="@string/app_name"
android:screenOrientation="portrait"/>
答案 1 :(得分:0)
由于您的上下文在某些事件中为空,因此您需要更新片段&amp;的onAttach(mcontext)中的上下文。还有其他方法可以摆脱这个问题:
1)使用android:configChanges="orientation|screenSize|keyboardHidden"
2)在清单中使用此标志反对活动以摆脱它double total = db.tblCustomerOrders.Where(x => x.CustomerID == customer.CustomerID).Select(t => t.Amount ?? 0).Sum();
答案 2 :(得分:0)
我已经创建了新的Class,用于检查网络连接是否可用,还使用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的Class,我将该参数更改为上下文,可以从public void onReceive(Context context, Intent intent)
方法访问。因此,使用此代码,我的应用程序运行完美。
我在清单文件中添加了三个权限来检查网络连接
<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" />