我的应用程序有时会崩溃(AsyncTask应该是静态的)

时间:2017-11-22 19:17:50

标签: java android rss

我有一个Android应用程序,显示我的网站的rss,并在有新内容时显示通知。

问题: 我的应用程序有时会崩溃,这是我在Google Play控制台中可以看到的内容:

java.lang.RuntimeException: 
  at android.os.AsyncTask$3.done (AsyncTask.java:318)
  at java.util.concurrent.FutureTask.finishCompletion (FutureTask.java:354)
  at java.util.concurrent.FutureTask.setException (FutureTask.java:223)
  at java.util.concurrent.FutureTask.run (FutureTask.java:242)
  at android.os.AsyncTask$SerialExecutor$1.run (AsyncTask.java:243)
  at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1133)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:607)
  at java.lang.Thread.run (Thread.java:761)

Caused by: java.lang.NullPointerException: 
  at com.mydomain.rss.notification.RssNotificationService$SearchForUpdates.doInBackground (RssNotificationService.java:100)
  at com.mydomain.rss.notification.RssNotificationService$SearchForUpdates.doInBackground (RssNotificationService.java:92)
  at android.os.AsyncTask$2.call (AsyncTask.java:304)
  at java.util.concurrent.FutureTask.run (FutureTask.java:237)

在android studio中,我看到以下消息:

  

此AsyncTask类应该是静态的,否则可能会发生泄漏   (com.mydomain.rss.notification.RssNotificationService.SearchForUpdates)

以下是我需要修改以解决问题的java文件,但我不确定要修改问题需要修改的内容:

package com.mydomain.rss.notification;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import com.mydomain.rss.FeedReaderActivity;
import com.mydomain.rss.R;
import com.mydomain.rss.SettingsActivity;
import com.mydomain.rss.cache.MainActivityContext;
import com.mydomain.rss.cache.RefreshFeed;
import com.mydomain.rss.parser.RSSItem;
import com.mydomain.rss.utility.RSSutility;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.text.Html;

/**
 * RSS Service Executer
 */

public class RssNotificationService extends Service {

    public static final int NOTIFICATION_ID = 1;
    //public static final String TITLE_ERROR = "Notify Error";

    Handler searchHandler = new Handler();
    Timer searchLoader = new Timer();

     @Override
     public void onCreate() {
         super.onCreate();
         boolean is_notification_on = getPrefrenceBoolean(SettingsActivity.NOTIFICATION, false);
         if (is_notification_on){
             new SearchForUpdates().execute();
         }
     }

     @Override
     public IBinder onBind(Intent intent) {
         return null;
     }

     @Override
     public void onRebind(Intent intent) {
     super.onRebind(intent);
     }

     @Override
     public boolean onUnbind(Intent intent) {
     return true;
     }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
       return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public boolean getPrefrenceBoolean(String preference, boolean default_value){
        SharedPreferences sp = getSharedPreferences(this.getPackageName(), Context.MODE_PRIVATE);
        return sp.getBoolean (preference, default_value);
    }

    public void savePrefrenceString(String preference, String value){
        SharedPreferences.Editor editor = getSharedPreferences(this.getPackageName(), Context.MODE_PRIVATE).edit();
        editor.putString(preference, value);
        editor.apply();
    }
    public String getPrefrenceString(String preference, String default_value){
        SharedPreferences sp = getSharedPreferences(this.getPackageName(), Context.MODE_PRIVATE);
        return sp.getString(preference, default_value);
    }

    private class SearchForUpdates extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {

                String lastest_title = getPrefrenceString ("lastTitle", "No feed");

                List<RSSItem> feeds = RSSutility.getRSSFeed(getString(R.string.rss_url));
                RSSItem feed = feeds.get(0);
                String title = feed.getTitle(); 

                if (lastest_title.equalsIgnoreCase(title)){
                    //no update
                }else{
                    showNotification(feed);
                    //store last title so next time will not notify for same rss
                    savePrefrenceString("lastTitle", title);
                }

            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) { 

             boolean is_notification_on = getPrefrenceBoolean(SettingsActivity.NOTIFICATION, false);
             if (is_notification_on){
                //Reload Menu
                long SEARCH_FREQUENCY = Integer.valueOf(getString(R.string.frequency)) * 60 * 1000; 

                searchLoader = new Timer();
                searchLoader.schedule(new TimerTask(){
                    public void run() {
                            searchHandler.post(new Runnable(){
                                public void run(){
                                    new SearchForUpdates().execute();
                                    searchLoader.cancel();
                                }
                            });
                }}, SEARCH_FREQUENCY, SEARCH_FREQUENCY);
             }
        }

