2

I've created a database to store ExoPlayer's seek time so when the user tries to play the same content, if it is in the database, then it will ask the user to resume or start again but getting NullPointerException.

Here's the Database:


public class DatabaseHelper extends SQLiteOpenHelper {

   private static final int DATABASE_VERSION = 1;
   private static final String DATABASE_NAME = "mydata.db";

   private static final String EPISODE_TABLE_NAME = "episode_data";

   public DatabaseHelper(Context context) {
       super(context, DATABASE_NAME, null, DATABASE_VERSION);
   }

   @Override
   public void onCreate(SQLiteDatabase db) {
       db.execSQL(CREATE_EPISODE_DATA_TABLE());
   }

   
   private String CREATE_EPISODE_DATA_TABLE() {
       return "CREATE TABLE IF NOT EXISTS episode_data (id TEXT,timestamp TEXT)";
   }

   @Override
   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
       db.execSQL("DROP TABLE IF EXISTS episode_data");
       onCreate(db);
   }

   public String getEpisodeData(String string2) {
       SQLiteDatabase sQLiteDatabase = this.getReadableDatabase();
       StringBuilder stringBuilder = new StringBuilder();
       stringBuilder.append("SELECT * FROM episode_data WHERE id= ");
       stringBuilder.append(string2);
       Cursor cursor = sQLiteDatabase.rawQuery(stringBuilder.toString(), null);
       String string3 = null;
       if (cursor != null) {
           boolean bl = cursor.moveToLast();
           string3 = null;
           if (bl) {
               string3 = cursor.getString(cursor.getColumnIndex("timestamp"));
           }
           cursor.close();
       }
       return string3;
   }

   public long insertEpisodeData(String string2, String string3) {
       SQLiteDatabase sQLiteDatabase = this.getWritableDatabase();
       ContentValues contentValues = new ContentValues();
       contentValues.put("id", string2);
       contentValues.put("timestamp", string3);
       long l = sQLiteDatabase.replace(EPISODE_TABLE_NAME, null, contentValues);
       sQLiteDatabase.close();
       return l;
   }

}

The activity where it stores the data from and also crashes:

public class ShowsDetailsActivity extends AppCompatActivity {

    public String episodeid;
    DatabaseHelper databaseHelper;

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

       databaseHelper = new DatabaseHelper(this);

        // My rest of the code
   }

   public void iniMoviePlayerForEpisode(EpiModel epiModel,Context context){

       ShowsDetailsActivity.epiModel =epiModel;
       String type=epiModel.getServerType();
       
  if (type.equals("embed") || type.equals("vimeo") || type.equals("gdrive")){
           isVideo=false;
           initWeb(epiModel.getStreamURL());
       }else {
           isVideo=true;
           initVideoPlayer(epiModel.getStreamURL(),context,type);
       }

       }
   }

   public void setMediaUrlForTvSeries(String url, String season, String episod, String episode_id) {
       mediaUrl = url;
       this.season = season;
       this.episod = episod;
       this.episodeid = episode_id;
   }


   public void initVideoPlayer(String url, Context context, String type) {
       progressBar.setVisibility(VISIBLE);

       if (player != null) {
           player.release();
       }

       BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
       TrackSelection.Factory videoTrackSelectionFactory = new
               AdaptiveTrackSelection.Factory(bandwidthMeter);


       TrackSelector trackSelector = new
               DefaultTrackSelector(videoTrackSelectionFactory);

       player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);

       simpleExoPlayerView.setPlayer(player);
       player.prepare(mediaSource, true, false);

       player.addListener(new Player.DefaultEventListener() {

           @Override
           public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {

               if (playWhenReady && playbackState == Player.STATE_READY) {

                   isPlaying = true;
                   progressBar.setVisibility(View.GONE);

               } else if (playbackState == Player.STATE_READY) {

                   progressBar.setVisibility(View.GONE);
                   isPlaying = false;

                   if (player != null) {
                       StringBuilder stringBuilder = new StringBuilder();
                       stringBuilder.append("episode id: ");
                       stringBuilder.append(episodeid);
                       stringBuilder.append(" TimeStamp: ");
                       stringBuilder.append(player.getCurrentPosition() / 1000L);
                       databaseHelper.insertEpisodeData(episodeid, String.valueOf((long)player.getCurrentPosition()));
                   }

               } else if (playbackState == Player.STATE_BUFFERING) {
                   isPlaying = false;
                   progressBar.setVisibility(VISIBLE);

               } else {
                   isPlaying = false;

                   if (player != null) {
                       StringBuilder stringBuilder = new StringBuilder();
                       stringBuilder.append("episode id: ");
                       stringBuilder.append(episodeid);
                       stringBuilder.append(" TimeStamp: ");
                       stringBuilder.append(player.getCurrentPosition() / 1000L);
                       databaseHelper.insertEpisodeData(episodeid, String.valueOf((long)player.getCurrentPosition()));
                   }
               }

           }
       });

       String getPlayed = databaseHelper.getEpisodeData(episodeid);
       if (getPlayed != null) {
           showResumeAlert();
           return;
       }
       player.setPlayWhenReady(true);

   }

   private void showResumeAlert () {
       new AlertDialog.Builder(this)
               .setTitle("Do you want to resume from where you left ?")
               .setPositiveButton("Resume", new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialog, int which) {

                       String getPlayed = databaseHelper.getEpisodeData(episodeid);
                       if (getPlayed != null) {
                           player.seekTo(Long.parseLong(getPlayed));
                           player.setPlayWhenReady(true);
                       }
                   }
               })
               .setNegativeButton("Start Again", new DialogInterface.OnClickListener() {
                   @Override
                   public void onClick(DialogInterface dialog, int which) {
                       player.setPlayWhenReady(true);
                   }
               })
               .setCancelable(false)
               .show();
   }

    // My rest of the code

}

