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
iniMoviePlayerForEpisode?iniMoviePlayerForEpisodeis being called. You only added the complete body of it.