I'm loading json file from online and saving it on Sqlite such that when app is offline...Then still user will be able to see the data.
It works fine in MainActivity.
But when I try to covert it into fragment, I'm getting errors of Fragment cannot be cast in to FlowerAdapter$FlowerClickListener
Here is the error file
My Fragment name is nepali.
Here is the Mainactivity
public class MainActivity extends AppCompatActivity implements FlowerAdapter.FlowerClickListener, FlowerFetchListener {
private static final String TAG = MainActivity.class.getSimpleName();
private RecyclerView mRecyclerView;
private RestManager mManager;
private FlowerAdapter mFlowerAdapter;
private FlowerDatabase mDatabase;
private Button mReload;
private ProgressDialog mDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configViews();
mManager = new RestManager();
mDatabase = new FlowerDatabase(this);
loadFlowerFeed();
mReload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadFlowerFeed();
}
});
}
private void loadFlowerFeed() {
mDialog = new ProgressDialog(MainActivity.this);
mDialog.setMessage("Loading Flower Data...");
mDialog.setCancelable(true);
mDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mDialog.setIndeterminate(true);
mFlowerAdapter.reset();
mDialog.show();
if (getNetworkAvailability()) {
getFeed();
} else {
getFeedFromDatabase();
}
}
private void getFeedFromDatabase() {
mDatabase.fetchFlowers(this);
}
private void configViews() {
mReload = (Button) findViewById(R.id.reload);
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.VERTICAL, false));
mFlowerAdapter = new FlowerAdapter(this);
mRecyclerView.setAdapter(mFlowerAdapter);
}
#Override
public void onClick(int position) {
}
public void getFeed() {
Call<List<Flower>> listCall = mManager.getFlowerService().getAllFlowers();
listCall.enqueue(new Callback<List<Flower>>() {
#Override
public void onResponse(Call<List<Flower>> call, Response<List<Flower>> response) {
if (response.isSuccessful()) {
List<Flower> flowerList = response.body();
for (int i = 0; i < flowerList.size(); i++) {
Flower flower = flowerList.get(i);
SaveIntoDatabase task = new SaveIntoDatabase();
task.execute(flower);
mFlowerAdapter.addFlower(flower);
}
} else {
int sc = response.code();
switch (sc) {
case 400:
Log.e("Error 400", "Bad Request");
break;
case 404:
Log.e("Error 404", "Not Found");
break;
default:
Log.e("Error", "Generic Error");
}
}
mDialog.dismiss();
}
#Override
public void onFailure(Call<List<Flower>> call, Throwable t) {
mDialog.dismiss();
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public boolean getNetworkAvailability() {
return Utils.isNetworkAvailable(getApplicationContext());
}
#Override
public void onDeliverAllFlowers(List<Flower> flowers) {
}
#Override
public void onDeliverFlower(Flower flower) {
mFlowerAdapter.addFlower(flower);
}
#Override
public void onHideDialog() {
mDialog.dismiss();
}
public class SaveIntoDatabase extends AsyncTask<Flower, Void, Void> {
private final String TAG = SaveIntoDatabase.class.getSimpleName();
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Flower... params) {
Flower flower = params[0];
try {
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
}
}
and FlowerDatabase class is
public class FlowerDatabase extends SQLiteOpenHelper {
private static final String TAG = FlowerDatabase.class.getSimpleName();
public FlowerDatabase(Context context) {
super(context, Constants.DATABASE.DB_NAME, null, Constants.DATABASE.DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
try {
db.execSQL(Constants.DATABASE.CREATE_TABLE_QUERY);
} catch (SQLException ex) {
Log.d(TAG, ex.getMessage());
}
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(Constants.DATABASE.DROP_QUERY);
this.onCreate(db);
}
public void addFlower(Flower flower) {
Log.d(TAG, "Values Got " + flower.getName());
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Constants.DATABASE.PRODUCT_ID, flower.getProductId());
values.put(Constants.DATABASE.CATEGORY, flower.getCategory());
values.put(Constants.DATABASE.PRICE, Double.toString(flower.getPrice()));
values.put(Constants.DATABASE.INSTRUCTIONS, flower.getInstructions());
values.put(Constants.DATABASE.NAME, flower.getName());
try {
db.insert(Constants.DATABASE.TABLE_NAME, null, values);
} catch (Exception e) {
}
db.close();
}
public void fetchFlowers(FlowerFetchListener listener) {
FlowerFetcher fetcher = new FlowerFetcher(listener, this.getWritableDatabase());
fetcher.start();
}
public class FlowerFetcher extends Thread {
private final FlowerFetchListener mListener;
private final SQLiteDatabase mDb;
public FlowerFetcher(FlowerFetchListener listener, SQLiteDatabase db) {
mListener = listener;
mDb = db;
}
#Override
public void run() {
Cursor cursor = mDb.rawQuery(Constants.DATABASE.GET_FLOWERS_QUERY, null);
final List<Flower> flowerList = new ArrayList<>();
if (cursor.getCount() > 0) {
if (cursor.moveToFirst()) {
do {
Flower flower = new Flower();
flower.setFromDatabase(true);
flower.setName(cursor.getString(cursor.getColumnIndex(Constants.DATABASE.NAME)));
flower.setPrice(Double.parseDouble(cursor.getString(cursor.getColumnIndex(Constants.DATABASE.PRICE))));
flower.setInstructions(cursor.getString(cursor.getColumnIndex(Constants.DATABASE.INSTRUCTIONS)));
flower.setCategory(cursor.getString(cursor.getColumnIndex(Constants.DATABASE.CATEGORY)));
flower.setProductId(Integer.parseInt(cursor.getString(cursor.getColumnIndex(Constants.DATABASE.PRODUCT_ID))));
flowerList.add(flower);
publishFlower(flower);
} while (cursor.moveToNext());
}
}
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
mListener.onDeliverAllFlowers(flowerList);
mListener.onHideDialog();
}
});
}
public void publishFlower(final Flower flower) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
mListener.onDeliverFlower(flower);
}
});
}
}
}
and FlowerAdapter Class is
public class FlowerAdapter extends RecyclerView.Adapter<FlowerAdapter.Holder> {
private static final String TAG = FlowerAdapter.class.getSimpleName();
private final FlowerClickListener mListener;
private List<Flower> mFlowers;
public FlowerAdapter(FlowerClickListener listener) {
mFlowers = new ArrayList<>();
mListener = listener;
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item, null, false);
return new Holder(row);
}
#Override
public void onBindViewHolder(Holder holder, int position) {
Flower currFlower = mFlowers.get(position);
holder.mName.setText(currFlower.getName());
holder.minstruction.setText(currFlower.getInstructions());
}
#Override
public int getItemCount() {
return mFlowers.size();
}
public void addFlower(Flower flower) {
mFlowers.add(flower);
notifyDataSetChanged();
}
/**
* #param position
* #return
*/
public Flower getSelectedFlower(int position) {
return mFlowers.get(position);
}
public void reset() {
mFlowers.clear();
notifyDataSetChanged();
}
public class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView mName, minstruction;
public Holder(View itemView) {
super(itemView);
mName = (TextView) itemView.findViewById(R.id.flowerName);
minstruction = (TextView) itemView.findViewById(R.id.flowerPrice);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
mListener.onClick(getLayoutPosition());
}
}
public interface FlowerClickListener {
void onClick(int position);
}
}
My fragment class is that I try to convert above Mainactivity code into Frament class is
public class nepali extends Fragment {
private static final String TAG = nepali.class.getSimpleName();
private RecyclerView mRecyclerView;
private RestManager mManager;
private FlowerAdapter mFlowerAdapter;
private FlowerDatabase mDatabase;
private Button mReload;
private ProgressDialog mDialog;
View view;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.activity_data, container, false);
configViews();
mManager = new RestManager();
mDatabase = new FlowerDatabase(getActivity());
loadFlowerFeed();
mReload.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadFlowerFeed();
}
});
return view;
}
private void loadFlowerFeed() {
mDialog = new ProgressDialog(getActivity());
mDialog.setMessage("Loading Flower Data...");
mDialog.setCancelable(true);
mDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mDialog.setIndeterminate(true);
mFlowerAdapter.reset();
mDialog.show();
if (getNetworkAvailability()) {
getFeed();
} else {
getFeedFromDatabase();
}
}
private void getFeedFromDatabase() {
mDatabase.fetchFlowers(this);
}
private void configViews() {
mReload = (Button) view.findViewById(R.id.reload);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
mFlowerAdapter = new FlowerAdapter((FlowerAdapter.FlowerClickListener) this);;
mRecyclerView.setAdapter(mFlowerAdapter);
}
public void getFeed() {
Call<List<Flower>> listCall = mManager.getFlowerService().getAllFlowers();
listCall.enqueue(new Callback<List<Flower>>() {
#Override
public void onResponse(Call<List<Flower>> call, Response<List<Flower>> response) {
if (response.isSuccessful()) {
List<Flower> flowerList = response.body();
for (int i = 0; i < flowerList.size(); i++) {
Flower flower = flowerList.get(i);
SaveIntoDatabase task = new SaveIntoDatabase();
task.execute(flower);
mFlowerAdapter.addFlower(flower);
}
} else {
int sc = response.code();
switch (sc) {
case 400:
Log.e("Error 400", "Bad Request");
break;
case 404:
Log.e("Error 404", "Not Found");
break;
default:
Log.e("Error", "Generic Error");
}
}
mDialog.dismiss();
}
#Override
public void onFailure(Call<List<Flower>> call, Throwable t) {
mDialog.dismiss();
Toast.makeText(getActivity(), t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
public boolean getNetworkAvailability() {
return Utils.isNetworkAvailable(getActivity());
}
public void onDeliverFlower(Flower flower) {
mFlowerAdapter.addFlower(flower);
}
public void onHideDialog() {
mDialog.dismiss();
}
public class SaveIntoDatabase extends AsyncTask<Flower, Void, Void> {
private final String TAG = SaveIntoDatabase.class.getSimpleName();
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Flower... params) {
Flower flower = params[0];
try {
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
return null;
}
}
}
Lastly the FlowerService class is
public interface FlowerService {
#GET("/routine/first.json")
Call<List<Flower>> getAllFlowers();
}
and FlowerFetchListener Class is
public interface FlowerFetchListener {
void onDeliverAllFlowers(List<Flower> flowers);
void onDeliverFlower(Flower flower);
void onHideDialog();
}
Please Help....and Thanks in advance.
You should not call db and network from activity or fragment. Try to learn MVVM architecture and use ViewModel to store the data from db or network. You may put a lot of effort making your app work but it will still lead to crashes (especially after you introduce fragment and call db and API from there). You will need to handle your data state during configuration changes. Listen to this talk and start writing clean code https://m.youtube.com/watch?v=5qlIPTDE274
The error you get is because you pass wrong parameter into adapter constructor ‘new FlowerAdapter((FlowerAdapter.FlowerClickListener) this)’. If you want to pass a listener to the adapter you need to pass the class which implements the listener: either activity - then pass getActivity(), or fragment ‘this’ - then make fragment implement implements FlowerAdapter.FlowerClickListener.Be aware that it can be null when fragment is not attached to activity, eg configuration change.
Related
I'm having a problem, that maybe we can solve it and help the community. I have made an Adapter for my RecyclerView and I have created a listener for the constraint layout in order to remove one element of the list. As you can see in the code the delete message works well but I don't know how to update the RecyclerView from the AccountFragment (the one that's using this adapter). Does anyone know how to notify that changes?
AccountFragment:
public class AccountFragment extends Fragment {
private TextView textViewUserProfileUsername;
private TextView textViewUserProfileDescription;
private ImageButton imageButtonAccountEdit;
private EditText editTextAccountDescription;
private RecyclerView recyclerViewUserProfileComments;
private TextView textViewUserProfileNoComments;
private ImageView imageViewUserProfileSendMessage;
private EditText editTextUserProfileSendMessage;
private final Gson gson = new Gson();
private User userLocal;
private SharedPreferences sharedPreferences;
private Context context;
private AlertDialog dialog;
private String previousDescription;
private AccountCommentsAdapter accountCommentsAdapter;
private final List<UserComments> userCommentsList = new ArrayList<>();
public AccountFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getActivity();
assert context != null;
sharedPreferences = context.getSharedPreferences(Constants.sharedPreferencesDocName, Context.MODE_PRIVATE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_account, container, false);
}
#Override
public void onViewCreated(#NonNull #NotNull View view, #Nullable #org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
bindUI(view);
setListeners();
userLocal = gson.fromJson(sharedPreferences.getString("user", ""), User.class);
showUserInformation();
setAdapter();
}
private void bindUI(View view) {
textViewUserProfileUsername = view.findViewById(R.id.textViewUserProfileUsername);
textViewUserProfileDescription = view.findViewById(R.id.textViewUserProfileDescription);
imageButtonAccountEdit = view.findViewById(R.id.imageButtonAccountEdit);
recyclerViewUserProfileComments = view.findViewById(R.id.recyclerViewUserProfileComments);
textViewUserProfileNoComments = view.findViewById(R.id.textViewUserProfileNoComments);
imageViewUserProfileSendMessage = view.findViewById(R.id.imageViewUserProfileSendMessage);
editTextUserProfileSendMessage = view.findViewById(R.id.editTextUserProfileSendMessage);
}
private void setListeners() {
imageButtonAccountEdit.setOnClickListener(v -> showEditDescriptionDialog());
imageViewUserProfileSendMessage.setOnClickListener(view -> {
if (!TextUtils.isEmpty(editTextUserProfileSendMessage.getText().toString())) {
final Date currentTime = new Date();
#SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
TimeZone timeZone = simpleDateFormat.getTimeZone();
simpleDateFormat.setTimeZone(timeZone);
String date = simpleDateFormat.format(currentTime);
final UserComments userCommentsToAdd = new UserComments(userLocal.getId(), userLocal.getId(), userLocal.getUsername(), userLocal.getUsername(), editTextUserProfileSendMessage.getText().toString().trim(), date);
editTextUserProfileSendMessage.setText("");
addComment(userCommentsToAdd);
}
});
}
private void showUserInformation() {
textViewUserProfileUsername.setText(userLocal.getUsername());
textViewUserProfileDescription.setText(userLocal.getDescription());
getUserComments();
}
private void showEditDescriptionDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(getString(R.string.edit_description));
final View customLayout = getLayoutInflater().inflate(R.layout.alert_dialog_edit_account, null);
builder.setView(customLayout);
dialog = builder.create();
editTextAccountDescription = customLayout.findViewById(R.id.editTextAccountDescription);
if (userLocal.getDescription() != null) {
editTextAccountDescription.setText(userLocal.getDescription());
previousDescription = editTextAccountDescription.getText().toString();
}
Button buttonAccountCancelDescription = customLayout.findViewById(R.id.buttonAccountCancelDescription);
Button buttonAccountSaveDescription = customLayout.findViewById(R.id.buttonAccountSaveDescription);
buttonAccountSaveDescription.setOnClickListener(v -> saveUserDescription());
buttonAccountSaveDescription.setOnClickListener(v -> {
if (editTextAccountDescription.getText().toString().length() <= 150) {
saveUserDescription();
} else {
setErrors(2);
}
});
editTextAccountDescription.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() > 150) {
setErrors(2);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
buttonAccountCancelDescription.setOnClickListener(v -> dialog.dismiss());
dialog.setCancelable(false);
dialog.show();
}
private void saveUserDescription() {
if (!editTextAccountDescription.getText().toString().isEmpty()) {
if (!editTextAccountDescription.getText().toString().equals(previousDescription)) {
userLocal.setDescription(editTextAccountDescription.getText().toString());
sharedPreferences.edit().putString("user", gson.toJson(userLocal)).apply();
Thread thread = new Thread() {
#Override
public void run() {
Response response;
try {
response = UserRequests.editUserDescription(userLocal.getId(), userLocal.getDescription());
if (response.code() == 200) {
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
if (responseBody.contains("1")) {
updateDescription();
} else if (responseBody.contains("2")) {
updateDescription();
} else {
setErrors(1);
}
} else {
setErrors(1);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
} else {
setErrors(4);
}
} else {
setErrors(3);
}
}
private void updateDescription() {
Thread thread = new Thread() {
public void run() {
requireActivity().runOnUiThread(() -> {
textViewUserProfileDescription.setText(userLocal.getDescription());
dialog.dismiss();
});
}
};
thread.start();
}
private void setErrors(int error) {
switch (error) {
case 1:
Thread thread = new Thread() {
public void run() {
requireActivity().runOnUiThread(() -> Toast.makeText(context, getString(R.string.generic_error), Toast.LENGTH_SHORT).show());
}
};
thread.start();
break;
case 2:
editTextAccountDescription.setError(getString(R.string.description_length));
editTextAccountDescription.requestFocus();
break;
case 3:
editTextAccountDescription.setError(getString(R.string.required_field));
editTextAccountDescription.requestFocus();
break;
case 4:
dialog.dismiss();
break;
}
}
private void setAdapter() {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
linearLayoutManager.setStackFromEnd(true);
recyclerViewUserProfileComments.setLayoutManager(linearLayoutManager);
recyclerViewUserProfileComments.scrollToPosition(userCommentsList.size() - 1);
}
private void displayMessages() {
if (userCommentsList.size() > 0) {
Thread thread = new Thread() {
public void run() {
requireActivity().runOnUiThread(() -> {
if (recyclerViewUserProfileComments.getVisibility() == View.GONE) {
recyclerViewUserProfileComments.setVisibility(View.VISIBLE);
}
if (textViewUserProfileNoComments.getVisibility() == View.VISIBLE) {
textViewUserProfileNoComments.setVisibility(View.GONE);
}
accountCommentsAdapter = new AccountCommentsAdapter(context, userCommentsList);
recyclerViewUserProfileComments.setAdapter(accountCommentsAdapter);
recyclerViewUserProfileComments.scrollToPosition(userCommentsList.size() - 1);
accountCommentsAdapter.notifyDataSetChanged();
});
}
};
thread.start();
} else {
Thread thread = new Thread() {
public void run() {
requireActivity().runOnUiThread(() -> {
recyclerViewUserProfileComments.setVisibility(View.GONE);
textViewUserProfileNoComments.setVisibility(View.VISIBLE);
});
}
};
thread.start();
}
}
private void addComment(UserComments userCommentsToAdd) {
Thread thread = new Thread() {
#Override
public void run() {
Response response;
try {
response = UserCommentsRequests.addUserComment(userCommentsToAdd);
if (response.code() == 200) {
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
if (responseBody.contains("1")) {
userCommentsList.add(userCommentsToAdd);
userCommentsList.clear();
getUserComments();
}
} else if (response.code() == 204) {
displayMessages();
} else {
setErrors(1);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
}
private void getUserComments() {
Thread thread = new Thread() {
#Override
public void run() {
Response response;
try {
response = UserCommentsRequests.getUserComments(userLocal.getId());
if (response.code() == 200) {
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
JSONArray responseArray = new JSONArray(responseBody);
for (int i = 0; i < responseArray.length(); i++) {
String jsonObjectString = responseArray.getJSONObject(i).toString();
userCommentsList.add(gson.fromJson(jsonObjectString, UserComments.class));
}
displayMessages();
} else if (response.code() == 204) {
displayMessages();
} else {
setErrors(1);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
}
}
AccountCommentsAdapter:
public class AccountCommentsAdapter extends RecyclerView.Adapter<AccountCommentsAdapter.AccountCommentsAdapterViewHolder> {
private final Context context;
List<UserComments> userCommentsList;
public static final int MSG_TYPE_LEFT = 0;
public static final int MSG_TYPE_RIGHT = 1;
public AccountCommentsAdapter(Context context, List<UserComments> userCommentsList) {
this.context = context;
this.userCommentsList = userCommentsList;
}
#NonNull
#NotNull
#Override
public AccountCommentsAdapterViewHolder onCreateViewHolder(#NonNull #NotNull ViewGroup parent, int viewType) {
View view;
if (viewType == MSG_TYPE_RIGHT) {
view = LayoutInflater.from(context).inflate(R.layout.fragment_chat_message_sent, parent, false);
} else {
view = LayoutInflater.from(context).inflate(R.layout.fragment_chat_message_received, parent, false);
}
return new AccountCommentsAdapterViewHolder(view);
}
#Override
public int getItemViewType(int position) {
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
assert firebaseUser != null;
if (userCommentsList.get(position).getUser_from_username().equals(firebaseUser.getDisplayName())) {
return MSG_TYPE_RIGHT;
} else {
return MSG_TYPE_LEFT;
}
}
#Override
public void onBindViewHolder(#NonNull #NotNull AccountCommentsAdapterViewHolder holder, int position) {
UserComments userComments = userCommentsList.get(position);
int viewType = holder.getItemViewType();
if (viewType == MSG_TYPE_LEFT) {
holder.textViewMessageUsername.setText(userComments.getUser_from_username());
holder.textViewMessageUsername.setOnClickListener(v -> {
Intent intent = new Intent(context, UserProfileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle bundle = new Bundle();
bundle.putString("userId", userComments.getUser_from_id());
bundle.putString("username", userComments.getUser_from_username());
intent.putExtras(bundle);
context.startActivity(intent);
});
holder.constraintLayoutMessageRight.setOnLongClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.delete_message)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> deleteMessage(position))
.setNegativeButton(R.string.no, (dialogInterface, which) -> dialogInterface.dismiss());
builder.create();
builder.show();
return false;
});
} else {
holder.constraintLayoutMessageRight.setOnLongClickListener(v -> {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(R.string.delete_message)
.setPositiveButton(R.string.yes, (dialogInterface, i) -> deleteMessage(position))
.setNegativeButton(R.string.no, (dialogInterface, which) -> dialogInterface.dismiss());
builder.create();
builder.show();
return false;
});
}
holder.textViewMessageMessage.setText(userComments.getMessage());
holder.textViewMessageTime.setText(userComments.getCreated_time());
}
#Override
public int getItemCount() {
return userCommentsList.size();
}
public static class AccountCommentsAdapterViewHolder extends RecyclerView.ViewHolder {
ConstraintLayout constraintLayoutMessageRight;
TextView textViewMessageMessage;
TextView textViewMessageTime;
TextView textViewMessageUsername;
public AccountCommentsAdapterViewHolder(#NonNull #NotNull View itemView) {
super(itemView);
textViewMessageMessage = itemView.findViewById(R.id.textViewMessageMessage);
textViewMessageTime = itemView.findViewById(R.id.textViewMessageTime);
constraintLayoutMessageRight = itemView.findViewById(R.id.constraintLayoutMessageRight);
textViewMessageUsername = itemView.findViewById(R.id.textViewMessageUsername);
}
}
private void deleteMessage(int position) {
UserComments userCommentsToRemove = userCommentsList.get(position);
Thread thread = new Thread() {
#Override
public void run() {
Response response;
try {
response = UserCommentsRequests.removeUserComments(userCommentsToRemove.getId());
if (response.code() == 200) {
String responseBody = Objects.requireNonNull(response.body()).string();
responseBody = responseBody.replace("\r\n", "");
if (responseBody.contains("1")) {
userCommentsList.remove(position);
// Here it should update the recyclerview in order to notify that element has been removed.
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
thread.start();
}
}
UPDATE:
Solved by adding this method and then call it after userCommentsList.remove(position):
private void updateUI(){
Handler mainHandler = new Handler(context.getMainLooper());
Runnable runnable = this::notifyDataSetChanged;
mainHandler.post(runnable);
}
Inside the adapter you can use notifyDataSetChanged()
I'm making a simple app that has to make a call to an API that returns an object with some attributes and is shown in a RecyclerView.
The call is being made to https://jsonplaceholder.typicode.com/photos?_start=0&_limit=5
The app doesn't crash, the recyclerview is being generated but it is empty. I used the debugger and saw that the list in the adapter of the recyclerview is empty (the size is 0).
I believe the issue is with the structure of the java objects I made but I can't confirm it for sure and I can't seem to modify my object structure to match that of the returned object. I'm not seeing an object with other objects inside of like with other apis I've worked on (when I check the above link with a json online reader).
I usually make my object and another object container (which has a list of the first object). My suspicion is that the issue is there, please help me find the problem.
Below the main activity, object, object container, adapter, retrofit object, object dao and object controller.
Activity:
public class PhotoActivity extends AppCompatActivity implements AdapterPhotoRecyclerView.SelectedPhotoListener {
private AdapterPhotoRecyclerView adapterPhotoRecyclerView;
private RecyclerView recyclerView;
private ProgressBar progressBar;
private LinearLayoutManager linearLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo);
linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
progressBar = findViewById(R.id.photo_activity_progress_bar);
makeCall("photos?_start=0&_limit=5");
adapterPhotoRecyclerView = new AdapterPhotoRecyclerView(this);
recyclerView = findViewById(R.id.photo_activity_recyclerview);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapterPhotoRecyclerView);
}
public void makeCall(String fixedUrl) {
MyPhotoController myPhotoController = new MyPhotoController();
myPhotoController.getPhotos(fixedUrl, new ResultListener<MyPhotoContainer>() {
#Override
public void finish(MyPhotoContainer result) {
progressBar.setVisibility(View.VISIBLE);
adapterPhotoRecyclerView.setMyPhotoList(result.getmPhotoList());
progressBar.setVisibility(View.GONE);
}
});
}
#Override
public void selectePhoto(Integer position, List<MyPhoto> myPhotoList) {
MyPhoto clickedPhoto = myPhotoList.get(position);
Toast.makeText(this, clickedPhoto.getTitle(), Toast.LENGTH_SHORT).show();
}
}
Adapter of the RecyclerView
public class AdapterPhotoRecyclerView extends RecyclerView.Adapter<AdapterPhotoRecyclerView.PhotoViewHolder> {
private List<MyPhoto> myPhotoList;
private SelectedPhotoListener selectedPhotoListener;
public AdapterPhotoRecyclerView(SelectedPhotoListener selectedPhotoListener) {
myPhotoList = new ArrayList<>();
this.selectedPhotoListener = selectedPhotoListener;
}
public void setMyPhotoList(List<MyPhoto> myPhotoList) {
this.myPhotoList = myPhotoList;
notifyDataSetChanged();
}
public List<MyPhoto> getMyPhotoList() {
return myPhotoList;
}
#NonNull
#Override
public PhotoViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_cell_photo, parent, false);
PhotoViewHolder photoViewHolder = new PhotoViewHolder(view);
return photoViewHolder;
}
#Override
public void onBindViewHolder(#NonNull PhotoViewHolder holder, int position) {
MyPhoto myPhoto = myPhotoList.get(position);
holder.bindPhoto(myPhoto);
}
#Override
public int getItemCount() {
if (myPhotoList == null){
return 0;
} else {
return myPhotoList.size();
}
}
public class PhotoViewHolder extends RecyclerView.ViewHolder {
private ImageView thumbnail;
private TextView title;
public PhotoViewHolder(#NonNull View itemView) {
super(itemView);
this.thumbnail = itemView.findViewById(R.id.recyclerview_cell_photo_thumbnail);
this.title = itemView.findViewById(R.id.recyclerview_cell_photo_title);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPhotoListener.selectePhoto(getAdapterPosition(), myPhotoList);
}
});
}
public void bindPhoto(MyPhoto myPhoto) {
Glide.with(itemView).load(myPhoto.getThumbnailUrl()).placeholder(R.mipmap.ic_launcher).into(thumbnail);
title.setText(myPhoto.getTitle());
}
}
public interface SelectedPhotoListener {
public void selectePhoto(Integer position, List<MyPhoto> myPhotoList);
}
}
Object dao
public class MyPhotoDao extends MyRetrofit {
private JsonPlaceholderService service;
public MyPhotoDao() {
super("https://jsonplaceholder.typicode.com/");
service = retrofit.create(JsonPlaceholderService.class);
}
public void getPhotos(String fixedUrl, final ResultListener<MyPhotoContainer> listenerOfTheController) {
Call<MyPhotoContainer> call = service.jsonPlaceholderPhoto(fixedUrl);
call.enqueue(new Callback<MyPhotoContainer>() {
#Override
public void onResponse(Call<MyPhotoContainer> call, Response<MyPhotoContainer> response) {
MyPhotoContainer myPhotoContainer = response.body();
listenerOfTheController.finish(myPhotoContainer);
}
#Override
public void onFailure(Call<MyPhotoContainer> call, Throwable t) {
}
});
}
public void getAlbum(String fixedUrl, final ResultListener<List<Album>> listenerOfTheController){
Call<List<Album>> call = service.jsonPlaceholderAlbum(fixedUrl);
call.enqueue(new Callback<List<Album>>() {
#Override
public void onResponse(Call<List<Album>> call, Response<List<Album>> response) {
List<Album> albumList = response.body();
listenerOfTheController.finish(albumList);
}
#Override
public void onFailure(Call<List<Album>> call, Throwable t) {
}
});
}
}
Object controller
public class MyPhotoController {
public void getPhotos(String fixedUrl, final ResultListener<MyPhotoContainer> listenerOfTheView) {
MyPhotoDao myPhotoDao = new MyPhotoDao();
myPhotoDao.getPhotos(fixedUrl, new ResultListener<MyPhotoContainer>() {
#Override
public void finish(MyPhotoContainer result) {
listenerOfTheView.finish(result);
}
});
}
public void getAlbums(String fixedUrl, final ResultListener<List<Album>> listenerOfTheView){
MyPhotoDao myPhotoDao = new MyPhotoDao();
myPhotoDao.getAlbum(fixedUrl, new ResultListener<List<Album>>() {
#Override
public void finish(List<Album> result) {
listenerOfTheView.finish(result);
}
});
}
}
Retrofit object
public abstract class MyRetrofit {
protected Retrofit retrofit;
public MyRetrofit(String baseUrl) {
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient.build())
.addConverterFactory(GsonConverterFactory.create());
retrofit = builder.build();
}
}
Object I'm trying to GET
public class MyPhoto implements Serializable {
#SerializedName("AlbumId")
private Integer albumNumber;
#SerializedName("id")
private Integer photoId;
private String title;
#SerializedName("url")
private String photoUrl;
private String thumbnailUrl;
public Integer getAlbumNumber() {
return albumNumber;
}
public Integer getPhotoId() {
return photoId;
}
public String getTitle() {
return title;
}
public String getPhotoUrl() {
return photoUrl;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
}
Object container
public class MyPhotoContainer implements Serializable {
#SerializedName("array")
private List<MyPhoto> mPhotoList;
public List<MyPhoto> getmPhotoList() {
return mPhotoList;
}
}
If there is anything missing please let me know.
Any help and comments are apreciated!
JSON payload does not fit to POJO classes. You do not need to use MyPhotoContainer class at all. Response JSON is a JSON Array with directly placed JSON Objects. getPhotos method should look similar to getAlbum method. Try:
public void getPhotos(String fixedUrl, final ResultListener<List<MyPhoto>> listenerOfTheView)
I have tried to implement a user list with pagination using paging library. But despite being able to fetch all data from back-end, the PagedList is null while observing LiveData.
Here are the codes.
UserModel.java
class User{
#SerializedName("user_id")
public int user_id;
#SerializedName("username")
public String username;
#SerializedName("name")
public String name;
#SerializedName("familyname")
public String familyname;
#SerializedName("pp_dir")
public String pp_url; }
public class UserModel {
#SerializedName("users")
public List<User> list;
#SerializedName("last_page")
public boolean lastPage;
#SerializedName("total_page")
public int totalPage;
#SerializedName("total_user_count")
public int totalUserCount;}
UserSearchDataSource.java
public class UserSearchDataSource extends ItemKeyedDataSource<Integer, User> {
public static final int PAGE_SIZE = 15;
private static final int FIRST_PAGE = 1;
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<User> callback) {
RetrofitClient.getInstance().getApi().getAllUsers(FIRST_PAGE, PAGE_SIZE).enqueue(new Callback<UserModel>() {
#Override
public void onResponse(Call<UserModel> call, Response<UserModel> response) {
if (response.body() != null) {
callback.onResult(response.body().list);
System.out.println(response.body().list);
}
else {
System.out.println(response.code());
System.out.println(response.message());
}
}
#Override
public void onFailure(Call<UserModel> call, Throwable t) {
System.out.println(t.getMessage());
}
});
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<User> callback) {
RetrofitClient.getInstance().getApi().getAllUsers(FIRST_PAGE, PAGE_SIZE).enqueue(new Callback<UserModel>() {
#Override
public void onResponse(Call<UserModel> call, Response<UserModel> response) {
if (response.body() != null) {
//Integer key = response.body().lastPage ? null : params.key + 1;
callback.onResult(response.body().list);
}
}
#Override
public void onFailure(Call<UserModel> call, Throwable t) {
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<User> callback) {
RetrofitClient.getInstance().getApi().getAllUsers(FIRST_PAGE, PAGE_SIZE).enqueue(new Callback<UserModel>() {
#Override
public void onResponse(Call<UserModel> call, Response<UserModel> response) {
if (response.body() != null) {
//Integer key = (params.key > 1) ? params.key - 1 : null;
callback.onResult(response.body().list);
}
else {
System.out.println(response.message());
}
}
#Override
public void onFailure(Call<UserModel> call, Throwable t) {
System.out.println(t.getMessage());
}
});
}
#NonNull
#Override
public Integer getKey(#NonNull User item) {
return item.user_id;
} }
UserSearchDataSourceFactory.java
public class UserSearchDataSourceFactory extends DataSource.Factory<Integer, User> {
private MutableLiveData<UserSearchDataSource> userLiveDataSource = new MutableLiveData<>();
public UserSearchDataSourceFactory() {
}
#NonNull
#Override
public DataSource<Integer, User> create() {
UserSearchDataSource dataSource = new UserSearchDataSource();
userLiveDataSource.postValue(dataSource);
return dataSource;
}
public MutableLiveData<UserSearchDataSource> getUserLiveDataSource() {
return userLiveDataSource;
} }
UserSearchAdapter.java
public class UserSearchAdapter extends PagedListAdapter<User, UserSearchAdapter.ViewHolder> {
private Context context;
UserSearchAdapter(Context context) {
super(DIFF_CALLBACK);
this.context = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.user_item, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
User model = getItem(position);
if (model != null) {
Picasso.get().load(model.pp_url).into(holder.userPp);
holder.tvUsername.setText(model.username);
holder.tvFullname.setText(model.name.concat(" ").concat(model.familyname));
}
else {
Toast.makeText(context, "Item is null", Toast.LENGTH_LONG).show();
}
}
private static DiffUtil.ItemCallback<User> DIFF_CALLBACK = new DiffUtil.ItemCallback<User>() {
#Override
public boolean areItemsTheSame(#NonNull User oldItem, #NonNull User newItem) {
return oldItem.user_id == newItem.user_id;
}
#SuppressLint("DiffUtilEquals")
#Override
public boolean areContentsTheSame(#NonNull User oldItem, #NonNull User newItem) {
return oldItem.equals(newItem);
}
};
public class ViewHolder extends RecyclerView.ViewHolder {
ImageView userPp;
TextView tvUsername, tvFullname;
public ViewHolder(#NonNull View itemView) {
super(itemView);
userPp = itemView.findViewById(R.id.image_user);
tvUsername = itemView.findViewById(R.id.tv_username);
tvFullname = itemView.findViewById(R.id.tv_fullname);
}
} }
UserSearchViewModel.java
public class UserSearchViewModel extends AndroidViewModel {
private LiveData<PagedList<User>> userPagedList;
LiveData<UserSearchDataSource> liveDataSource;
public UserSearchViewModel(Application application) {
super(application);
}
public LiveData<PagedList<User>> getUserPagedList() {
UserSearchDataSourceFactory userSearchDataSourceFactory = new UserSearchDataSourceFactory();
liveDataSource = userSearchDataSourceFactory.getUserLiveDataSource();
PagedList.Config config = (new PagedList.Config.Builder())
.setEnablePlaceholders(true)
.setPageSize(UserSearchDataSource.PAGE_SIZE)
.build();
userPagedList = new LivePagedListBuilder<>(userSearchDataSourceFactory, config).build();
return userPagedList;
} }
UserSearchFragment.java
mViewModel.getUserPagedList().observe(this, (PagedList<User> users) -> {
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
adapter = new UserSearchAdapter(getContext());
adapter.submitList(users);
recyclerView.setAdapter(adapter);
//System.out.println(users.get(0).name);
});
I use this code to play the full-screen video but I have a problem when it is video playing and moving from the main activity to the full-screen activity occurs freezing of the video for 2-3 seconds This problem occurs only with the releases after 2.8.3 only but with 2.8.0 works Video is smooth
code full: https://github.com/MATPOCKIH/ExoPlayerFullscreen
PlayerViewManager
public class PlayerViewManager {
private static final String TAG = "ExoPlayerViewManager";
public static final String EXTRA_VIDEO_URI = "video_uri";
private static Map<String, PlayerViewManager> instances = new HashMap<>();
private Uri videoUri;
public boolean isPlayerPlaying;
private boolean isMustPlaying;
private UniversalPlayerView universalPlayer;
public static PlayerViewManager getInstance(String videoUri) {
PlayerViewManager instance = instances.get(videoUri);
if (instance == null) {
instance = new PlayerViewManager(videoUri);
instances.put(videoUri, instance);
}
return instance;
}
private PlayerViewManager(String videoUri) {
this.videoUri = Uri.parse(videoUri);
}
public void preparePlayer(PlayerHolderView playerHolderView) {
if (playerHolderView == null) {
return;
}
if (universalPlayer == null) {
universalPlayer = createPlayer(playerHolderView.getContext());
isPlayerPlaying = true;
isMustPlaying = true;
}
universalPlayer.initialize(videoUri, playerHolderView);
}
public void releaseVideoPlayer() {
if (universalPlayer != null) {
universalPlayer.release();
}
universalPlayer = null;
}
public void goToBackground() {
if (universalPlayer != null /*&& !isMustPlaying*/) {
//isPlayerPlaying = player.getPlayWhenReady();
universalPlayer.pause();
}
}
public void goToForeground() {
if (universalPlayer != null && isMustPlaying) {
universalPlayer.play();
}
}
public void pausePlayer(){
if (universalPlayer != null) {
universalPlayer.pause();
isPlayerPlaying = false;
isMustPlaying = false;
}
}
public void playPlayer(){
if (universalPlayer != null) {
universalPlayer.play();
isPlayerPlaying = true;
isMustPlaying = true;
}
}
private UniversalPlayerView createPlayer(Context context){
if (videoUri.getScheme().startsWith("http")){
return new FaceterExoPlayerView(context);
}
return new FaceterExoPlayerView(context);
}
}
FaceterExoPlayerView
public class FaceterExoPlayerView extends UniversalPlayerView {
private Uri videoUri;
private DefaultDataSourceFactory dataSourceFactory;
private SimpleExoPlayer player;
private PlayerView exoPlayerView;
private Context context;
public FaceterExoPlayerView(Context context) {
this.context = context;
}
#Override
public void initialize(Uri videoUri, PlayerHolderView playerHolderView) {
if (playerHolderView == null || videoUri == null)
return;
exoPlayerView = playerHolderView.findViewById(R.id.exo_player);
if (player == null) {
player = ExoPlayerFactory.newSimpleInstance(context, new DefaultTrackSelector());
dataSourceFactory = new DefaultDataSourceFactory(context,
Util.getUserAgent(context, "faceter"));
MediaSource videoSource = buildMediaSource(videoUri, null);
player.prepare(videoSource);
}
player.clearVideoSurface();
player.setVideoTextureView((TextureView) exoPlayerView.getVideoSurfaceView());
exoPlayerView.setPlayer(player);
exoPlayerView.hideController();
setResizeModeFill(playerHolderView.isResizeModeFill());
}
#Override
public void play() {
player.setPlayWhenReady(true);
}
#Override
public void pause() {
player.setPlayWhenReady(false);
}
#SuppressWarnings("unchecked")
private MediaSource buildMediaSource(Uri uri, #Nullable String overrideExtension) {
int type = Util.inferContentType(uri, overrideExtension);
switch (type) {
/*case C.TYPE_DASH:
return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false))
.setManifestParser(
new FilteringManifestParser<>(
new DashManifestParser(), (List<RepresentationKey>) getOfflineStreamKeys(uri)))
.createMediaSource(uri);
case C.TYPE_SS:
return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false))
.setManifestParser(
new FilteringManifestParser<>(
new SsManifestParser(), (List<StreamKey>) getOfflineStreamKeys(uri)))
.createMediaSource(uri);*/
case C.TYPE_HLS:
return new HlsMediaSource.Factory(dataSourceFactory)
/*.setPlaylistParser(
new FilteringManifestParser<>(
new HlsPlaylistParser(), (List<RenditionKey>) getOfflineStreamKeys(uri)))*/
.createMediaSource(uri);
case C.TYPE_OTHER:
return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
default: {
throw new IllegalStateException("Unsupported type: " + type);
}
}
}
#Override
public void release() {
if (player != null) {
player.release();
}
player = null;
}
#Override
public void setResizeModeFill(boolean isResizeModeFill) {
if (isResizeModeFill) {
exoPlayerView.setResizeMode(RESIZE_MODE_FILL);
} else {
exoPlayerView.setResizeMode(RESIZE_MODE_FIT);
}
}
}
PlayerHolderView.java
public class PlayerHolderView extends FrameLayout {
private String videoUrl;
private boolean isResizeModeFill = true;
private OnUserInteractionListener onUserInteractionListener;
public PlayerHolderView(#NonNull Context context) {
super(context);
init();
}
public PlayerHolderView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public PlayerHolderView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(R.layout.layout_player, this, true);
View controlView = this.findViewById(R.id.exo_controller);
controlView.findViewById(R.id.exo_play)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlayerViewManager.getInstance(videoUrl).playPlayer();
}
});
controlView.findViewById(R.id.exo_pause)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlayerViewManager.getInstance(videoUrl).pausePlayer();
}
});
controlView.findViewById(R.id.exo_fullscreen_button)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getContext(), FullscreenVideoActivity.class);
intent.putExtra(PlayerViewManager.EXTRA_VIDEO_URI, videoUrl);
getContext().startActivity(intent);
}
});
MainActivity
public class MainActivity extends AppCompatActivity {
private List<PlayerHolderView> playerHolders = new ArrayList<>();
private List<TextView> links = new ArrayList<>();
private List<String> mVideoUrls = new ArrayList<>(
Arrays.asList(
//"http://10.110.3.30/api/Playlists/6a3ecad7-e744-446f-9341-0e0ba834de63?from=2018-09-20&to=2018-09-21"
"https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/hls/TearsOfSteel.m3u8",
"http://redirector.c.youtube.com/videoplayback?id=604ed5ce52eda7ee&itag=22&source=youtube&sparams=ip,ipbits,expire,source,id&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=513F28C7FDCBEC60A66C86C9A393556C99DC47FB.04C88036EEE12565A1ED864A875A58F15D8B5300&key=ik0",
"https://html5demos.com/assets/dizzy.mp4"
//"https://cdn.faceter.io/hls/ab196789-8876-4854-82f3-087e5682d013",
//"https://cdn.faceter.io/hls/65d1c673-6a63-44c8-836b-132449c9462a"
)
);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
playerHolders.add((PlayerHolderView) findViewById(R.id.holder1));
playerHolders.add((PlayerHolderView) findViewById(R.id.holder2));
playerHolders.add((PlayerHolderView) findViewById(R.id.holder3));
links.add((TextView) findViewById(R.id.title1));
links.add((TextView) findViewById(R.id.title2));
links.add((TextView) findViewById(R.id.title3));
}
#Override
public void onResume() {
super.onResume();
int i = 0;
for (final String videoUrl : mVideoUrls) {
playerHolders.get(i).setupPlayerView(videoUrl);
playerHolders.get(i).setOnUserInteractionListener(this);
links.get(i).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onVideoTitleClicked(videoUrl);
}
});
i++;
}
}
#Override
public void onPause() {
super.onPause();
for (String videoUrl : mVideoUrls) {
PlayerViewManager.getInstance(videoUrl).goToBackground();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
for (String videoUrl : mVideoUrls) {
PlayerViewManager.getInstance(videoUrl).releaseVideoPlayer();
}
}
public void onVideoTitleClicked(String videoUrl) {
Intent intent = new Intent(getBaseContext(), DetailActivity.class);
intent.putExtra(PlayerViewManager.EXTRA_VIDEO_URI, videoUrl);
startActivity(intent);
}
}
FullscreenVideoActivity
public class FullscreenVideoActivity extends AppCompatActivity {
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private View mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
#SuppressLint("InlinedApi")
#Override
public void run() {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of
// API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private final Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
hide();
}
};
private String mVideoUri;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fullscreen_video);
mContentView = findViewById(R.id.enclosing_layout);
PlayerHolderView playerHolderView = findViewById(R.id.player_holder);
playerHolderView.setResizeModeFill(false);
mVideoUri = getIntent().getStringExtra(PlayerViewManager.EXTRA_VIDEO_URI);
PlayerViewManager.getInstance(mVideoUri).preparePlayer(playerHolderView);
/*
// Set the fullscreen button to "close fullscreen" icon
View controlView = playerView.findViewById(R.id.exo_controller);
ImageView fullscreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
fullscreenIcon.setImageResource(R.drawable.exo_controls_fullscreen_exit);
controlView.findViewById(R.id.exo_fullscreen_button)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
}
});
controlView.findViewById(R.id.exo_play)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlayerViewManager.getInstance(mVideoUri).playPlayer();
}
});
controlView.findViewById(R.id.exo_pause)
.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PlayerViewManager.getInstance(mVideoUri).pausePlayer();
}
});*/
}
#Override
public void onResume() {
super.onResume();
PlayerViewManager.getInstance(mVideoUri).goToForeground();
}
#Override
public void onPause() {
super.onPause();
PlayerViewManager.getInstance(mVideoUri).goToBackground();
}
#Override
public void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide();
}
private void hide() {
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in delay milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide() {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, 100);
}
}
Just try out this code for video freeze problem:
#Override
public void play() {
player.setPlayWhenReady(true);
player.getPlaybackState();
}
#Override
public void pause() {
player.setPlayWhenReady(false);
player.getPlaybackState();
}
Here player.getPlaybackState(); is help full to get it to back state.
This question already has answers here:
NullPointerException addToRequestQueue(com.android.volley.Request, java.lang.String)' on a null object reference
(8 answers)
Closed 4 years ago.
This is a barcode scanning app. It crashes when I scanned the code. If anyone knows how to fix help me out.
It crashes after I scanned the code from the ScanActivity.java and pass the object to the TicketResultActivity.javato display the result.
error
java.lang.RuntimeException: Unable to start activity ComponentInfo{info.androidhive.movietickets/info.androidhive.movietickets.TicketResultActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void info.androidhive.movietickets.MyApplication.addToRequestQueue(com.android.volley.Request)' on a null object reference
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
// making toolbar transparent
transparentToolbar();
setContentView(R.layout.activity_main);
findViewById(R.id.btn_scan).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, ScanActivity.class));
}
});
}
private void transparentToolbar() {
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true);
}
if (Build.VERSION.SDK_INT >= 19) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
if (Build.VERSION.SDK_INT >= 21) {
setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false);
getWindow().setStatusBarColor(Color.TRANSPARENT);
}
}
private void setWindowFlag(Activity activity, final int bits, boolean on) {
Window win = activity.getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
}
ScanActivity.java
public class ScanActivity extends AppCompatActivity implements BarcodeReader.BarcodeReaderListener{
BarcodeReader barcodeReader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan);
// get the barcode reader instance
barcodeReader = (BarcodeReader) getSupportFragmentManager().findFragmentById(R.id.barcode_scanner);
}
#Override
public void onScanned(Barcode barcode) {
// playing barcode reader beep sound
barcodeReader.playBeep();
// ticket details activity by passing barcode
Intent intent = new Intent(ScanActivity.this, TicketResultActivity.class);
intent.putExtra("code", barcode.displayValue);
startActivity(intent);
}
#Override
public void onScannedMultiple(List<Barcode> list) {
}
#Override
public void onBitmapScanned(SparseArray<Barcode> sparseArray) {
}
/*#Override
public void onCameraPermissionDenied() {
finish();
}*/
#Override
public void onScanError(String s) {
Toast.makeText(getApplicationContext(), "Error occurred while scanning " + s, Toast.LENGTH_SHORT).show();
}
}
TicketResultActivity.java
public class TicketResultActivity extends AppCompatActivity {
private static final String TAG = TicketResultActivity.class.getSimpleName();
// url to search barcode
private static final String URL = "https://api.androidhive.info/barcodes/search.php?code=";
private TextView txtName, txtDuration, txtDirector, txtGenre, txtRating, txtPrice, txtError;
private ImageView imgPoster;
private Button btnBuy;
private ProgressBar progressBar;
private TicketView ticketView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ticket_result);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
txtName = findViewById(R.id.name);
txtDirector = findViewById(R.id.director);
txtDuration = findViewById(R.id.duration);
txtPrice = findViewById(R.id.price);
txtRating = findViewById(R.id.rating);
imgPoster = findViewById(R.id.poster);
txtGenre = findViewById(R.id.genre);
btnBuy = findViewById(R.id.btn_buy);
imgPoster = findViewById(R.id.poster);
txtError = findViewById(R.id.txt_error);
ticketView = findViewById(R.id.layout_ticket);
progressBar = findViewById(R.id.progressBar);
String barcode = getIntent().getStringExtra("code");
// close the activity in case of empty barcode
if (TextUtils.isEmpty(barcode)) {
Toast.makeText(getApplicationContext(), "Barcode is empty!", Toast.LENGTH_LONG).show();
finish();
}
// search the barcode
searchBarcode(barcode);
}
/**
* Searches the barcode by making HTTP call
* Request was made using Volley network library but the library is
* not suggested in production, consider using Retrofit
*/
private void searchBarcode(String barcode) {
// making volley's json request
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
URL + barcode, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.e(TAG, "Ticket response: " + response.toString());
// check for success status
if (!response.has("error")) {
// received movie response
renderMovie(response);
} else {
// no movie found
showNoTicket();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "Error: " + error.getMessage());
showNoTicket();
}
});
MyApplication.getInstance().addToRequestQueue(jsonObjReq);
}
private void showNoTicket() {
txtError.setVisibility(View.VISIBLE);
ticketView.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
}
/**
* Rendering movie details on the ticket
*/
private void renderMovie(JSONObject response) {
try {
// converting json to movie object
Movie movie = new Gson().fromJson(response.toString(), Movie.class);
if (movie != null) {
txtName.setText(movie.getName());
txtDirector.setText(movie.getDirector());
txtDuration.setText(movie.getDuration());
txtGenre.setText(movie.getGenre());
txtRating.setText("" + movie.getRating());
txtPrice.setText(movie.getPrice());
Glide.with(this).load(movie.getPoster()).into(imgPoster);
if (movie.isReleased()) {
btnBuy.setText(getString(R.string.btn_buy_now));
btnBuy.setTextColor(ContextCompat.getColor(this, R.color.colorPrimary));
} else {
btnBuy.setText(getString(R.string.btn_coming_soon));
btnBuy.setTextColor(ContextCompat.getColor(this, R.color.btn_disabled));
}
ticketView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
} else {
// movie not found
showNoTicket();
}
} catch (JsonSyntaxException e) {
Log.e(TAG, "JSON Exception: " + e.getMessage());
showNoTicket();
Toast.makeText(getApplicationContext(), "Error occurred. Check your LogCat for full report", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
// exception
showNoTicket();
Toast.makeText(getApplicationContext(), "Error occurred. Check your LogCat for full report", Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
}
return super.onOptionsItemSelected(item);
}
private class Movie {
String name;
String director;
String poster;
String duration;
String genre;
String price;
float rating;
#SerializedName("released")
boolean isReleased;
public String getName() {
return name;
}
public String getDirector() {
return director;
}
public String getPoster() {
return poster;
}
public String getDuration() {
return duration;
}
public String getGenre() {
return genre;
}
public String getPrice() {
return price;
}
public float getRating() {
return rating;
}
public boolean isReleased() {
return isReleased;
}
}
}
MyApplication.java
public class MyApplication extends Application {
public static final String TAG = MyApplication.class
.getSimpleName();
private RequestQueue mRequestQueue;
private static MyApplication mInstance;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req) {
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}
To initialize MyApplication properly you have to add the following in the AndroidManifest.xml
<application android:name="com.package.subpackage.MyApplication">
...
</application>