0

我開發一個聊天應用程序,我的適配器(BaseAdapter),持有聊天日誌,在服務,導致變量,讓我的IRC資源在服務。當活動綁定時,我的聊天片段從服務中獲取適配器。 起初,我試圖從適配器本身通知DataSetChanged(),然後我發現我需要從主UI線程調用它。所以我發送廣播片段來通知內部的適配器,片段使用主UI線程。 現在,即時通訊這個問題導致即時通訊提供列表之外的UI線程(從服務),並通知主線程。但它在Service上需要這個適配器。 我該怎麼辦?適配器的內容已更改,但ListView未收到通知。 (喂主列主線)

這是我的適配器。每次對話都有一個。該適配器將保持服務:

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; 
} 

}

這是我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(); 
} 

}

這只是我收到服務消息的方法和適配器變量:

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); 

} 

同樣的事情發生在我的消息日誌列表和我的用戶列表(尼克列表)上。用戶列表適配器也在服務中,並且我有一個listfragment來顯示它; 在這兩種情況下,我從服務更新arraylist,並通過sendBroadcast()通知適配器和接收包含適配器的片段;

+0

很難說沒有任何代碼。 – cyroxis

+0

雖然它可能工作,但我會說你正在使用危險的結構。理想的情況是服務會發布消息,然後在您的活動中,您會收到此消息並填寫適配器(您可以使用已編碼的廣播消息發送新消息數據而不是無效請求)。無論如何,你得到的錯誤意味着適配器內容已經改變,而你還沒有調用notifyDataSetChanged():ListView檢測到它自己的內容已經改變'後門'。這打破了ListView內部。 – rupps

+0

只要我更新列表,我每次都發送廣播通知數據。問題是關於多線程。但即使活動已關閉,我仍需要收到消息。該服務必須收到消息。適配器必須在使用中。 –

回答

0

我通過使用Handler來訪問主線程來做我所需要的。 Handler handler = new Handler(Looper.getMainLoop);

相關問題