适配器和活动之间的通信?

时间:2014-10-17 08:07:31

标签: android

我在listview中有一个layout,每个项目都有两个部分:一个是用户头像(ImageView),另一个是聊天内容({{1} })。看起来像:

enter image description here

我有一个自定义TextView

我想实现:当我点击头像时,我可以进入系统库并选择一张照片作为头像。

所以我在adapter课程中关于onClickListener的代码是:

adapter

我还覆盖了活动中的 Intent itent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); ((Activity)(context)).startActivityForResult(itent, LOAD_IMAGE_RESULT); 方法。

但是,我上面提到的解决方案无法更改onActivityResult方法中的头像,因为我不知道如何在onActivityResultadapter之间进行通信。

希望找到解决方案。

4 个答案:

答案 0 :(得分:2)

编辑 - 最初,我刚刚展示了一种更新子视图的方法,只是让它的适配器处于不一致状态(因为原始问题不提供有关基础数据结构的更多信息)。

  

适配器:Adapter对象充当AdapterView与该视图的基础数据之间的桥梁。适配器提供访问权限   数据项。适配器还负责制作View for   数据集中的每个项目。

注意: 由于定义本身描述了维护状态(数据+视图)很重要。因此,您应该始终拥有一致的用户体验。

为了正确地给出示例,我还根据原始问题中给定图像的假设定义了数据模型类ItemData

/**
 * Model Class
 */  
public class ItemData {

    private Uri imageUri;
    private String msg;
    private Date timeStamp;

    public void setImageUri(Uri uri) {
        this.imageUri = uri;
    }

    public Uri getImageUri() {
        return this.imageUri;
    }

    ...
}

<强> CustomAdapter

为listView创建自定义适配器,它将相应地维护子视图及其数据集。您必须维护最后选择的行索引lastSelectedIndexRow的引用,稍后可以使用它来更新视图。

注意: 要获取listView中任何索引的视图,我们不应该调用适配器的getView()方法。由于对convertView调用getView()为null会导致适配器从适配器的布局资源中膨胀新视图(不会获取已经显示的视图)。

AdapterView 应始终根据适配器保留的当前数据集使用notifyDataSetChanged()进行更新。

public class CustomAdapter extends BaseAdapter {

    private Context context;
    private LayoutInflater inflater;

    private List<ItemData> dataList;

    private int lastSelectedRowIndex = -1;
    public static int LOAD_IMAGE_RESULT = 201;

    public CustomAdapter(Context context, ArrayList<ItemData> dataList) {

        // hold the items
        this.context = context;
        this.dataList = dataList;

        this.inflater = LayoutInflater.from(this.context);
    }

    @Override
    public int getCount() {
         return (dataList != null && !dataList.isEmpty()) ? dataList.size() : 0;
    }

