如何:在onPreExecute中将子项添加到listview,然后更改onPostExecute中添加的项的视图

时间:2014-08-03 01:35:48

标签: android android-listview android-asynctask

Summaray:我正在使用ListView来实现聊天。列表视图中的每个条目都是发送或接收的消息,可以是文本或图像。当发送图像时,asynctask对象将...

  1. protected void onPreExecute()在列表视图中插入一个条目,它包含正在发送的图像的缩略图和进度微调器。
  2. protected Void doInBackground(String ... params) - 将上传图片。
  3. protected void onPostExecute(Void param) - 应将步骤1中添加的条目中的进度微调器设置为不可见。
  4. 我有这个工作到第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);
    }
    

1 个答案:

答案 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 }}