I've a dynamic image array which come through from database. And i just show image thumbnails at first screen and want to display full screen of same image array. The thing is that i want to pass the whole dynamic array to next screen. Actually i know how to use preferences in java. But i don't know how to pass the whole array with variables or something. Any ideas would be appreciate.
public class MerchantDetails extends GLCityActivity implements OnClickListener {
public static MerchantDetails instance;
private Gallery gallery;
private ImageView imView;
String Header, contentName;
DBManager gDatabase = new DBManager(this);
private ArrayList<Multimedia> mm;
private ImageViewAdapter iva;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.Theme_Translucent);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.details);
instance = this;
initActivity(instance, " ");
try {
gDatabase.createDataBase();
} catch (IOException e) {
throw new Error("Unable to create database");
}
try {
gDatabase.openDatabase();
} catch (SQLiteException sqle) {
throw sqle;
}
settingLayout();
}
public void settingLayout() {
SharedPreferences preferences = getSharedPreferences(
Constants.DEFAUL_SHARE_DATA, 0);
Header = preferences.getString("SubName", "");
headerTxt = (TextView) findViewById(R.id.templateTopTitleTView);
headerTxt.setText(Header);
gallery = (Gallery) findViewById(R.id.gallery);
if (mm.isEmpty()) {
gallery.setVisibility(gallery.INVISIBLE);
} else {
gallery.setAdapter(iva);
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v,
int position, long id) {
SharedPreferences preferences = getSharedPreferences(
Constants.DEFAUL_SHARE_DATA, 0);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("ImagePosition", mm.get(position) + "");
editor.putInt("ImageLength", mm.size());
Intent viewer = new Intent(instance, GalleryViewer.class);
startActivityForResult(viewer, 0);
if (editor.commit()) {
}
}
});
}
}
private class ImageViewAdapter extends ArrayAdapter<Multimedia> {
private ArrayList<Multimedia> items;
public ImageViewAdapter(Context context, int textViewResourceId,
ArrayList<Multimedia> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.image_list, null);
}
Multimedia info = items.get(position);
if (info != null) {
ImageView imView = (ImageView) v
.findViewById(R.id.rowlistIconIView);
String name = info.thumbnail;
String[] test = gDatabase.split(name, ".");
int resID = getResources().getIdentifier(test[0], "drawable",
getPackageName());
Log.v("Log", name + ";" + resID + ";" + test[0] + ";");
try {
imView.setImageResource(resID);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
return v;
}
}
}
Edited :
#Jeremy Edwards,thanks for your reply. I tried to do as you suggest but i found this error while i coded. I tried to use putExtra(String name,int[] value) but the error said The method putExtra(String name,boolean value) in the type Intent is not applicable for the arguments (String,Multimedia). Actually i already chose putExtra(String name,int[] value) from auto suggest box. wonder how it change back to (String name,int[] value) suddenly. Please check my code below.
private ArrayList<Multimedia> mm;
viewer.putExtra("ImagePosition",mm.get(position));
viewer.putExtra(String name,int[] value)
For the viewer Intent. Use Intent.put(name, "Id of the image").
Then in the viewer activity use getIntent().getIntExtra(name) to get that id back.
I'd advise against passing image data itself since android uses IPC "Shared memory" to pass data between the activity boundaries. It was meant to be lightweight.
The viewer activity should get the ID and then hit the DB for the full blown image you want. You shouldn't need to use preferences either to accomplish this since the Bundle inside the Intent object will carry the information you need.
From scanning through your code I think you are storing the images in ArrayList.
ArrayList is Serializable so you can use bundle to pass it to the next screen. You can use bundle's putSerializable method
Something like this
Bundle bundle = new Bundle();
bundle.putSerializable(<key>, <your serializable obj>);
then use the getSerializable() to get it back
Related
I try to open each video when I click on them but what I get instead is only the second video (sometimes first video). For example, when I click on "16 best video ideas for small business" I want it to open that particular video. But what I get instead is "this tiny camera can show the world from a bug's point of view. I think the problem occurs because of for loop inside query in UserHomeVideoAdapter.
UserHomeVideoAdapter.java:
public class UserHomeVideoAdapter extends FirestoreRecyclerAdapter<FollowList, UserHomeVideoAdapter.UserVideoHolder> {
Context context;
final FirebaseFirestore db = FirebaseFirestore.getInstance();
String thumbUrl, videoTitle, videoUrl, videoDesc, videoId, publisherId;
Video video;
public UserHomeVideoAdapter(#NonNull #NotNull FirestoreRecyclerOptions<FollowList> options, Context context) {
super(options);
this.context = context;
}
#Override
protected void onBindViewHolder(#NonNull #NotNull UserVideoHolder holder, int position, #NonNull #NotNull FollowList model) {
Query query = db.collection("Videos").whereEqualTo("publisherId", model.getUserId());
query.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {
if (task.getResult() != null) {
for (QueryDocumentSnapshot documentSnapshot : task.getResult()) {
video = documentSnapshot.toObject(Video.class);
Log.d("Data", documentSnapshot.getId() + " => " + documentSnapshot.getData());
thumbUrl = video.getThumbUrl();
videoTitle = video.getVideoTitle();
videoUrl = video.getVideoUrl();
videoDesc = video.getVideoDesc();
videoId = video.getVideoId();
publisherId = video.getPublisherId();
}
if (task.getResult().size() != 0) {
Glide.with(context).load(model.getUserImageUrl()).into(holder.userProfileImage);
Glide.with(context).load(thumbUrl).into(holder.videoImageView);
holder.videoTitle.setText(videoTitle);
holder.mainContainerVideo.setVisibility(View.VISIBLE);
} else if (task.getResult().size() == 0) {
holder.mainContainerVideo.getLayoutParams().height = 0;
holder.mainContainerVideo.getLayoutParams().width = 0;
}
}
} else {
Toast.makeText(context, String.valueOf(task.getException()), Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(e -> Toast.makeText(context, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show());
holder.videoContainer.setOnClickListener(v -> {
Intent intent = new Intent(context, VideoActivity.class);
intent.putExtra("videoPublisherUserName", model.getUserName());
intent.putExtra("thumbUrl", thumbUrl);
intent.putExtra("videoPublisherEmail", model.getUserEmail());
intent.putExtra("videoUrl", videoUrl);
intent.putExtra("videoId", videoId);
intent.putExtra("videoPublisherFullName", model.getUserFullName());
intent.putExtra("videoPublisherId", publisherId);
context.startActivity(intent);
});
}
#NonNull
#NotNull
#Override
public UserVideoHolder onCreateViewHolder(#NonNull #NotNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.video_cell, parent, false);
return new UserVideoHolder(v);
}
public static class UserVideoHolder extends RecyclerView.ViewHolder {
RelativeLayout videoContainer, mainContainerVideo;
CircleImageView userProfileImage;
TextView videoTitle;
ImageView videoImageView;
public UserVideoHolder(#NonNull #NotNull View itemView) {
super(itemView);
mainContainerVideo = itemView.findViewById(R.id.mainContainerVideo);
videoContainer = itemView.findViewById(R.id.videoContainer);
userProfileImage = itemView.findViewById(R.id.userProfileImage);
videoTitle = itemView.findViewById(R.id.videoTitle);
videoImageView = itemView.findViewById(R.id.videoImageView);
}
}
}
I logged videoId inside that is assigned inside for loop. Sometimes it returns ids in this order "1"; "2" and sometimes it returns like this "2"; "1". When it returns in this order "1"; "2" click opens second video even if I click first video and when it returns like this "2"; "1" click opens first video even if I click second video.
If you need additional code to solve the problem please ask and I will provide it as soon as possible. Any help is appreciated. Thanks
The short answer is that onBindViewHolder() is trying to do too much. From the documentation:
Called by RecyclerView to display the data at the specified position. This method should update the contents of the ViewHolder#itemView to reflect the item at the given position.
In other words, onBindViewHolder() is only responsible for one single item in the RecyclerView. However, you are trying to fetch all of the data for every element in the list. Instead, you should fetch the data external to your adapter and pass it in as a parameter. Then onBindViewHolder() should update the UI elements of a view inside the RecyclerView to display whatever you want for one single item.
Google has a great example CustomerAdapter. First, the constructor takes the list of data that will be displayed:
public CustomAdapter(String[] dataSet) {
mDataSet = dataSet;
}
Then onbindViewHolder() is only responsible for setting what is displayed in the UI of a single item in the RecyclerView:
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
Log.d(TAG, "Element " + position + " set.");
// Get element from your dataset at this position and replace the contents of the view
// with that element
viewHolder.getTextView().setText(mDataSet[position]);
}
It does NOT try to get data or loop over a list or anything else. All of that is someone else's responsibility.
I have a fragment which displays a popup when the user is successfully logged in. If I navigate to a new fragment and come back, the popup with the previous username is shown again. I fixed this problem using SingleLiveEvent, but I now have to refactor my code to use MediatorLiveData as my data can come from 2 sources (remote and database), and it is not compatible with SingleLiveEvent.
I tried using an event wrapper and removing observers on onDestroyView() but so far nothing is working, the livedata onChanged function keeps getting called when I move back to the fragment. Here is some of my fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
binding = FragmentDashboardBinding.inflate(inflater, container, false);
binding.setLifecycleOwner(getActivity());
//Get the attendanceViewModel for registering attendance
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
return binding.getRoot();
}
private void showResultClockInOutPopup() {
clockInBuilder = new AlertDialog.Builder(getActivity());
View view = getLayoutInflater().inflate(R.layout.status_clock_in_out_popup, null);
TextView responseClockInOut = view.findViewById(R.id.responseClockInOut);
Button dismissButton = view.findViewById(R.id.dismissButton);
//Setup Popup Text
if (clokedInOutMember != null) {
if (StringToBool(clokedInOutMember.is_clocked_in_temp)) {
responseClockInOut.setText("Bienvenue " + clokedInOutMember.name + ", tu es bien enregistré(e).");
} else {
responseClockInOut.setText("Désolé de te voir partir " + clokedInOutMember.name + ", à bientôt!");
}
} else {
responseClockInOut.setText("Oups, il semblerait qu'il y ait une erreur...\n Essaye à nouveau.");
}
[..SETUP ALERTDIALOG...]
//Dismiss popup
dismissButton.setOnClickListener(v -> {
clockInResultDialog.dismiss();
clockInResultPopupShowed = false;
clokedInOutMember = null;
});
clockInResultDialog.show();
clockInResultPopupShowed = true;
}
}
#Override
public void onDestroyView() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onDestroyView();
}
And here is my ViewModel, I have to use transformations as I am getting the userId from the fragment, passing to the Viewmodel which passes it to the repository for query (maybe there is a better way?):
public class AttendanceViewModel extends AndroidViewModel {
private AttendanceRepository repository = AttendanceRepository.getInstance();
public LiveData<AttendanceMemberModel> mAttendanceAndMember;
private MutableLiveData<String> mId = new MutableLiveData<>();
private MediatorLiveData<AttendanceMemberModel> mObservableAttendance = new MediatorLiveData<AttendanceMemberModel>();
{
mObservableAttendance.setValue(null);
mAttendanceAndMember = Transformations.switchMap(mId, id -> {
return repository.saveAttendance(id);
});
mObservableAttendance.addSource(mAttendanceAndMember, mObservableAttendance::setValue);
}
public AttendanceViewModel(#NonNull Application application) {
super(application);
}
public LiveData<AttendanceMemberModel> getAttendance() {
return mObservableAttendance;
}
public void setMemberId(String id) {
mId.setValue(id);
}
#Override
protected void onCleared() {
mObservableAttendance.setValue(null);
super.onCleared();
}
}
I can suggest you two ways. First create a boolean variable whether dialog is shown in Fragment and after showing dialog set it to true and before showing dialog check if dialog is shown. Second way is after showing dialog set livedata value to null and check if observer value null before showing dialog. I prefer second way.
Use anyone of them, which works and behaves according to your need.
#Override
public void onPause() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onPause();
}
#Override
public void onStop() {
attendanceViewModel.getAttendance().removeObservers(this);
super.onStop();
}
Fragment Life Cycle
Have a look at the lifecycle of the fragment, it will give you bit more idea.
Let me know if this works or not.
The best way to the same is to bind your view model in OnViewCreated meathod.
#Override
public void onActivityCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
attendanceViewModel = ViewModelProviders.of(this).get(AttendanceViewModel.class);
setUpObservers();
}
private void setUpObservers() {
attendanceViewModel.getAttendance().observe(getViewLifecycleOwner(), attendanceAndMember -> {
if (attendanceAndMember != null && attendanceAndMember instanceof AttendanceMemberModel) {
clokedInOutMember = attendanceAndMember.member;
}
showResultClockInOutPopup();
});
}
If still it don't work kindly let me know. Thank you.
Title basically says the issue. I referred to this: https://english.stackexchange.com/questions/11481 to solve the latter issue but then its giving me the former issue.
public class PbfSampleApplication extends Application {
public static final String TAG = "PbfSampleApplication";
#Override
public void onCreate() {
super.onCreate();
startService(new Intent(this.getApplicationContext(),
PbfSampleService.class));
FlicManager.init(this.getApplicationContext(), "2125f7c3-0d0e-42d5-88fe-
fda8765867d6", "94d6448c-22d3-4d2e-951f-f625f60f471a");
FlicManager manager = FlicManager.getManager();
for (FlicButton button : manager.getKnownButtons()) {
button.connect();
listenToButtonWithToast(button);
}
}
public void listenToButtonWithToast(FlicButton button) {
button.addEventListener(new FlicButtonAdapter() {
#Override
public void onButtonUpOrDown(FlicButton button, boolean wasQueued, int timeDiff, boolean isUp, boolean isDown) {
if (isDown) {
View v =LayoutInflater.inflate(R.layout.activity_main);
//Above line has the error
View innerView = v.findViewById(R.id.number);
Toast.makeText(getApplicationContext(), "Button " + button + " was pressed", Toast.LENGTH_SHORT).show();
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:017702329065"));
startActivity(callIntent);
}
}
});
}
}
I know I'm supposed to pass in an int but when I check the method in the developer website it appears the argument is correctly formatted, so I'm not sure what else I need to get this to work
Create an instance of LayoutInflater before calling it:
LayoutInflater inflater = LayoutInflater.from(getContext());
View v = inflater.inflate(R.layout.activity_main, null);
View innerView = v.findViewById(R.id.number);
The second parameter is a ViewGroup that may be null. The LayoutInflater does not have an inflate method that takes only one argument
I have been reading different posts on here about baseadapters and trying to learn so that I can fix my issue but I haven't been able to resolve it. On my BaseAdapter I have a String called post that is used in a column in the listview. If the post is longer than 13 characters then it is shortened automatically when the user Clicks on the shortened post then it displays it's full length,however the issue is that once you scroll down the listview and come back up to that same post it's still shortened even though the user clicked before to show the full post. I think this is an issue of the Listview or Baseadapter recycling or cache mechanism is there anyway I can fix this? This image will clear things up .. This post is more than 13 characters so it shows the shortened version
if a user wants to read it in full then they will click on the Read More which will then show all of the content which looks like this
and when the user scrolls down or up that same long post will return to this without the user clicking it again, which I want to avoid
I know that the Listview recycles but how can I update it? This is my code below
public class LocalFeed_CustomView extends BaseAdapter {
JSONObject names;
Context ctx;
Activity m;
// More is the default value
String result="More";
#Override
public int getCount() {
try {
JSONArray jaLocalstreams = names.getJSONArray("localstreams");
return jaLocalstreams.length();
} catch (Exception e) {
Toast.makeText(ctx, "Error: Please try again", Toast.LENGTH_LONG).show();
return names.length();
}
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row=convertView;
MyViewHolder holder=null;
try {
if (row == null) {
LayoutInflater li = (LayoutInflater) m.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(R.layout.customadapter, null);
holder = new MyViewHolder(row);
row.setTag(holder);
} else {
holder = (MyViewHolder) row.getTag();
}
final MyViewHolder finalHolder1=holder;
// Json data has been read
JSONArray jaLocalstreams = names.getJSONArray("localstreams");
final JSONObject jsonObject = jaLocalstreams.getJSONObject(position);
// if post length is more than 14 then shorten it
if (jsonObject.getString("post").length() > 14) {
holder.post.setText(jsonObject.getString("post").substring(0, 13) + "...Read More");
holder.post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
// if Result is More then show full post
if (result.equals("More")) {
finalHolder1.post.setText(jsonObject.getString("post") + "... Read Less");
result = "Less";
}
else
{
//Result is Less so shorten it again
finalHolder1.post.setText(jsonObject.getString("post").substring(0, 13) + "... Read More");
result = "More";
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
} else{
// This Post is already less than 14 characters so no Onclick here
holder.post.setText(jsonObject.getString("post"));
}
return row;
} catch (Exception e) {
e.printStackTrace();
}
return row;
}
class MyViewHolder{
TextView post;
MyViewHolder(View v)
{
post = (TextView)v.findViewById(R.id.post);
}
}
}
The adapter represents the model of the list at any given moment in time.
What this means to you is that if a user clicks a TextView to expand it with the idea that the view is going to stay expanded, then that expanded TextView is state information that will have to be captured in the adapter.
Adapters should always be thought of in two phases:
Event (like onClick()) will update state in the adapter and call notifyDataSetChanged().
getView() uses the current state to create the view.
So let's say in the adapter constructor we create an array of flags
boolean expanded[] = new boolean[size];
where size is the length of your list.
Then you can do this:
// use the current state to create the view
String text;
if (expanded[position]) {
text = jsonObject.getString("post") + "... Read Less";
} else {
text = jsonObject.getString("post").substring(0, 13) + "...Read More";
}
holder.post.setText(text);
holder.post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// update the current state and request list refresh
expanded[position] = ! expanded[position]; // toggle
notifyDataSetChanged();
}
});
This code doesn't do exactly what yours does, I just wanted to give you the basic idea.
I have a ListView of contacts and each contact is a Java object with a bunch of information associated with it. Some of that info is shown in the ListView, but the rest is meant for the DetailView. I'm trying to write a method that will take me to a DetailView for any contact I click on, but I also need to take the object with me. I store all of the contacts in an ArrayList in my MainActivity.java
My questions: Do I need to take the contact object with me or is there actually some way to access my ArrayList in another Activity?
If I can/have to take it with me, how would I do so, since the putExtra() methods don't take objects as arguments.
The beginning of my MainActivity looks like this:
public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
ListView list;
I have a very basic onClickListener right now but don't know what to put into it:
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Intent intent = new Intent(MainActivity.this, DetailView.class);
intent.putExtra("contact", i);
startActivity(intent);
}
I feel like my initial definition of the MainActivity class doesn't correspond to the onItemClick method or something, which is why it doesn't execute and take me to another screen.
Intent intent = new Intent(ActivityA.this, DetailView.class);
intent.putExtra("extra_name","extra");
startActivity(intent);
Then in the other Activity :
/*onCreate*/
Object extra = getIntent().getExtra().get("extra_name");
I would recommend to pass an ID of some sort pointing to the description, passing complex data structure with intents is not recommended
Simply, use Intent.putExtra() to pass the information and getIntent().getExtras() to receive the information.
// call a new intent
myIntent = new Intent(ActivityA.this, ActivityB.class);
// put an extra (like this following string)
String userid = "User A";
myIntent.putExtra("TAG_CONTACT_ID", userid);
startActivity(myIntent);
// receive the info in your onCreate method in ActivityB
Bundle extras = getIntent().getExtras();
if(extras != null) {
String newUserID = extras.getString("TAG_CONTACT_ID");
}
See this short example for more information.
If you want to pass an Integer, you can do it as the following: myIntent.putExtra("value", i); and take it with: int myValue = extras.getInt("value");.
Hope this help.
Try something like this:
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Contact c = (Contact)contacts.get(position);
Intent i = new Intent();
i.putExtras("contact", c);
i.setClass(this, Activity2.class);
startActivity(i);
}
Create java object with parcelable
Check the below code to create parcelable object in Android.
public class ObjFeedImages implements Parcelable {
public int image_id;
public boolean like_status = false;
public String image_url = null;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[] {
String.valueOf(image_id),
String.valueOf(like_status),
image_url, });
}
public ObjFeedImages(Parcel in) {
String[] data = new String[3];
int i = 0;
in.readStringArray(data);
image_id = Integer.parseInt(data[i++]);//
like_status = Boolean.parseBoolean(data[i++]);
image_url = data[i++];
}
public static final Parcelable.Creator<ObjFeedImages> CREATOR = new Parcelable.Creator<ObjFeedImages>() {
#Override
public ObjFeedImages createFromParcel(Parcel source) {
try {
return new ObjFeedImages(source);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
public ObjFeedImages[] newArray(int size) {
try {
return new ObjFeedImages[size];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
};
}
After creating some list of such object say
ObjFeedImages object = new ObjFeedImages();
object.image_id = 1;
object.like_status = true;
object.image_url="http://some image url";
Intent intent = new Intent(/*Your Intent Info*/);
intent.putExtras("key_name",object);
startActivity(intent);
Here is the complete description.
To retrive object in other activity you have to write below code.
ObjFeedImages objectOnOtherActivity = (ObjFeedImages)getIntent().getParcelableExtra("key_name");
So ready to enjoy code.
Happy coding....