Hello I am trying to call this function loadFiles() which is located in fragmentB and I want to call it from FragmentA, so I can refresh my GridView for my images and videos.
I get this error from the same method
FATAL EXCEPTION: main
java.lang.NullPointerException
my method in FragmentB:
public void loadFiles(){
gridView = (GridView) this.v.findViewById(R.id.grid);
File f = new File(home);
if (f.exists()){
String [] media = f.list();
ArrayList<String> files = new ArrayList<>();
for (int i=0; i<media.length;i++){
if (media[i].endsWith(".jpg")||
media[i].endsWith(".png")||
media[i].endsWith(".JPEG")||
media[i].endsWith(".3gp")||
media[i].endsWith(".mp4")||
media[i].endsWith(".mov")){
files.add(media[i]);
}
if (i==media.length-1){
GridAdapter adapter = new GridAdapter(this.v.getContext(), files, gridView);
adapter.notifyDataSetChanged();
gridView.setAdapter(adapter);
}
}
}
}
How I do call it in FragmentA:
FragmentB b = new FragmentB();
b.loadFiles();
I think the problem is because of this line but I have tried everything and there is no luck :(
GridAdapter adapter = new GridAdapter(this.v.getContext(), files, gridView);
I would suggest you to do like this:
public class Utils{
public static ArrayList<String> loadFiles(){
File f = new File(home);
if (f.exists()){
String [] media = f.list();
ArrayList<String> files = new ArrayList<>();
for (int i=0; i<media.length;i++){
if (media[i].endsWith(".jpg")||
media[i].endsWith(".png")||
media[i].endsWith(".JPEG")||
media[i].endsWith(".3gp")||
media[i].endsWith(".mp4")||
media[i].endsWith(".mov")){
files.add(media[i]);
}
}
return files;
}
}
}
Now in FragmentA and FragmentB etc. you can do
gridView = (GridView) this.v.findViewById(R.id.grid);
GridAdapter adapter = new GridAdapter(this.v.getContext(), Utils.loadFiles(), gridView);
gridView.setAdapter(adapter);
Often you will want one Fragment to communicate with another, for
example to change the content based on a user event. All
Fragment-to-Fragment communication is done through the associated
Activity. Two Fragments should never communicate directly.
See this link here, you will find all required details; also you can download zip file containing sample app.
If you want to call a fragment method is because that fragment exists, so you can find and call it with:
Fragment2 myFragment = (MyFragment2) getFragmentManager().findFragmentByTag("TAG_NAME");
myFragment.method();
If it doesn't exist and you have to instantiate it from Fragment1, then maybe your strategy is not correct and you should put your code in your activity.
Related
I tried to add new message item who arrived from push notification to list.
I tried to achieve this by live data. I used databinding in recyclerview and in main activity.
The func onChanged is not called when item is added to live data list in MsgViewModel class.
what I doing wrong?
public class MyFirebaseMessagingService extends FirebaseMessagingService {
......
private void showNotification(Map<String, String> data) {
id = data.get("id");
phone = data.get("phone");
locations = data.get("locations");
textMessage = data.get("textMessage");
MsgViewModel viewModel = new MsgViewModel(getApplication());
viewModel.addMessage(new Message(id, phone, locations, textMessage));
}
public class MsgViewModel extends AndroidViewModel {
private MutableLiveData<ArrayList<Message>> messageArrayList;
public MsgViewModel(#NonNull Application application) {
super(application);
messageArrayList = new MutableLiveData<>();
}
public void addMessage(Message message){
List<Message> messages = messageArrayList.getValue();
ArrayList<Message> cloneMessageList;
if(messages == null){
cloneMessageList = new ArrayList<>();
}else {
cloneMessageList = new ArrayList<>(messages.size());
for (int i = 0; i < messages.size(); i++){
cloneMessageList.add(new Message(messages.get(i)));
}
}
cloneMessageList.add(message);
messageArrayList.postValue(cloneMessageList);
}
public MutableLiveData<ArrayList<Message>> getMessageList(){
return messageArrayList;
}
}
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private MsgViewModel msgViewModel;
private MsgListAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.contentMainId.recyclerview.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
binding.contentMainId.recyclerview.setLayoutManager(layoutManager);
msgViewModel = new ViewModelProvider(this).get(MsgViewModel.class);
msgViewModel.getMessageList().observe(this, new Observer<ArrayList<Message>>() {
#Override
public void onChanged(ArrayList<Message> list) {
mAdapter = new MsgListAdapter(getApplication(), list);
binding.contentMainId.recyclerview.setAdapter(mAdapter);
// mAdapter.notifyDataSetChanged();
}
});
}
Any help why it is not update the adapter will be appreciated
==========Update=======
onChanged() method not called when have new item who added to the list
The problem here is how you instantiate your viewModels. If I understand correctly, you want them to be the same instance in both the activity and the messaging service.
One is MsgViewModel viewModel = new MsgViewModel(getApplication());
The other one is msgViewModel = new ViewModelProvider(this).get(MsgViewModel.class);
On the second one this stands for the current instance of the activity. And its context is different from the one you get from getApplication().
As far as I know, when you call 'postValue()' or something 'setValue()' method, you should give new object of something like oldMutableList.toList().
In other words, after a list is entered as a parameter in 'postvalue()'method of livedata, even if a new value is added to the list, livedata is not recognized. In order for the observer to recognize, the newly created list object must be entered as a parameter when calling postvalue again.
_liveData.postValue(list.toList()) // "list.toList()" <- this code generate new List object which has another hashcode.
or
_liveData.postValue(list.sortedBy(it.somethingField))
sorry about this kotlin code, not java.
// this original in your code
messageArrayList.postValue(cloneMessageList);
// change to these codes
messageArrayList.postValue(new ArrayList(cloneMessageList));
or
messageArrayList.postValue(cloneMessageList.toList());
private String[] listView2 = {"aa","bb","cc","dd","ee"};
listView1 = (ListView)findViewById(R.id.listView1);
listAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,listView2);
listView1.setAdapter(listAdapter);
Change listView2[1] to "zzz".
Following code isn't work.
listView2[1] = "zzz";
you also need to call
listAdapter.notifyDataSetChanged();
Or use one of the listAdpater methods for changing the data:
add(T), insert(T, int), remove(T), clear()
you can update adapter like this:
adapter.insert("zz", 1);
adapter.notifyDataSetChanged();
Try this.^_^
public void newListView(){
listAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,listView2);
listView1.setAdapter(listAdapter);
}
listView2[0] = "zz";
newListView();
Currently I'm using an ArrayAdapter which I just import. As the question states I want to get images into my listviews. I'm loading information into my list using JSONObjects and storing them into my ArrayLists. I know my current method removes html tages from the JSONObjects.
public class Home extends Activity {
ListView lView;
TextView tView;
ArrayAdapter lAdapter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_layout);
lView = (ListView) findViewById(android.R.id.list);
//tView = (TextView) findViewById(android.R.id.);
loadList(lView);
}
public void loadList(ListView lView){
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall("URL", ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
ArrayList<String> titles = new ArrayList<String>();
ArrayList<String> body = new ArrayList<String>();
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
JSONArray entries = jsonObj.getJSONArray("entries");
for (int i = 0; i < entries.length(); i++) {
JSONObject c = entries.getJSONObject(i);
String text = c.getString("introtext");
if(text == "null"){
text = "No text here" + "\n" + "\n";
}
else {
text = android.text.Html.fromHtml(text).toString();
}
String title= c.getString("title");
String full = title + "\n" + "\n" + text;
titles.add(full);
//body.add(text);
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
lAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, titles);
lView.setAdapter(lAdapter);
}
}
Any suggestions would be great help
Thanks
First create a layout same what you want to show in a row, now create a class for a custom adapter like:
public class MyAdapter extends ArrayAdapter<T>{
}
Where T represents the entity class, which represents your data model.
Now under override method:
public View getView(final int position, View convertView, ViewGroup parent) {}
Inflate your layout created for the row, and set each view as you want to show.
Don't forgot to use lazy loading for the image to load over the imageview.
Hope it will help you.
You will need to create a custom adapter that has your own Layout defined. In this layout, you can include whatever you want (including an ImageView, that you can place your image).
There are many examples, but the important thing to know in your code, is you will supply your own adapter here, and set it up a bit differently:
lAdapter = new ArrayAdapter<String>(this, R.layout.my_custom_adapter, titles);
Try to use a Base Adapter
Inflate a custom Xml having a imageview using the base adapter
You can put any views(Image,textview etc ) depending on your
requirement
Finally use picasso or imageloader to populate images using the JSON
response to your base adapter
Hope it helps, Revert back to me if you need any more help, Happy coding
You'll have to create a custom adapter instead of ArrayAdapter, so that you can use your own layout for every row, and perform any 'image loading' there. Try creating a class that extends the BaseAdapter abstract class from the framework. Also, search the web or here (in stackoverflow) you'll find tons of tutorials on how to create a custom adapter.
Since downloading and loading images can be a bit of a pain if you aren't experienced with ListViews and custom adapters, I would suggest looking up two 3rd party libraries for this job:
Picasso or Universal-Image-Loader, each one having examples on how to use them alongside with custom adapters
I know I am Probably making a bigger deal out of this but here is my problem:
I basically want to be able to make a playlist from a list of songs. As each song/item is clicked it adds it to another arraylist in another activity.
Please help it so frustrating:
here is my code..
public class SDLTlist extends ListActivity {
// Songs list
public ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ltsdlist);
ArrayList<HashMap<String, String>> songsListData = new ArrayList<HashMap<String, String>>();
ImportSD plm = new ImportSD();
// get all songs from sdcard
this.songsList = plm.getPlayList();
// looping through playlist
for (int i = 0; i < songsList.size(); i++) {
// creating new HashMap
HashMap<String, String> song = songsList.get(i);
// adding HashList to ArrayList
songsListData.add(song);
}
// Adding menuItems to ListView
ListAdapter adapter = new SimpleAdapter(this, songsListData,
R.layout.playlist_item, new String[] { "songTitle" }, new int[] {
R.id.songTitle });
setListAdapter(adapter);
};
});
}
}
The above class imports songs using MEDIA_PATH with file extensions .MP3 (which is called in another class called importSD) and lists them in an array, as I select an item from that list I want it to be added to another list in a different activity. Should I use the onItemClickListners function? If so how would I do it?
You can either:
A. Keep the ArrayList you want to add to outside the Activities (ie. In a class that overrides Application) and then add it while still in the second Activity.
or
B. Pass the selected Array of data back to the Activity and handle it in OnActivityResult by pulling out the list you passed back.
IE. If you have a String[], you could pull that out of the passed-back Intent with:
data.getStringArrayExtra("my_string_array_name")
You can always create a global application class that can be shared across all your activities:
package com.example.app;
import android.app.Application;
import java.util.ArrayList;
public class GlobalVars extends Application {
public ArrayList<String> aList;
public GlobalVars() {
aList = new ArrayList<String>();
}
}
Then in each Activity you can get the global class like this:
gVars = (GlobalVars) getApplication();
gVars.aList.add("Adding a String");
Make sure to add this Application class correctly to your AndroidManifest.xml.
I looked at the following site: ListView Example
Which describes how to implement a search function in a listview which uses the default adapter and it works fine.
How can I modify it so I can use the same for a Custom Adapter for my listview?
Partial code is:
dataList = (ListView) findViewById(R.id.lvFiles);
tvQuote = (TextView) findViewById(R.id.tvDisplay);
tvQuote.setTypeface(Typeface.createFromAsset(MainActivity.this.getAssets(), "fonts/roboto.ttf"));
for (int y=0; y<strNamesOfAllah.length;y++) {
name = strNamesOfAllah[y];
meaning = strMeaning[y];
rowsArray.add(new SetRows(R.drawable.icon, name, meaning));
}
adapter = new SetRowsCustomAdapter(MainActivity.this, R.layout.customlist, rowsArray);
dataList.setAdapter(adapter);
dataList.setClickable(true);
You need to override getFilter inside of your adapter and return a new customFilter object that you create. See this answer: No results with custom ArrayAdapter Filter
Edit:
#Override
public Filter getFilter() {
if(customFilter == null){
customFilter = new CustomFilter();
}
return customFilter;
}