Summaray:我正在使用ListView来实现聊天。列表视图中的每个条目都是发送或接收的消息,可以是文本或图像。当发送图像时,asynctask对象将...
我有这个工作到第3部分。我不知道如何修改在步骤1中添加的ListView条目的进度微调器。请记住,在步骤1中将条目添加到ListView后,还有更多条目(聊天消息)可能已添加到存储列表中使用的数据的数组中。还有其他线程可以向此阵列添加数据。
当我通过ArrayAdapter执行add时,我不知道它添加到哪个索引。我知道它在Array的末尾,所以我考虑保存从执行getCount()获得的索引但是因为有多个线程向Array添加数据我相信add和getCount操作必须是原子的,他们不是!
我可以就如何继续使用一些建议。
ArrayAdapter:
public class ChatArrayAdapter extends ArrayAdapter<ChatListEntry>{
private static final String TAG = "Kingfisher";
private TextView message;
private List<ChatListEntry> messages = new ArrayList<ChatListEntry>();
private RelativeLayout wrapper;
private LinearLayout wrapper_text_entry;
static class ViewHolder {
public ImageButton btn_showFSImageActivity;
ImageView imgCaptureThbnail;
}
public ChatArrayAdapter(Context context, int textview_resourceID) {
super(context, textview_resourceID);
}
@Override
public void add(ChatListEntry object) {
messages.add(object);
super.add(object);
}
public int getCount() {
return this.messages.size();
}
public ChatListEntry getItem(int index) {
return this.messages.get(index);
}
/**
* Every new item that is added to the ListView gets a new View inflater
* and loads specified layout. Even if the View/Layout is already loaded.
* ie the same type of message is being added to the chat listview.
* This is easier to code, I dont have to check what the view/layout is
* currently loaded, but this may not be the most efficient way to do it.
*/
public View getView(int position, View convertView, ViewGroup parent) {
//test - id like to see every time getView is invoked. print to log.
Log.i(TAG, "getview invoked.");
View row = convertView;
final ChatListEntry chatentry = getItem(position);
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(chatentry.msgType.equals("IMG")) {
row = inflater.inflate(R.layout.list_view_row_img, parent, false);
if(chatentry.isOutbound == false) {
chatentry.imgthmbnail = createThumbnailImg(getBitmapFromURL(chatentry.content));
//test
Log.i(TAG, "bitmap width is" + chatentry.imgthmbnail.getWidth());
}
wrapper = (RelativeLayout) row.findViewById(R.id.wrapper);
ViewHolder viewHolder = new ViewHolder();
viewHolder.btn_showFSImageActivity = (ImageButton) row.findViewById(R.id.upload_img_thmbnail);
viewHolder.imgCaptureThbnail = (ImageView) row.findViewById(R.id.upload_img_thmbnail);
viewHolder.imgCaptureThbnail.setImageBitmap(chatentry.imgthmbnail);
row.setTag(viewHolder);
//testing
Log.i(TAG,"img received from srv. Here is associtated text content: " + chatentry.content);
viewHolder.btn_showFSImageActivity.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i(TAG,"yay button clicked, here is chatentry.content:" + chatentry.content);
MainActivity main_act = (MainActivity) v.getContext();
main_act.onShowImgInActivity(chatentry.content);
}
});
wrapper.setBackgroundResource(chatentry.isOutbound ? R.drawable.bubble_green : R.drawable.bubble_yellow);
wrapper.setGravity(chatentry.isOutbound ? Gravity.RIGHT : Gravity.LEFT);
} else if(chatentry.msgType.equals("TXT")) {
row = inflater.inflate(R.layout.list_view_row, parent, false);
wrapper_text_entry = (LinearLayout) row.findViewById(R.id.wrapper_listviewtextrow);
message = (TextView) row.findViewById(R.id.textview_chatmsg);
message.setText(chatentry.content);
message.setBackgroundResource(chatentry.isOutbound ? R.drawable.bubble_green : R.drawable.bubble_yellow);
wrapper_text_entry.setGravity(chatentry.isOutbound ? Gravity.RIGHT : Gravity.LEFT);
} else
Log.e(TAG, "Something has gone terribly wrong in ChatArrayAdapter-getView.");
return row;
}
}
AsyncTask类:
public class ServerTask_UploadContent extends AsyncTask<String, Integer , Void> {
private String SERVERURL;
private final static String INPUT_IMG_FILENAME = "/imgcapture_temp.jpg";
//Task state
private final int UPLOADING_PHOTO_STATE = 0;
private final int SERVER_PROC_STATE = 1;
private ProgressDialog dialog;
private String fname; /* file name for file to be uploaded */
private String uploadFilePath; /* file name on android storage to be uploaded. */
private MainActivity app;
private static final String TAG = "Kingfisher";
private int lstvwentrnum = -1; //index were captured image is being saved in listview.
public ServerTask_UploadContent(Context c) {
super();
app = (MainActivity) c;
SERVERURL = app.getString(R.string.srv_domain) + app.getString(R.string.srv_uploadfile);
}
//upload photo to server
private HttpURLConnection uploadPhoto(FileInputStream fileInputStream)
{
fname = createTimeStamp() + ".jpg";
final String lineEnd = "\r\n";
final String twoHyphens = "--";
final String boundary = "*****";
try
{
URL url = new URL(SERVERURL);
// Open a HTTP connection to the URL
final HttpURLConnection conn = (HttpURLConnection)url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
dos.writeBytes(twoHyphens + boundary + lineEnd);
if( uploadFilePath.compareTo((Environment.getExternalStorageDirectory().toString() + INPUT_IMG_FILENAME)) == 0 )
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + fname +"\"" + lineEnd);
else
{
Log.e(TAG, "Something has gone wrong passing video to HTTPImgUploader. " +
"path passed to class is: " + uploadFilePath + "\n" +
"path using getexternalstoragedircotry function is: " +
(Environment.getExternalStorageDirectory().toString()));
System.exit(-1);
}
dos.writeBytes(lineEnd);
// create a buffer of maximum size
int bytesAvailable = fileInputStream.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
Log.d(TAG, "buffer: " + buffer);
while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
// send multipart form data after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
publishProgress(SERVER_PROC_STATE);
// close streams
fileInputStream.close();
dos.flush();
return conn;
}
catch (MalformedURLException ex){
Log.e(TAG, "error: " + ex.getMessage(), ex);
return null;
}
catch (IOException ioe){
Log.e(TAG, "error: " + ioe.getMessage(), ioe);
return null;
}
}
protected void onPreExecute()
{
app.addImgToChat(fname);
}
@Override
protected Void doInBackground(String... params)
{
uploadFilePath = params[0];
processImage(uploadFilePath);
return null;
}
@Override
protected void onPostExecute(Void param)
{
app.sendFileUploadSuccessMsg(fname);
}
答案 0 :(得分:0)
为什么不为ChatListEntry模型分配额外的字段,为每条消息提供唯一的ID?
正如您所说,如果您遇到的问题是此ArrayList可以从不同的进程获取条目,您可以在模型类中保留一个静态值,您可以将其用作参考自动增量值。应用。这样您就可以确保每条消息都有唯一的标识符。
我会做类似的事情:
public class ChatListEntry {
private static int INCREMENTAL_ID = 0;
// Fields:
private int id;
...
//----
// Constructor:
public ChatListEntry(id){
this.id = id;
}
public static int getNextId(){
return INCREMENTAL_ID++;
}
}
然后按如下方式构建它们:
ChatListEntry cle = new ChatListEntry(ChatListEntry.getNextId());
然后,您可以轻松地将项目ID传播回MainActivity方法,我假设处理项目布局并使ListView无效......
对您的自定义AsyncTask
进行少量修改后,您甚至可以将其桥接(如果必须)。
类似的东西:
public class ServerTask_UploadContent extends AsyncTask<String, Integer , Void> {
private final int messageId = ChatListEntry.getNextId();
protected void onPreExecute()
{
ChatListEntry newCle = new ChatListEntry(messageId);
newCle.setFname(fname);
// You send copy of the object with unique Id:
app.addImgToChat(newCle);
}
@Override
protected Void doInBackground(String... params)
{
uploadFilePath = params[0];
processImage(uploadFilePath);
return null;
}
@Override
protected void onPostExecute(String messageId)
{
// You notify with messageId wich item to point to:
app.sendFileUploadSuccessMsg(fname,messageId);
}
}
然后,您可以在ArrayList<ChatListEntry>
sendFileUploadSuccessMsg()
内找到该特定项目,将ProgressBar
设置为隐藏/替换它,最后调用notifyDataSetChanged()
您的ChatArrayAdapter
}}