Question

Im developing a chat app and my adapters (BaseAdapter), that holds the chat logs, are in Service, cause the variable that give me IRC resources are in Service. When an activity is binded, my chat fragments gets the adapters from the service. At first, i was trying to notifyDataSetChanged() from adapter itself, then i discover that i need to call it from main UI thread. So i send a broadcast to fragment to notify the adapter inside, the fragment uses the main UI thread. Now, im getting this problem cause im feeding the list outside the UI thread (from Service) and notifying it on main thread. But it need this adapter on Service. What should i do?

This is my adapter. There are one of it for each conversation. This adapter remains in Service:

public class Conversa extends BaseAdapter {

private Context context;
public ArrayList<String> log;
private String target;

public Conversa(Context context, String target) {
    this.context = context;
    this.target = target;
    log = new ArrayList<String>();
}

@Override
public int getCount() {
    return log.size();
}

@Override
public Object getItem(int pos) {
    return log.get(pos);
}

@Override
public long getItemId(int arg0) {
    return 0;
}

@Override
public View getView(int pos, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.msg_layout, parent, false);
    }

    TextView msg = (TextView) convertView.findViewById(R.id.msg);
    msg.setText(log.get(pos));

    return convertView;
}

public ArrayList<String> getLog() {
    return log;
}

public String getTarget() {
    return target;
}

public void setTarget(String target) {
    this.target = target;
}

}

This is my ChatFragment:

public class ChatFragment extends Fragment {

private String target;
private ListView listview;
private EditText edittext;
private Conversa conversa;
private MainActivity activity;
private BroadcastReceiver BR_update_list;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    target = getArguments().getString(IRCService.EXTRA_TARGET);

    activity = (MainActivity) getActivity();

    conversa = activity.service.getConversa(target);

    registerUpdateReceiver();

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    setHasOptionsMenu(true);

    View view;

    view = inflater.inflate(R.layout.chat_layout, container, false);

    edittext = (EditText) view.findViewById(R.id.chatinput);
    listview = (ListView) view.findViewById(R.id.chatlist);

    listview.setAdapter(conversa);

    // EM CASO DE RETORNO DO SERVICE EM BACKGROUND, ROLAR A LISTA ATEH O FIM
    if (!conversa.getLog().isEmpty()) {
        scrollMyListViewToBottom();
    }

    // LISTENER QUE RECEBERA O "ENVIAR" DO TECLADO DO ANDROID
    edittext.setOnEditorActionListener(new OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId,
                KeyEvent event) {
            boolean handled = false;
            if (actionId == EditorInfo.IME_ACTION_SEND) {
                // ESCONDE O TECLADO APOS ENVIAR
                InputMethodManager in = (InputMethodManager) getActivity()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                in.hideSoftInputFromWindow(
                        edittext.getApplicationWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);

                sendMessage(target, edittext.getText().toString());

                // ALTERA O FLAG
                handled = true;

            }

            return handled;
        }
    });

    return view;
}

@Override
public void onDestroy() {
    activity.unregisterReceiver(BR_update_list);
    super.onDestroy();
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    if (target.equals(IRCService.CANAL)) {
        inflater.inflate(R.menu.canal_menu, menu);
    } else {
        inflater.inflate(R.menu.pvt_menu, menu);
    }
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.menu_closepvt:
        activity.removePVTTab(conversa.getTarget());
        return true;

    case R.id.menu_desconectar:
        activity.service.IRCdisconnect();
        return true;

    case R.id.menu_mudarnick:
        // TODO IMPLEMENTAR MUDANÇA DE NICK

        return true;
    }

    return false;

}

private void registerUpdateReceiver() {

    BR_update_list = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            conversa.notifyDataSetChanged();
        }
    };

    //a categoria sera o que definira qual fragment devera ser atualizado
    IntentFilter filter = new IntentFilter(IRCService.ACTION_RECEIVE_MSG);
    filter.addCategory(target);

    activity.registerReceiver(BR_update_list, filter);

}

public void sendMessage(String target, String msg) {
    activity.service.sendMessage(target, msg);

    // APAGA O EDITTEXT
    edittext.setText("");
}

private void scrollMyListViewToBottom() {
    listview.post(new Runnable() {
        @Override
        public void run() {
            // Select the last row so it will scroll into view...
            listview.setSelection(conversa.getCount() - 1);
        }
    });
}

public void setQuote(String nick) {
    ((MainActivity) getActivity()).drawerlayout.closeDrawers();
    edittext.setText("");
    edittext.append(nick + ": ");
    edittext.requestFocus();
}

}

This is only my receive message methods and adapter variables on service:

private List<Conversa> pvts;
private Conversa canal;
private UserList userList;


public void receivePVTMessage(String target, String nick, String msg) {

    Conversa pvt = getConversa(target);

    if (pvt == null) {
        addPVTConversa(target);
        pvt = getConversa(target);
    }

    pvt.log.add(Colors.removeFormattingAndColors("<" + nick + "> " + msg));

    // é dessa forma que o fragment fará o notifydatasetchanged na UI
    // thread, a categoria define qual fragment sera atualizado.
    Intent it = new Intent(IRCService.ACTION_RECEIVE_MSG);
    it.addCategory(target);
    sendBroadcast(it);

}

/**
 * Metodo usado para adicionar mensagens de usuarios na janela do chat
 */
public void receiveChatMessage(String nick, String msg) {
    canal.log
            .add(Colors.removeFormattingAndColors("<" + nick + "> " + msg));

    // é dessa forma que o fragment fará o notifydatasetchanged na UI
    // thread, a categoria define qual fragment sera atualizado.
    Intent it = new Intent(IRCService.ACTION_RECEIVE_MSG);
    it.addCategory(IRCService.CANAL);
    sendBroadcast(it);

}

/**
 * Metodo usado para adicionar mensagens gerais na janela do chat
 */
public void receiveChatMessage(String msg) {
    canal.log.add(Colors.removeFormattingAndColors(msg));

    // é dessa forma que o fragment fará o notifydatasetchanged na UI
    // thread, a categoria define qual fragment sera atualizado.
    Intent it = new Intent(IRCService.ACTION_RECEIVE_MSG);
    it.addCategory(IRCService.CANAL);
    sendBroadcast(it);

}

The same thing happens on my message log list and to my user list (nick list). The userlist adapter is on service too, and i have a listfragment to show it; In both cases i'm updating the arraylists from service, and notifying them adapters by sendBroadcast() and receiving on fragment that holds the adapter;

Was it helpful?

Solution

I do what i need by using the Handler to get access to the main thread. Handler handler = new Handler(Looper.getMainLoop);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top