    @Override
    public ItemData getItem(int position) {
        return (dataList != null && !dataList.isEmpty()) ? dataList.get(position) : null;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolderItem viewHolder;
        if (converView == null) {

             // inflate the layout
             convertView = inflater.inflate(R.layout.row_item, parent, false);

             // well set up the ViewHolder
             viewHolder = new ViewHolderItem();
             viewHolder.avatar = (ImageButton)view.findById(R.id.avatar); 

             // store the holder with the view.
             convertView.setTag(viewHolder);    
        }
        else {
             // we've just avoided calling findViewById() on resource every time
             // just use the viewHolder
             viewHolder = (ViewHolderItem) convertView.getTag();
        }

        // Set row data
        ItemData data = (ItemData)getItem(position);
        if (data != null) {

            // set message
            viewHolder.message.setText(data.getMessage());

            // set formatted timestamp
            String formattedTimeStamp = ...; // convert data.getTimeStamp() into formatted version
            viewHolder.timeStamp.setTextView(formattedTimeStamp);

            // set Image and also it's action.
            viewHolder.avatar.setImageUri(data.getImageUri());
            viewHolder.avatar.setOnClickListener(new View.OnClickListener() {

               @Override
               public void onClick(View view) {
                  try {

                      Intent intent = new Intent(Intent.ACTION_PICK,
                            MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

                      ((Activity)context).startActivityForResult(intent, LOAD_IMAGE_RESULT);
                  } catch (Exception e) {
                     Log.e("Demo application", "Failed to invoke call", e);
                  }
              }
           }
        }
    }

    /**
     * Get the last selected item index
     *
     */ 
    public int getLastSelectedItemIndex() {
       return lastSelectedRowIndex;
    }

    /**
     * Update the adapater with new data
     *
     */ 
    public void updateItems(List<ItemData> dataList) {

        if (this.dataList != dataList)
            this.dataList = dataList;

        // update the view.
        notifyDataSetChanged(); 

        // reset the last selection
        lastSelectedRowIndex = -1; 
    }

    /**
     * Hold View items 
     */   
    static class ViewHolderItem {

        private ImageView avatar;
        private TextView message;
        private TextView timeStamp;
    }
}

<强>为ExampleActivity

在活动中,您需要定义自定义适配器的引用并使用onActivityResult()方法处理图像选择结果。从库中获取所选图像后,更新dataList内的基础数据,并通过调用updateItems()自定义方法更新适配器。

适配器的updateItems()方法将新数据列表作为参数,并通过调用notifyDataSetChanged()使adapterView无效。

public class ExampleActivity extend FragmentActivity {

     private ListView listView;
     private CustomAdapter adapter; 

     private List<ItemData> dataList;

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

         dataList = ...; // Load the list from database

         // Create the custom adapter with filled list items.
         adapter = new CustomAdapter(this, dataList);

         // List View and set the data adapter
         listView = (ListView)findViewById(R.id.listView);
         listView.setAdapter(adapter);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);

         // Check if it's coming from MediaStore Selection.
         if (resultCode == Activity.RESULT_OK && 
                   requestCode == CustomAdapter.LOAD_IMAGE_RESULT) {

             // Get the selected rowIndex 
             if (adapter != null && dataList != null) {

                  // check the row index is valid
                  int rowIndex = adapter.getLastSelectedItemIndex();
                  if (rowIndex > -1 && rowIndex < dataList.size()) {

                       // Get the item
                       ItemData item = dataList.get(rowIndex);

                       // Update the item with imageUri
                       item.setImageUri(Uri.parse(data.getData()));

                       /**
                        * If you may want to update the information in database, 
                        * then it's the best place, but please do in background thread.
                        */

                      //Now notify the adapter with new changes
                      adapter.updateItems(dataList);
                  }
             }
         }
    }

    ...
}

答案 1 :(得分:0)

您应该在onClickListener方法中保存对单击视图的引用,并在适配器中使用公共方法。当您在onActivityResult方法中获得响应时,请调用适配器的方法并使用

答案 2 :(得分:-1)

在适配器中,(不确定使用哪种适配器),为ImageView设置onClickListener。因此,

mImageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
                <INSERT CODE HERE>
                mContext.startActivity(intent);
        }
    });

其中mImageView是该项目的ImageView。另外一个好主意可能是使用ImageButton,因为它允许图像,并且是一个你想要的按钮。然后通过添加要选择图像的代码。您可能还需要将上下文传递给适配器(但无论如何通常都会这样做)。然后,您可以在适配器所在的活动中处理onActivityResult方法,即将Image设置为您选择的图像。有几种方法可以做到这一点。

答案 3 :(得分:-1)

在自定义适配器中添加公共方法以设置图像(如public void setAvatar(Bitmap image)

然后,在您的onActivityResult方法中,选择图像并使用新创建的方法在适配器中设置新图像。 (有关更多信息,请参见此处:Getting a Result from an Activity

请勿忘记在适配器的新方法末尾放置notifyDataSetChanged();以刷新所有列表。

public void setAvatar(Bitmap image)
{
    ...

    imageView.setImageBitmap(image);
    ...

    notifyDataSetChanged();
}

此外,如果您需要知道点击了哪个图片,可以指定Integer作为参数,并在onActivityResult中进行检查。
我看到你为这个参数使用常量LOAD_IMAGE_RESULT。而不是一个常量,放一个识别被点击项的整数。