The adapter:

public class DirectorApater extends RecyclerView.Adapter<DirectorApater.OriginalViewHolder> {

   private List<EpiModel> items;
   private Context ctx;

   int selectedPosition=-1;
   private int seasonNo;


   public DirectorApater(Context context, List<EpiModel> items,String name, int seasonNo) {
       ArrayList<EpiModel> arrayList=new ArrayList<>();
       for(int i=0;i<items.size();i++){
           if(items.get(i).getSeson().equals(name)){
               arrayList.add(items.get(i));
           }
       }

       items.clear();
       this.items = arrayList;
       this.seasonNo = seasonNo;

       ctx = context;
   }


   @Override
   public DirectorApater.OriginalViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
       DirectorApater.OriginalViewHolder vh;
       View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_director_name, parent, false);
       vh = new DirectorApater.OriginalViewHolder(v);
       return vh;
   }

   @Override
   public void onBindViewHolder(final DirectorApater.OriginalViewHolder holder, final int position) {
       final EpiModel obj = items.get(position);

       holder.llEpi.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               selectedPosition=position;
               notifyDataSetChanged();
               ((ShowsDetailsActivity)ctx).setMediaUrlForTvSeries(obj.getStreamURL(), obj.getSeson(), obj.getEpi(), obj.getEpisode_id());

 if (!castSession) {
                   new ShowsDetailsActivity().iniMoviePlayerForEpisode(obj,ctx);
               } else {
                   ((ShowsDetailsActivity)ctx).showQueuePopup(ctx, holder.llEpi, ((ShowsDetailsActivity)ctx).getMediaInfo());

               }
           }
       });

   }
   
   @Override
   public int getItemCount() {
       return items.size();
   }

   public class OriginalViewHolder extends RecyclerView.ViewHolder {

       // some code

       public OriginalViewHolder(View v) {
           super(v);
            // some code
       }
   }

So basically when a user clicks on the recyclerview item, it passes the data to the activity class "(ShowsDetailsActivity)ctx).setMediaUrlForTvSeries(obj.getStreamURL(), obj.getSeson(), obj.getEpi(), obj.getEpisode_id());"

App works fine without

 String getPlayed = databaseHelper.getEpisodeData(episodeid);
        if (getPlayed != null) {
            showResumeAlert();
            return;
        }

in ShowsDetailsActivity class but crashes with this error log when I add it:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.myapp.db.DatabaseHelper.getEpisodeData(java.lang.String)' on a null object reference

7
  • Where are you calling iniMoviePlayerForEpisode? Commented Aug 28, 2020 at 21:08
  • @puelo because API sends video in two formats, one is web (embed) which loads in a webview, and the other is a normal video that plays in ExoPlayer. Commented Aug 28, 2020 at 21:10
  • @puelo check my edit, I added the method. I had to remove to avoid character limit Commented Aug 28, 2020 at 21:12
  • I am still not seeing where iniMoviePlayerForEpisode is being called. You only added the complete body of it. Commented Aug 28, 2020 at 21:13
  • @puelo sorry, check my edit, I'm calling it from my adapter Commented Aug 28, 2020 at 21:19

1 Answer 1

4

You are calling the iniMoviePlayerForEpisode method here:

new ShowsDetailsActivity().iniMoviePlayerForEpisode(obj,ctx);

but at that point onCreate was not yet called and thus your databaseHelper is still null. Check the reference i linked: onCreate is called when your Activity starts, not when the object is created.

Sign up to request clarification or add additional context in comments.

5 Comments

I just tried but crashes with the same error. databaseHelper also saves the content details which works fine so it's not null. The only issue I have is with episodeid string.
@puelo looks correct. I didn't see any place where you call onCreate with the current state obj and context obj. So, you still have a null databaseHelper object.
@StevenRõgrê If you mean insertEpisodeData, then this works because it is only called in a callback for a listener, not directly inside the iniMoviePlayerForEpisode method. The callback is probably called when the activity is already started.
@puelo ok so what do you suggest I do here? I've been trying to figure this out for hours and can't wrap my head around.
i am not that versed when it comes to Android, but you probably could try to make your databaseHelper a singleton, like mentioned here: guides.codepath.com/android/… and then access it freely. Other suggestion: Move the creation of the databaseHelper instance to the constructor instead of onCreate

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.