简体   繁体   English

从自定义适配器(而不是从主要活动)开始意图 - 如何实现活动结果以重新加载适配器中的视图?

[英]Starting an intent from custom adapter (not from the main activity) - how to implement on activity result to reload views in adapter?

In my app, I am implementing a custom adapter for a recycler view with multiple views.在我的应用程序中,我正在为具有多个视图的回收器视图实现自定义适配器。 In my adapter, I case on my list of objects passed in from the main activity and set my views and onClickListeners there.在我的适配器中,我列出了从主活动传入的对象列表,并在那里设置了我的视图和 onClickListeners。 For one of the intents I fire, I am editing something which I set in my adapter.对于我触发的意图之一,我正在编辑我在适配器中设置的内容。 After the activity returns - the adapter does not update.活动返回后 - 适配器不会更新。 I am not sure how I would implement an interface or onActivityForResult() method for my adapter to reconfigure this view in my RecyclerView after the activity finishes.我不确定如何为我的适配器实现接口或 onActivityForResult() 方法,以便在活动完成后在我的 RecyclerView 中重新配置此视图。

I tried implementing an interface but am not sure how to do this exactly as I declare my adapter in my main activity (fragment) and then from there add a list of objects.我尝试实现一个接口,但不确定如何完全按照我在主要活动(片段)中声明的适配器来执行此操作,然后从那里添加对象列表。 In my adapter, I set my views there based on which object is added.在我的适配器中,我根据添加的对象在那里设置我的视图。

Here is the relevant code from my main fragment class: I am adding various objects to mObjects.这是我的主要片段类中的相关代码:我正在向 mObjects 添加各种对象。

public class ProfileFragment extends Fragment{
    public final static String TAG = "ProfileFragment";  // tag for logging from this activity
    final ParseUser user = ParseUser.getCurrentUser();

    // For post feed:
    ArrayList<Object> mObjects;
    ArrayList<Post> mPosts;
    RecyclerView mLayout;
    MultiViewAdapter mMultiAdapter;

    // For stats view:
    HashMap<String, Integer> mCities;  // Contains the cities and number of times visited by user
    HashMap<String, Integer> mCountries;  // Contains the countries and number of times visited by user
    HashMap<String, Integer> mContinents;  // Contains the continents and number of times visited by user


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_profile, container, false);
        setUpLogOutButton(v);

        // Populate stat maps and get posts
        mObjects = new ArrayList<>();
        mCities = new HashMap<>();
        mCountries = new HashMap<>();
        mContinents = new HashMap<>();
        mPosts = new ArrayList<>();

        // Get posts
        getPosts();
        mObjects.add(user);

        // For post feed view:
        mMultiAdapter = new MultiViewAdapter(getActivity(), mObjects);

        mLayout = v.findViewById(R.id.rvPosts);
        mLayout.setLayoutManager(new LinearLayoutManager(getContext()));
        mLayout.setAdapter(mMultiAdapter);

        return v;
    }
}

Here is the relevant code from my adapter:这是我的适配器中的相关代码:

