Chap 24 Challenge: Layout Question


#1

Completed the challenge by creating my own Activity Holder item layout file, but wondered if any of the “standard” layouts like android.R.layout.simple_list_item_1 could have helped. The one-line descriptions in the documentation are pretty sketchy. Are there better descriptions, or even example screens, of what these look like? Or is that another challenge? :wink:


#2

Doesn’t seem like it! I tried to use android.R.layout.simple_gallery_item to see if I could display icons only but got casting errors.

Then I tried to put an ImageView within fragment_nerd_launcher.xml but ended up with the RecyclerView has no LayoutManager error.

So eventually was forced to create a new list_item_app.xml layout and that worked well enough (some of the icons came out much larger than the others).


#3

I use android.R.layout.activity_list_item and it just work.
Here is my code:

NerdLauncherFragment.java
package com.bignerdranch.android.nerdlauncher;

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by behin on 10/22/2017.
 */

public class NerdLauncherFragment extends Fragment {
	private static final String TAG = "NerdLauncherFragment";
	private RecyclerView  mRecyclerView;

	public static NerdLauncherFragment newInstance() {
		return new NerdLauncherFragment();
	}

	@Nullable
	@Override
	public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
		View v = inflater.inflate(R.layout.fragment_nerd_launcher, container, false);
		mRecyclerView = v.findViewById(R.id.app_recycler_view);
		mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

		setupAdapter();

		return v;
	}

	private void setupAdapter() {
		Intent startupIntent = new Intent(Intent.ACTION_MAIN);
		startupIntent.addCategory(Intent.CATEGORY_LAUNCHER);

		PackageManager pm = getActivity().getPackageManager();
		List<ResolveInfo> activities = pm.queryIntentActivities(startupIntent, 0);
		Collections.sort(activities, new Comparator<ResolveInfo>() {
			@Override
			public int compare(ResolveInfo a, ResolveInfo b) {
				PackageManager pm = getActivity().getPackageManager();
				return String.CASE_INSENSITIVE_ORDER.compare(
						a.loadLabel(pm).toString(),
						b.loadLabel(pm).toString()
				);
			}
		});

		Log.i(TAG, "Found " + activities.size() + " activities.");
		mRecyclerView.setAdapter(new ActivityAdapter(activities));
	}

	private class ActivityHolder extends RecyclerView.ViewHolder
			implements  View.OnClickListener{
		private ResolveInfo mResolveInfo;
		private TextView mNameTextView;
		private ImageView mIconImageView;


		public ActivityHolder(View itemView) {
			super(itemView);
			itemView.setOnClickListener(this);
			mNameTextView =  itemView.findViewById(android.R.id.text1);
			mIconImageView = itemView.findViewById(android.R.id.icon);
		}

		public void bindActivity(ResolveInfo resolveInfo) {
			mResolveInfo = resolveInfo;
			PackageManager pm = getActivity().getPackageManager();
			String appName = mResolveInfo.loadLabel(pm).toString();
			Drawable appIcon = mResolveInfo.loadIcon(pm);
			mNameTextView.setText(appName);
			mIconImageView.setImageDrawable(appIcon);
		}

		@Override
		public void onClick(View view) {
			ActivityInfo activityInfo = mResolveInfo.activityInfo;

			Intent i = new Intent(Intent.ACTION_MAIN)
					.setClassName(activityInfo.applicationInfo.packageName, activityInfo.name)
					.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

			startActivity(i);
		}
	}

	private class ActivityAdapter extends RecyclerView.Adapter<ActivityHolder> {
		private final List<ResolveInfo> mActivities;

		public ActivityAdapter(List<ResolveInfo> activities) {
			mActivities = activities;
		}

		@Override
		public ActivityHolder onCreateViewHolder(ViewGroup parent, int viewType) {
			LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
			View view = layoutInflater
					.inflate(android.R.layout.activity_list_item, parent, false);

			return new ActivityHolder(view);
		}

		@Override
		public void onBindViewHolder(ActivityHolder holder, int position) {
			ResolveInfo resolveInfo = mActivities.get(position);
			holder.bindActivity(resolveInfo);
		}

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

#4

I used the same simple_list_item_1 layout. Remember, that an image can be set even on a TextView with the following command:

nameTextView.setCompoundDrawablesWithIntrinsicBounds(
        Drawable left, 
        Drawable top, 
        Drawable right,
    	Drawable bottom
);

However, I had to resize, because not all of the apps in my mobile used the same app icon size. So, resize and use the above command, setting your icon in any one of the above-mentioned positions and use null for the remaining positions.