I am facing an issue where I am getting ArrayIndexOutOfBound on photoViewAttacherList.get(position). Now I can easily handle by catching the error, but I am not able to understand why it is happening at the very first place. Here is the code of the adapter. It's strange because I am adding the new PhotoViewAttacher in instantiate function which will be called for every new item added.
public class FullImagePagerAdaptor extends PagerAdapter {
private final LayoutInflater inflater;
private final ArrayList<String> urls;
private final Context context;
private final ArrayList<String> descriptions;
private ArrayList<PhotoViewAttacher> photoViewAttacherList;
private TogglePagingListener togglePagingListener;
public FullImagePagerAdaptor(Context context, ArrayList<String> urls, ArrayList<String>
descriptions, TogglePagingListener togglePagingListener) {
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.urls = urls;
this.context = context;
this.descriptions = descriptions;
photoViewAttacherList = new ArrayList<>();
this.togglePagingListener = togglePagingListener;
}
#Override
public int getCount() {
return urls.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, final int position) {
View v = inflater.inflate(R.layout.fragment_full_image, container, false);
TextView description = (TextView) v.findViewById(R.id.txt_full_image_description);
ProgressBar progressBar = (ProgressBar) v.findViewById(R.id.progress_bar_full_image);
ImageView imageView = (ImageView) v.findViewById(R.id.full_image_view);
if (descriptions != null && descriptions.get(position) != null) {
description.setText(descriptions.get(position));
}
Log.d("sg","Instantiating Pager:with position" + position);
ImageUtility.loadImage(context, urls.get(position),
GlobalVariables.IMAGE_TYPE.URL, 0, 0,
imageView, progressBar);
photoViewAttacherList.add(new PhotoViewAttacher(imageView));
// THIS IS WHERE ARRAYINDEXOUTOFBOUND EXCEPTION IS GETTING RAISED
photoViewAttacherList.get(position).setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() {
#Override
public void onMatrixChanged(RectF rect) {
if(isImageZoomed(position))
togglePagingListener.disablePaging();
else
togglePagingListener.enablePaging();
}
});
container.addView(v);
return v;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
photoViewAttacherList = null;
container.removeView((View) object);
}
public boolean isImageZoomed(int pos) {
return checkZoom(pos) != 1.0;
}
public float checkZoom(int pos){
return photoViewAttacherList.get(pos).getScale();
}
public interface TogglePagingListener {
public void enablePaging();
public void disablePaging();
}
From your code I understand one thing that, you want to add a new PhotoViewAttacher object to your existing list and add a listener setOnMatrixChangeListener to that object.
For this you are adding that object in list and then accessing the same again from list, rather you can have an object created and add to list and to the same object you can add event listener. This is a clean approach.
position should also be recalculated to know exactly where the element was inserted but this is final so you can not change it so declare a new variable for it.
Snippet:
PhotoViewAttacher photoObj = new PhotoViewAttacher(imageView);
photoViewAttacherList.add(photoObj);
final int newPositionInserted = photoViewAttacherList.size() - 1; //Recalculating the position here to know exactly where the object was added
// Here you can use the object which was created so you do not need to worry about the index also
photoObj.setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() {
#Override
public void onMatrixChanged(RectF rect) {
if(isImageZoomed(newPositionInserted))
togglePagingListener.disablePaging();
else
togglePagingListener.enablePaging();
}
});
Related
i created a custom listView of all installed apps but i don't know how to add a search functionality because it's a little complicated(..my app) can anyone help me with that?
(picture of the app )
App.java - app constructor
public class App {
private int number;
private String name;
private String version;
private Drawable drawable;
public App(int number, String name, String version, Drawable drawable){
this.number = number;
this.name = name;
this.version = version;
this.drawable = drawable;
}
//Getters & Setters...
}
AppAdapter.java - listView Adapter
public class AppAdapter extends ArrayAdapter<App> {
Context context;
List<App> objects;
public AppAdapter(Context context, int resources, int textViewResources, List<App> objects){
super(context, resources, textViewResources, objects);
this.context = context;
this.objects = objects;
}
public View getView(int position, View convertView, ViewGroup parent){
LayoutInflater layoutInflater = ((Activity)context).getLayoutInflater();
View view = layoutInflater.inflate(R.layout.custom_card,parent,false);
TextView tvName = (TextView)view.findViewById(R.id.tvName);
TextView tvVersion = (TextView)view.findViewById(R.id.tvVersion);
TextView tvNumber = (TextView)view.findViewById(R.id.tvNumber);
ImageView ivImage = (ImageView)view.findViewById(R.id.ivImage);
App current = objects.get(position);
tvName.setText(String.valueOf(current.getName()));
tvVersion.setText(String.valueOf(current.getVersion()));
tvNumber.setText(String.valueOf(current.getNumber()));
ivImage.setImageDrawable(current.getDrawable());
return view;
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ArrayList<App> appList;
ListView lv;
AppAdapter appAdapter;
App lastSelected;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText etSearch = findViewById(R.id.etSearch);
PackageManager packageManager = getPackageManager();
List<PackageInfo> mApps = packageManager.getInstalledPackages(0);
//array strings to all packages, names and version
final String[] arrPackages = new String[mApps.size()];
final String[] arrVersion = new String[mApps.size()];
String[] arrName = new String[mApps.size()];
//array of Drawables for icons...
Drawable[] arrIcons = new Drawable[mApps.size()];
App[] arrApps = new App[mApps.size()];
appList = new ArrayList<>();
//reading all app's packages and version to the arrays
for (int i = 0; i < mApps.size(); i++){
arrVersion[i] = mApps.get(i).versionName;
arrPackages[i] = mApps.get(i).packageName;
}
for (int i = 0; i < mApps.size(); i++){
try {//getting app's names from theres packages
arrName[i] = (String) packageManager.getApplicationLabel(packageManager.getApplicationInfo(arrPackages[i], PackageManager.GET_META_DATA));
} catch (PackageManager.NameNotFoundException e) {
arrName[i] = "Unknown";
}
try {//same as names for icons
arrIcons[i] = packageManager.getApplicationIcon(arrPackages[i]);
} catch (PackageManager.NameNotFoundException e) {
arrIcons[i] = getDrawable(R.drawable.placeholder);
}
arrApps[i] = new App(i + 1, "Name: "+arrName[i], "Version: "+arrVersion[i], arrIcons[i]);
appList.add(arrApps[i]);
}
//on item click open app
appAdapter = new AppAdapter(this,0,0,appList);
lv = findViewById(R.id.lv);
lv.setAdapter(appAdapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
lastSelected = appAdapter.getItem(position);
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(arrPackages[position]);
if (launchIntent != null) {
startActivity(launchIntent);//null pointer check in case package name was not found
}
}
});
//(trying to..) Add Text Change Listener to EditText
etSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Call back the Adapter with current character to Filter
MainActivity.this.appAdapter.getFilter().filter(s.toString());
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
(when i try to search something it's gives nothing...)
exchange this line
App current = objects.get(position);
to this
App current = (App) getItem(position);
you don't need to keep List<App> objects; inside your adapter, it is passed in constructors super call (last param) and kept under the hood for you. check out ArrayAdapter source - passed ArrayList is kept as mObjects and further used in some methods, e.g. getPosition, getCount and getItem
ArrayAdapter already implements Filterable, so there is an overriden method getFilter, which returns ArrayFilter - this inner class is declared on the bottom. when you call getFilter().filter( then performFiltering gets called (in a separated thread) and iterates through local copy of your data (line 588). It is using values.get(i).toString().toLowerCase() to compare objects from array with passed String (CharSequence in fact). so in your custom App class override toString method and return in there some searchable value, e.g.
#Override
public String toString(){
return name;
}
this is not best approach, because toString may be used in a lot of mechanisms (its base method of Object) and with above toString implementation two Apps with same name, but different version or number are threated as same object, which isn't true... maybe better way would be to return name+version+number;, but still you have also Drawable in there. thats why I've suggested (in this answer before edit) to make own class extends BaseAdapter and implement own filtering or at least use ArrayAdapter, but override getFilter method and return your own Filter implementation comparing variables instead of using toString. Then won't be needed to override this class, leave it as it is. By default it returns kind-of memory address, so it is unique for every new App instance, even when created with exacly same variables
also in THIS answer you can find nice example how to implement that Filter
Here, in this viewpageradapter class is using to set data, how can I set data in viewpager. I can try to implement but I don't know how can be achieving this.I also add my PhotoviewAdater and PhotoActivity. plz solve this problem.
public class PhotoViewAdapter extends PagerAdapter {
Context context;
ArrayList<Model_image> all_folder = new ArrayList<>();
int int_position;
LayoutInflater inflater;
public PhotoViewAdapter(Context context, ArrayList<Model_image> all_folder, int int_position) {
this.context=context;
this.all_folder=all_folder;
this.int_position=int_position;
}
#Override
public int getCount() {
return all_folder.get(int_position).getAll_imagepath().size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == ((RelativeLayout) object);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View viewLayout = inflater.inflate(R.layout.activity_photo_view_adapter, container,false);
imageView = (ImageView) container.findViewById(R.id.im_page);
try {
imageView.setImageResource(Integer.parseInt((all_folder.get(position).getAll_imagepath().get(int_position))));
} catch (Exception e) {
e.printStackTrace();
}
return viewLayout;
}
}
PhotoActivity:
public class PhotoActivity extends AppCompatActivity {
ViewPager viewPager;
int int_position;
PhotoViewAdapter photoViewAdapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_view);
int_position = getIntent().getIntExtra("pos",0);
viewPager = (ViewPager) findViewById(R.id.imagepage);
photoViewAdapter = new PhotoViewAdapter(getApplicationContext(), ImageActivity.all_images, int_position);
viewPager.setAdapter(photoViewAdapter);
}
}
Model_image:
public class Model_image {
String str_folder;
ArrayList<String> all_imagepath;
public void setStr_folder(String str_folder)
{
this.str_folder = str_folder;
}
public void setAll_imagepath(ArrayList<String> all_imagepath)
{
this.all_imagepath = all_imagepath;
}
public String getStr_folder()
{
return str_folder;
}
public ArrayList<String> getAll_imagepath()
{
return all_imagepath;
}
}
Change this
imageView.setImageResource(all_folder[position]);
to
imageView.setImageResource(all_folder.get(position));
all_folder is defined as an Arraylist not as an array.
all_folder.get(position) returns an Model_image object.
To set the image in the imageView you need an image reference.
I dont know which image you are trying to set.
If you want to set the image from all_imagepath, try doing
imageView.setImageResource(all_folder.get(position).getAll_imagepath.get(<position of the required image>));
setImageResource is used to set an image from the apk resources.
rather use imageView.setImageBitmap(BitmapFactory.decodeFile(all_folder.get(position).getPath()));
It is unclear yet from your Model_image class what an unique path can be, so you need to define a getPath() method.
I have created an app with a listview with arrayadapter that the user can dynamically populate. I store the info entered as a json string in the preferences and when I refresh the app, I get the list with the entries. The thing is that I want the image next to each entry to change after a network operation. The problem I'm facing seems to be that since the elements in the list are added dynamically, I dont seem to find a good way neither to update the imageview on the onPostExecute() method, either to be able to target each entry specifically since they share the same layout ids.
Here is my getView() method inside my adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.product_list_item, null);
holder = new ViewHolder();
holder.deviceName = (TextView) convertView
.findViewById(R.id.txt_pc_name);
holder.deviceIp = (TextView) convertView
.findViewById(R.id.txt_pdt_desc);
holder.devicePort = (TextView) convertView
.findViewById(R.id.txt_pdt_price);
holder.favoriteImg = (ImageView) convertView
.findViewById(R.id.imgbtn_favorite);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Devices device = (Devices) getItem(position);
holder.deviceName.setText(device.getName());
holder.deviceIp.setText(device.getIpOnline());
holder.devicePort.setText(device.getPortOnline() + "");
return convertView;
}
Here is my AsyncTask:
public class Connection extends AsyncTask<String, Void, String> {
private String ipOnline;
private int portOnline;
private String ipWol;
private int portWol;
private String macAddress;
private ImageView img;
private Context context;
public interface AsyncResponse {
void processFinish(String output);
}
public AsyncResponse delegate = null;
public Connection(Context mContext, ImageView Img,String IpOnline, int PortOnline, String IpWol, int PortWol, String MacAddress, AsyncResponse delegate) {
ipOnline = IpOnline;
portOnline = PortOnline;
ipWol = IpWol;
portWol = PortWol;
macAddress = MacAddress;
context = mContext;
// inflate = Inflate;
img = Img;
// spin = spinner;
this.delegate = delegate;
}
public int status;
#Override
protected String doInBackground(String... arg0) {PreferenceManager.getDefaultSharedPreferences(lastContext);
try {
Socket echoSocket = new Socket();
echoSocket.connect(new InetSocketAddress(ipOnline,portOnline),2000);
if(echoSocket.isConnected())
status = 1;
} catch (Exception e) {
status = 0;
}
if(status == 0)
return "0";
else
return "1";
}
#Override
protected void onProgressUpdate(Void... values) {}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ImageView img = (ImageView) activity.findViewById(R.id.imgbtn_favorite);
if (status == 0)
img.setImageResource(android.R.drawable.presence_offline);
else
img.setImageResource(android.R.drawable.presence_online);
delegate.processFinish(result);
}
}
And here is my call to it:
new Connection(activity, img, product.getIpOnline(), Integer.parseInt(product.getPortOnline()), product.getIpWol(), Integer.parseInt(product.getPortWol()), product.getMacAddress(), new Connection.AsyncResponse() {
#Override
public void processFinish(String output) {
}
}).execute();
You can use view holder pattern or recyclerview .
You need to store the reference of image view in holder and can update the image with the help of this reference instead of id of view
I came up with a solution.
I created a public variable on my adapter and I'm adding all the images:
public List<ImageView> allImages = new ArrayList<ImageView>();
public List<ImageView> getAllImages(){
return this.allImages;
}
this.allImages.add((ImageView) convertView
.findViewById(R.id.imgbtn_favorite));
Then on my fragmented activity onCreateView method I deployed a delayed runnable:
(new Handler()).postDelayed(new Runnable() {
#Override
public void run() {
updateStatus();
}
}, 500);
the updateStatus() method initializes the images variable and begins network checks to determine which image to use. Then it applies it accordingly.
public void updateStatus() {
List<ImageView> images = deviceListAdapter.getAllImages();
if(count > 0 && images.size() > 0) {
for (int i = 0; i < deviceListAdapter.getCount() ; i++) {
Devices product = (Devices) deviceListAdapter.getItem(i);
if((TextUtils.isDigitsOnly(product.getPortOnline()) && TextUtils.isDigitsOnly(product.getPortWol())) && (!product.getPortOnline().isEmpty() && !product.getPortWol().isEmpty())) {
new Connection(activity, images.get(i), product.getIpOnline(), Integer.parseInt(product.getPortOnline()), product.getIpWol(), Integer.parseInt(product.getPortWol()), product.getMacAddress(), new Connection.AsyncResponse() {
#Override
public void processFinish(Boolean output) {
}
}).execute();
}
}
}
}
It might not be optimal but feel free to add a better solution.
I'm trying to inflate a list using baseadapter within an activity. The list just doesn't inflate. From the logs implemented within the class, the getView() function doesn't even execute. Here's the code. -
public class CallLog extends Activity {
ListView logList;
List mList;
Context mCtx;
ArrayList<String> logName;
ArrayList<String> logNumber;
ArrayList<String> logTime;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.reject_call_log);
mCtx = getApplicationContext();
ListView logList = (ListView) findViewById(R.id.log_list);
mList = new List(mCtx, R.layout.log_row);
logList.setAdapter(mList);
SharedPreferences savedLogName = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogNumber = PreferenceManager.getDefaultSharedPreferences(mCtx);
SharedPreferences savedLogTime = PreferenceManager.getDefaultSharedPreferences(mCtx);
try{
logName = new ArrayList(Arrays.asList(TextUtils.split(savedLogName.getString("logName", null), ",")));
logNumber = new ArrayList(Arrays.asList(TextUtils.split(savedLogNumber.getString("logNumber", null), ",")));
logTime = new ArrayList(Arrays.asList(TextUtils.split(savedLogTime.getString("logTime", null), ",")));
Collections.reverse(logName);
Collections.reverse(logNumber);
Collections.reverse(logTime);
}catch(NullPointerException e){
e.printStackTrace();
//TextView noLog = (TextView)findViewById(R.id.no_log);
}
}
public class List extends BaseAdapter {
LayoutInflater mInflater;
TextView nameText;
TextView numberText;
TextView timeText;
int timePos = 1;
public List(Context context, int resource) {
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int i) {
return null;
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (convertView == null) {
v = mInflater.inflate(R.layout.row, null);
}
nameText = (TextView) v.findViewById(R.id.log_name);
numberText = (TextView) v.findViewById(R.id.log_number);
timeText = (TextView) v.findViewById(R.id.log_time);
nameText.setText(logName.get(position));
numberText.setText(logNumber.get(position));
timeText.setText(logTime.get(timePos) + logTime.get(timePos+1));
Log.d("RejectCall", "ListView");
timePos+=2;
return v;
}
}
}
Where is it all going wrong? Also, is there a better way to do what I'm trying to do?
Please replace the following code :
#Override
public int getCount() {
return 0;
}
with
#Override
public int getCount() {
return logName.size();
}
As list view only show the numbers of rows that is returned by this method and right now you are returning 0;
And after fetching the data in arraylist please use adapter.notifyDataSetChanged() to notify the list view.
You have to call notifyDataSetChanged() as you are filling data in array list after setting the adapter. so to notify the list view that data has been changed you have to call notify method(as above)
Your getItem() and getCount() haven't been implemented. If you want any kind of adapter to work for the list, these need to be implemented. Your list is also not holding any actual data, so getItem() has nothing to set.
Don't forget to call notifiyDataSetChanged() in your adapter after you set appropriate implementations for the above two functions.
Help to understand whether there is a memory leak or not.
Fragment
public class NewsFragment extends Fragment {
//some code
private OnNewsFeedsContentClickListener onNewsFeedsContentClickListener = new OnNewsFeedsContentClickListener()
{
#Override
public void onClick(String sYoutubeId, ContentType type)
{
//some code
}
}
}
Adapter
public class HowToAdapter extends BaseAdapter {
public static final String TAG = "HowToAdapter";
private List<ContentSkill> mContentList = null;
private Context mContext = null;
private ImageLoader mImageLoader = null;
private OnNewsFeedsContentClickListener mOnNewsFeedsContentClickListener = null;
public HowToAdapter(Context context, List<ContentSkill> contetnList, OnNewsFeedsContentClickListener onNewsFeedsContentClickListener)
{
mContext = context;
mContentList = contetnList;
mImageLoader = new ImageLoader(mContext, ImageType.HOW_TO);
mOnNewsFeedsContentClickListener = onNewsFeedsContentClickListener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
HowToView view = null;
if (convertView == null)
{
view = new HowToView(mContext);
}
else
{
view = (HowToView) convertView;
}
ContentSkill content = getItem(position);
if (content != null)
{
ViewHolder holder = (ViewHolder) view.getTag();
final String url = Utils.getYouTubeUrlImageFromUrl(content.getUrl());
final String youtubeId = Utils.getYoutubeIdFromUrl(content.getUrl());
mImageLoader.displayImage(url, holder.pIvThumb);
holder.pIvThumb.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
mOnNewsFeedsContentClickListener.onClick(youtubeId, ContentType.VIDEO);
}
});
}
return view;
}
}
Questions:
The adapter variable final String youtubeId will always be created,
but not killed? That is, each time getView() will be created but
the old youtubeId not clear from memory?
Each time call getView() OnClickListener will also be created, and the old
will be cleaned out of memory?
I think that the variables will be re-created each time and catch-up with the old memory.