        @Override
        protected void onPreExecute() {}

        @Override
        protected void onProgressUpdate(Void... values) {}
    }

    private void showNotification(RSSItem feed) {

        Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_notification);  

        Uri alarmSound = null;
        boolean is_notification_sound_on = getPrefrenceBoolean(SettingsActivity.NOTIFICATION_SOUND, false);
        if (is_notification_sound_on){
            alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        }

        String html = feed.getDescription();
        html = html.replaceAll("<(.*?)\\>", ""); //Removes all items in brackets
        html = html.replaceAll("<(.*?)\\\n", ""); //Must be undeneath
        html = html.replaceFirst("(.*?)\\>", ""); //Removes any connected item to the last bracket
        html = html.replaceAll("&nbsp;", "");
        html = html.replaceAll("&amp;", "");
        html = html.replaceAll("%20", " ");
        html = html.replaceAll("%2C", ", ");
        html = html.replaceAll("%0A", "");

        String title = feed.getTitle();
        title = title.replaceAll("<(.*?)\\>", ""); //Removes all items in brackets
        title = title.replaceAll("<(.*?)\\\n", ""); //Must be undeneath
        title = title.replaceFirst("(.*?)\\>", ""); //Removes any connected item to the last bracket
        title = title.replaceAll("&nbsp;", "");
        title = title.replaceAll("&amp;", "");
        title = title.replaceAll("%20", " ");
        title = title.replaceAll("%2C", ", ");
        title = title.replaceAll("%0A", "");

        //String description = feed.getDescription();

        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                this).setSmallIcon(R.drawable.ic_launcher).setLargeIcon(icon)
                .setContentTitle(feed.getTitle()).setContentText(html)
                .setAutoCancel(true)
                .setSound(alarmSound);

        NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();  
        bigText.bigText(Html.fromHtml(html));  
        bigText.setBigContentTitle(title);  
        bigText.setSummaryText(Html.fromHtml(html));  
        builder.setStyle(bigText);

        Intent intent = new Intent(this, FeedReaderActivity.class);
        intent.putExtra("NOTIFICATION", true);
        intent.putExtra("title", feed.getTitle());
        intent.putExtra("description", feed.getDescription());
        intent.putExtra("link", feed.getLink());
        intent.putExtra("pubDate", feed.getPubdate());
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(contentIntent);

        // Send the notification to the system.
        NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(NOTIFICATION_ID, builder.build());

        if (MainActivityContext.instance().activity!=null){
            MainActivityContext.instance().activity.runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Intent broadcast = new Intent();
                            broadcast.setAction("com.rss.RELOAD_URL");
                            sendBroadcast(broadcast);
                            RefreshFeed.instance().refresh = true;
                        }
                    }, 1000);
                }
            });
        }

    }

}

因此,如果您知道如何解决我的问题,请回复修改。

4 个答案:

答案 0 :(得分:2)

在asyncTask List<RSSItem> feeds中的后台执行时,它的valeo为null我在访问它时feeds.get(0)会导致空指针异常。你的AsyncTask类应该是静态的,所以你只能得到它的一个对象。

答案 1 :(得分:0)

使您的AsyncTask类保持静态。

答案 2 :(得分:0)

要摆脱“AsyncTask应该是静态的”警告,你可以......让你的AsyncTask保持静态。有关如何操作,请参阅我的full answer

正如评论中所指出的,如果AsyncTask到达onPostExecute时Activity不再存在,则应取消更新UI。如果加载RSS源需要很长时间,这很容易发生。这是一个代码片段,显示如果Activity为null,如何取消执行。

@Override
protected void onPostExecute(String result) {

    // get a reference to the activity if it is still there
    MyActivity activity = activityReference.get();

    // if it is gone, then cancel the UI update
    if (activity == null) return;

    // update the UI ...
}

答案 3 :(得分:-1)

AsyncTask的生命周期取决于Activity的生命周期。当活动被破坏时,您将在异步任务上崩溃。在你的情况下,它可以被销毁你正在使用runonuithread的活动。或者你的服务名为onDestroy()和snd异步任务泄露。它与生命周期的行为相同。