public class MultiViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    Context mContext;
    ArrayList<Object> items;

    // Identifier for objects in items and which view to load:
    private final int USER_INFO = 0, POST = 1, STAT = 2;

    // The total number of cities, countries, and continents in the world:
    public final int totalNumCities = 4416;
    public final int totalNumCountries = 195;
    public final int totalNumContinents = 7;

    public MultiViewAdapter(Context context, ArrayList<Object> items) {
        this.items = items;
        this.mContext = context;
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    //Returns the view type of the item at position for the purposes of view recycling.
    @Override
    public int getItemViewType(int position) {
        if (items.get(position) instanceof Post) {
            return POST;
        } else if (items.get(position) instanceof ParseUser) {
            return USER_INFO;
        } else if(items.get(position) instanceof HashMap){
            return STAT;
        }
        return -1;
    }


    /**
     * This method creates different RecyclerView.ViewHolder objects based on the item view type.
     *
     * @param viewGroup ViewGroup container for the item
     * @param viewType  type of view to be inflated
     * @return viewHolder to be inflated
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        RecyclerView.ViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
        switch (viewType) {
            case POST:
                View v1 = inflater.inflate(R.layout.item_post_card, viewGroup, false);
                viewHolder = new PostViewHolder(v1);
                break;
            case USER_INFO:
                View v2 = inflater.inflate(R.layout.item_user_information, viewGroup, false);
                viewHolder = new UserInfoViewHolder(v2);
                break;
            case STAT:
                View v3 = inflater.inflate(R.layout.item_user_stats, viewGroup, false);
                viewHolder = new StatViewHolder(v3);
        }
        return viewHolder;
    }

    /**
     * This method internally calls onBindViewHolder(ViewHolder, int) to update the
     * RecyclerView.ViewHolder contents with the item at the given position
     * and also sets up some private fields to be used by RecyclerView.
     *
     * @param viewHolder The type of RecyclerView.ViewHolder to populate
     * @param position   Item position in the viewgroup.
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        switch (viewHolder.getItemViewType()) {
            case POST:
                PostViewHolder vh1 = (PostViewHolder) viewHolder;
                configurePostViewHolder(vh1, position);
                break;
            case USER_INFO:
                UserInfoViewHolder vh2 = (UserInfoViewHolder) viewHolder;
                configureUserInfoViewHolder(vh2, position);
                break;
            case STAT:
                StatViewHolder vh3 = (StatViewHolder) viewHolder;
                configureStatViewHolder(vh3, position);
                break;
        }
    }

    private void configureStatViewHolder(final StatViewHolder vh3, final int position){
        final HashMap<String, Integer> cities = (HashMap<String, Integer>) items.get(position);
        if(cities!= null){
            // For pie chart
            // Cities:
            // TODO: add pie chart for continents and countries and put this in seperate method
            List<PieEntry> pieEntries = new ArrayList<>();
            pieEntries.add(new PieEntry(cities.size(), "Visited Cities"));
            pieEntries.add(new PieEntry(totalNumCities-cities.size(), "Unvisited Cities"));
            PieDataSet pieDataSet = new PieDataSet(pieEntries, "City Stats");
            pieDataSet.setColors(R.color.colorPrimary, R.color.colorPrimaryDark);
            PieData pieData = new PieData(pieDataSet);
            vh3.getmPieChart().setData(pieData);
            vh3.getmPieChart().animateY(1000);
            vh3.getmPieChart().invalidate();
        }
    }

    private void configurePostViewHolder(final PostViewHolder vh1, final int position) {
        final Post post = (Post) items.get(position);
        if (post != null) {
            vh1.getRootView().setTag(post);
            String cityName = post.getCity();
            String countryName = post.getCountry();
            String continentName = post.getContinent();
            vh1.getTvName().setText(cityName + ", " + countryName + ", " + continentName);
            vh1.getTvName().setTextColor(Color.WHITE);
            vh1.getvPalette().setBackgroundColor(ContextCompat.getColor(mContext, R.color.grey));

            SimpleTarget<Bitmap> target = new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
                    vh1.getIvProfile().setImageBitmap(resource);
                    Palette p = Palette.from(resource).generate();
                    vh1.getvPalette().setBackgroundColor(ContextCompat.getColor(mContext, R.color.grey));
                }
            };

            vh1.getIvProfile().setTag(target);
            // TODO: Maybe don't crop image as it looks very small
            if(post.getImage()!=null) {
                Glide.with(mContext).asBitmap().load(post.getImage().getUrl()).centerCrop().into(target);
            } else {
                // TODO: fix default image loaded where no image present to be prettier
                Glide.with(mContext).asBitmap().load(R.drawable.ic_add_photo).centerCrop().into(target);
            }
            vh1.getIvProfile().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent it = new Intent(mContext, EditPost.class);
                    Bundle bundle = new Bundle();
                    bundle.putSerializable(Post.class.getSimpleName(), post);
                    it.putExtras(bundle);
                    // Start activity for result to reconfigure user view after return
                    ((Activity) mContext).startActivityForResult(it, 2121);
                }
            });
        }
    }

    private void configureUserInfoViewHolder(UserInfoViewHolder vh2, final int position) {
        ParseUser user = (ParseUser) items.get(position);
        if (user != null) {
            if (user.getParseFile("profileImg") != null) {
                vh2.setmIvProfileImage(user.getParseFile("profileImg").getUrl(), mContext);
            } else {
Glide.with(mContext).load(R.drawable.ic_user).into(vh2.getmIvProfileImage());
            }
            vh2.getmTvEditProfile().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent it = new Intent(mContext, UserSettings.class);
** SEE HERE FOR INTENT FIRED **
                    (mContext).startActivityForResult(it);
                }
            });
        }
    }

From there, I start my UserSettings activity where the user can change there information.从那里,我开始我的 UserSettings 活动,用户可以在其中更改那里的信息。

public class UserSettings extends AppCompatActivity {
    ImageView mIvProfileImage;
    TextView mTvEditPhoto;
    ImageView mIvBackArrow;
    ImageView mIvSave;
    EditText mEtUsername;
    EditText mEtNumber;
    EditText mEtEmail;
    public String photoFileName = "photo.jpg";
    public static final int REQUEST_CODE = 101;
    File mPhotoFile;
    ParseFile mParseFile;
    final ParseUser user = ParseUser.getCurrentUser();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_settings);
      //  mIntentListener = getCallingActivity()

        // Set Views
        mIvProfileImage = findViewById(R.id.ivProfileImageMain);
        mTvEditPhoto = findViewById(R.id.tvEditPhoto);
        mIvBackArrow = findViewById(R.id.ivBack);
        mEtUsername = findViewById(R.id.etUsername);
        mEtNumber = findViewById(R.id.etNumber);
        mEtEmail = findViewById(R.id.etEmail);
        mIvSave = findViewById(R.id.ivSave);
        updateCurrentViews();

        // Set on click listener for photo
        mTvEditPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialog.Builder builder = new AlertDialog.Builder(UserSettings.this);
                builder.setTitle("Upload or Take a Photo");
                builder.setPositiveButton("Upload", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // Upload image
                        startActivityForResult(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI), Constants.GET_FROM_GALLERY);
                    }
                });
                builder.setNegativeButton("Take a Photo", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // Take Photo
                        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                        PhotoHelper photoHelper = new PhotoHelper();
                        mPhotoFile = photoHelper.getPhotoFileUri(UserSettings.this, photoFileName);
                        Uri fileProvider = FileProvider.getUriForFile(UserSettings.this, "com.example.fileprovider", mPhotoFile);
                        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileProvider);
                        if (intent.resolveActivity(UserSettings.this.getPackageManager()) != null) {
                            startActivityForResult(intent, Constants.CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
                        }
                    }
                });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });

        // Go back to profile activity if user clicks back
        mIvBackArrow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

        mIvSave.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mParseFile != null) {
                    user.put("profileImg", mParseFile);
                }

                user.setEmail(mEtEmail.getText().toString());
                user.setUsername(mEtUsername.getText().toString());
                user.put("phone", mEtNumber.getText().toString());
                user.put("email", mEtEmail.getText().toString());
                setResult(RESULT_OK, new Intent());
                user.saveInBackground(new SaveCallback() {
                    @Override
                    public void done(ParseException e) {
                        updateCurrentViews();
                        finish();
                    }
                });
            }
        });
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, final Intent data) {
        if (requestCode == Constants.CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
            if (resultCode == this.RESULT_OK) {
                Bitmap takenImage = BitmapFactory.decodeFile(mPhotoFile.getAbsolutePath());
                mIvProfileImage.setImageBitmap(takenImage);
                PhotoHelper photoHelper = new PhotoHelper();
                File photoFile = photoHelper.getPhotoFileUri(this, photoFileName);
                mParseFile = new ParseFile(photoFile);
            } else {
                mParseFile = null;
                Toast.makeText(this, "Picture wasn't taken!", Toast.LENGTH_SHORT).show();
            }
        } else {
            if (resultCode == this.RESULT_OK) {
                Bitmap bitmap = null;
                Uri selectedImage = data.getData();
                try {
                    bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
                } catch (Exception e) {
                }
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                byte[] image = stream.toByteArray();
                mParseFile = new ParseFile("profpic.jpg", image);
                final Bitmap finalBitmap = bitmap;
                Glide.with(this).load(finalBitmap).into(mIvProfileImage);
            } else {
                mParseFile = null;
            }
        }
    }

    public void updateCurrentViews() {
        // For profile image:
        mIvProfileImage = findViewById(R.id.ivProfileImageMain);
        if (user.getParseFile("profileImg") != null) {
            Glide.with(this).load(user.getParseFile("profileImg").getUrl()).into(mIvProfileImage);
        } else {
            Glide.with(this).load(R.drawable.ic_user).into(mIvProfileImage);
        }

        // EditText:
        mEtUsername.setText(user.getUsername());
        mEtNumber.setText(String.format("%s", user.get("phone")));
        mEtEmail.setText(String.format("%s", user.get("email")));
    }
}

The issue is when the UserSettingsActivity finishes the updated information is not reflected in the adapter and it shows the old information.问题是当 UserSettingsActivity 完成时,更新的信息未反映在适配器中,而是显示旧信息。

EDIT RESPONSE IN REPLY TO COMMENT Here is my main activity:编辑回复评论以下是我的主要活动:

public class HomeActivity extends AppCompatActivity {
    final FragmentManager fragmentManager = getSupportFragmentManager();

    final Fragment fragment1 = new MapFragment();
    final Fragment fragment2 = new DiscoverFragment();
    final Fragment fragment3 = new ProfileFragment();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        navView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                Fragment fragment;
                switch (menuItem.getItemId()) {
                    case R.id.navigation_home:
                        fragment = fragment1;
                        break;
                    case R.id.navigation_dashboard:
                        fragment = fragment2;
                        break;
                    case R.id.navigation_notifications:
                    default:
                        fragment = fragment3;
                        break;
                }
                fragmentManager.beginTransaction().replace(R.id.flContainer, fragment).commit();
                return true;
            }
        });
        navView.setSelectedItemId(R.id.navigation_home);
    }

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

And in my ProfileFragment I have added:在我的 ProfileFragment 中,我添加了:

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode == 2121){
            // the user information is at item 0
            mMultiAdapter.notifyItemChanged(0);
        }
    }

In Adapter I start the activity here with the code:在 Adapter 中,我使用以下代码开始活动:

((Activity) mContext).startActivityForResult(it, 2121);

You need to have onActivityResult() function in your ProfileFragment since it will be called when UserSettings activity is finished.您需要在 ProfileFragment 中有 onActivityResult() 函数,因为它会在 UserSettings 活动完成时被调用。 From there you get the intent, and get changed data.从那里你得到意图,并获得改变的数据。 Your ProfileFragment has an instance of adapter so you would call notifyItemChanged function after updating the object.您的 ProfileFragment 有一个适配器实例,因此您可以在更新对象后调用 notifyItemChanged 函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM