简体   繁体   中英

Fragment listview update from activity

I am pretty new to Android (3 days), but I have a pretty good background in PHP (which may be the cause of my confusion in a Java based environment). I started building an Android app using Android Studio (Beta). I created the default Android Studio activity with the Navigation Drawer Activity. I edited the activity fragment part to look like this:

@Override
public void onNavigationDrawerItemSelected(int position) {
    Bundle bundle = new Bundle();
    bundle.putStringArrayList("contacts", arr);
    bundle.putStringArrayList("messages", messages);
    Fragment fragment = null;
    switch (position) {
        case 0:
            fragment = new FriendsFragment();
            break;
        case 1:
            fragment = new ChatsFragment();
            break;
        case 2:
            fragment = new GroupsFragment();
            break;
        case 3:
            fragment = new LogoutFragment();
            break;
        default:
            break;
    }

    if (fragment != null) {
        fragment.setArguments(bundle);
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container, fragment).addToBackStack(null).commit();
    }
}

As you can see I am passing a Bundle to my Fragments called "messages" and "contacts" when an item is selected in the Navigation Drawer. The "messages" bundle are XMPP messages received by the aSmack library from an OpenFire server. So basically I'm trying to create a XMPP client. When I run the app I can receive the messages in the "ChatsFragment".

Now my problem: I have to press the "ChatsFragment" item on the drawer to have my messages updated (re-receive the bundle) everytime I feel like there are new messages received from the server. But I want this to be done automatically by the fragment.

First I would like to know if my procedure is correct (Activity listens to server, creates bundle, send bundle to fragment, bundle updates messages on receive**)

** = This part I haven't been able to understand how to implement.

1- If the procedure is correct tell me how I should get the messages to be updated by the fragment through the activity?

2- If this is not the correct way to do things in Android, recommend me a way of doing it.

My code for displaying the messages in fragment:

private void displayListView() {

    // Messages array list
    List<String> contacts = getArguments().getStringArrayList("messages");
    //System.out.println("arr: " + contacts);

    //create an ArrayAdaptar from the String Array
    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(getActivity(),
            R.layout.url_list, contacts);
    ListView listView = (ListView) getView().findViewById(R.id.listView);
    // Assign adapter to ListView
    listView.setAdapter(dataAdapter);

    //enables filtering for the contents of the given ListView
    listView.setTextFilterEnabled(true);

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {
            // Send the URL to the host activity
            //mListener.onURLSelected(((TextView) view).getText().toString());

        }
    });

}

Thanks in advance.

Typically for long running operations in the background, like listening to a server, incoming messages, etc, you need to use Services. You do so by subclassing the Service class in Android.

Now for your problem - the design approach should be that you have a background service listening to incoming messages. Anytime a message is received (an input stream in your socket operator) you should send a "broadcast" an intent that a message was received. A custom broadcast receiver that you create should wait for this broadcast. Within the onReceive() method of this receiver, you should trigger the creation of the bundle and updating your message.

Remember you should always delegate your long running operations in Android to services. That is exactly what they are for.

So basically if you're already listening for new messages to come in your activity, then you must have some kind of callback like onMessageRecieved() or something like that.

If you do, you can then notify your fragment in this way. Create a field (goes under your class declaration) called curFrag, so something like this:

public class MyActivity extends Activity {

private Fragment curFrag; 

//other code...

}

then in the code you posted you would initialize the curFrag there, but you also need to set a tag for the current fragment. This will be based on your case statement. Make some final string variables as tags. ie

public static final String CHATSTAG = "chatstag";

@Override
public void onNavigationDrawerItemSelected(int position) {
    Bundle bundle = new Bundle();
    bundle.putStringArrayList("contacts", arr);
    bundle.putStringArrayList("messages", messages);
    Fragment fragment = null;
    String tag = null; 
    switch (position) {
        case 0:
            tag = FRIENDSTAG;
            fragment = new FriendsFragment();
            break;
        case 1:
            tag = CHATSTAG;... and so on through the switch statement. 
            fragment = new ChatsFragment();
            break;
        case 2:
            fragment = new GroupsFragment();
            break;
        case 3:
            fragment = new LogoutFragment();
            break;
        default:
            break;
    }



    if (fragment != null) {
        fragment.setArguments(bundle);
        FragmentManager fragmentManager = getSupportFragmentManager();
//remember to set the tag.
        if(tag != null) {
fragmentManager.beginTransaction()
                .replace(R.id.container, fragment, tag).addToBackStack(null).commit();
        } else {

fragmentManager.beginTransaction()
                .replace(R.id.container,fragment,DEFAULTTAG).addToBackStack(null).commit();
}
       //new code
        curFrag = fragment;
    }
}

Now in your activity when a new message comes in, check the tag of the fragment and then if it matches a certain fragment, notify the fragment that new data has come in and retrieve it in the fragment.

public void onMessageRecieved() {

if(curFrag.getTag().equalsIgnoreCase(CHATSTAG)) {

ChatsFragment frag = (ChatsFragment) curFrag;
frag.notifyDataRecieved();
}
}

Once you have a reference to your fragment in the activity, you have access to any public methods in that fragment.

If your fragment cannot access the data on its own, then you'll need to get a reference to the activity and create a method in the activity that returns the new data.

So in your activity:

public String getMessageData() {

String newData = ...//get stuff from server;
return newData;
}

then in your fragment

public void notifyNewMessage() {
try {
 MyActivity activity = (MyActivity) getActivity();
} catch (ClassCastException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}

String message = activity.getMessageData();
//do something with the message.
}

It's not necessarily pretty but it works pretty well. You should also check to make sure your fragments are attached when you do this so that you avoid null exceptions.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM