IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

SimpleAdapter avec images distantes


Sujet :

Android

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut SimpleAdapter avec images distantes
    Bonjour,

    J'ai créé un classe qui hérite de SimpleAdapter qui permet d'afficher une liste (ListActivity) avec des images distantes (via HTTP).

    Voici le code de ma classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    public class SimpleAdapterWithRemoteImage extends SimpleAdapter {
    	Context context = null;
    	Map<String, SoftReference<Bitmap>> bitmaps = new HashMap<String, SoftReference<Bitmap>>();
    	Map<ImageView, URL> imageviews = new HashMap<ImageView, URL>();
     
     
    	public SimpleAdapterWithRemoteImage(Context context, List<Map<String, String>> data, int resource, String[] from, int[] to) {
    		super(context, data, resource, from, to);
    		this.context = context;
    	}
     
    	private Bitmap fetchBitmap(String url) {
    		SoftReference<Bitmap> bitmapReference =  bitmaps.get(url);
     
    		if (bitmapReference!=null) {
    			Bitmap bitmap = bitmapReference.get();
    			if (bitmap!=null) {
    				return bitmap;
    			} else {
    				bitmaps.remove(url);
    			}
    		}
     
    		return null;
    	}
     
    	public View getView(int position, View convertView, ViewGroup parent) {
    		View v = null;
     
     
    		if ( super.getCount()>position) {
    			v = super.getView(position, convertView, parent);
     
    			if (v!=null) {
    				ImageView imageView = (ImageView)v.findViewById(R.id.ad_detail_image);
    				if ( imageView!=null) {
    					URL url = null;
    					String thumb = null;
    					try {
    						Map<String, String> params = (Map<String, String>)super.getItem(position);
    						if ( params!=null) {
    							thumb = params.get("image");
    							if (thumb != null) {
    								url = new URL(thumb);
    							} else {
    								imageView.setImageResource(R.drawable.blank);
    							}
    						} else {}
    					} catch (MalformedURLException e) {}
     
    					imageviews.put(imageView, url);
    					if ( thumb!=null) {
    						Bitmap bitmap = fetchBitmap(thumb);
    						if ( bitmap!=null) {
    							imageView.setImageBitmap(bitmap);
    						} else {
    							try {
    								if (url!=null) {
    									imageView.setImageResource(R.drawable.blank);
    									ImageDownloadTask idt = new ImageDownloadTask();
    									idt.execute(new RemoteImageView(imageView, url));
    								} else {}
    							} catch (RejectedExecutionException e) {}
    						}
    					} else {
    						imageView.setImageDrawable(v.getResources().getDrawable(R.drawable.blank));
    					}
    				} else {}
    			} else {}
    		}
     
    		return v;
    	}
     
    	private class RemoteImageView {
    		ImageView iv;
    		URL url;
     
     
    		public RemoteImageView(ImageView iv, URL url) {
    			this.iv = iv;
    			this.url = url;
    		}
    	}
     
    	private class ImageDownloadTask extends AsyncTask<RemoteImageView, Integer, Bitmap> {
    		private RemoteImageView riv;
     
     
    		protected Bitmap doInBackground(RemoteImageView... rivs) {
    			Bitmap bm = null;
    			riv = rivs[0];
     
     
    			if ( riv!=null && riv.url!=null) {
    				URL url = riv.url;
    				InputStream is = null;
     
    				try {
    					is = url.openConnection().getInputStream();
    				} catch (MalformedURLException e) {
    				} catch (IOException e) {
    				}
     
    				if ( is!=null) {
    					try {
    						bm = BitmapFactory.decodeStream(is);
    						bitmaps.put(url.toExternalForm(), new SoftReference<Bitmap>(bm));
    					} catch ( OutOfMemoryError e) {}
     
    					try {
    						is.close();
    					} catch (IOException e) {}
    				} else {}
    			}
     
    			return bm;
    		}
     
    		protected void onPostExecute(Bitmap result) {
    			if ( riv!=null && riv.iv!=null && riv.url!=null && riv.url.equals(imageviews.get(riv.iv))) {
    				riv.iv.setImageBitmap(result);
    			}
    		}
    	}
    }
    Dans la plupart des cas, l'application fonctionne très bien. Cependant, je reçois de temps en temps les deux rapports d'erreur suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    java.lang.NullPointerException
    	at android.widget.ListView.setupChild(ListView.java:1735)
    	at android.widget.ListView.makeAndAddView(ListView.java:1713)
    	at android.widget.ListView.fillUp(ListView.java:670)
    	at android.widget.ListView.fillGap(ListView.java:615)
    	at android.widget.AbsListView.trackMotionScroll(AbsListView.java:2622)
    	at android.widget.AbsListView.onTouchEvent(AbsListView.java:2048)
    	at android.widget.ListView.onTouchEvent(ListView.java:3276)
    	at android.view.View.dispatchTouchEvent(View.java:3796)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:856)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1673)
    	at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1114)
    	at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
    	at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1657)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:888)
    	at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1673)
    	at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1114)
    	at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
    	at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1657)
    	at android.view.ViewRoot.handleMessage(ViewRoot.java:1758)
    	at android.os.Handler.dispatchMessage(Handler.java:99)
    	at android.os.Looper.loop(Looper.java:136)
    	at android.app.ActivityThread.main(ActivityThread.java:4425)
    	at java.lang.reflect.Method.invokeNative(Native Method)
    	at java.lang.reflect.Method.invoke(Method.java:521)
    	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:850)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
    	at dalvik.system.NativeStart.main(Native Method)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class com.company.project.SimpleAdapterWithRemoteImage)]
    	at android.widget.ListView.layoutChildren(ListView.java:1508)
    	at android.widget.AbsListView$CheckForTap.run(AbsListView.java:1930)
    	at android.os.Handler.handleCallback(Handler.java:587)
    	at android.os.Handler.dispatchMessage(Handler.java:92)
    	at android.os.Looper.loop(Looper.java:123)
    	at android.app.ActivityThread.main(ActivityThread.java:4627)
    	at java.lang.reflect.Method.invokeNative(Native Method)
    	at java.lang.reflect.Method.invoke(Method.java:521)
    	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    	at dalvik.system.NativeStart.main(Native Method)
    Quelqu'un sait-il d'où ça peut venir ? J'ai cherché un peu partout. Amélioré deux ou trois trucs. Mais quelques rares utilisateurs ont toujours ces erreurs.

    Merci !
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  2. #2
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    Pour la première erreur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    java.lang.NullPointerException
    	at android.widget.ListView.setupChild(ListView.java:1735)
    	at android.widget.ListView.makeAndAddView(ListView.java:1713)
    On dirait que les données de ta liste sont nulle . Est ce qu'a un moment donnée dans ton code tu peux avoir ce cas ?

    Pour la seconde erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(16908298, class android.widget.ListView) with Adapter(class com.company.project.SimpleAdapterWithRemoteImage)]
    	at android.widget.ListView.layoutChildren(ListView.java:1508)
    Les données de ta liste ont été changé, et tu préviens la liste à partir du Async Thread et non de l'UIThread .

    Donc pourrais tu nous montrer comment charges-tu ta liste avec l'adapter ?

    De même lorsque les données ont été modifié ( ajout, suppression , modification).

    Merci .
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Merci pour ta réponse. Voici le code de mon activité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    abstract public class ResultActivity extends ListActivity {
    	SearchQuery currentQuery = null;
    	ResultSearch mainResult = null;
     
    	List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
    	List<Map<String, String>> prepareList = new ArrayList<Map<String, String>>();
     
    	boolean searching = false;
    	boolean hasFocus = false;
     
    	final Handler uiThreadCallback = new Handler();
     
    	final Runnable runInUIThreadOnScroll = new Runnable() {
    		public void run() {
    			onUpdateResultList();
    			adapter.notifyDataSetChanged();
    			onUpdateTitle();
    			getParent().setProgressBarIndeterminateVisibility(false);
    	        searching = false;
    		}
    	};
     
    	final Runnable runInUIThreadOnResultSearch = new Runnable() {
    		public void run() {
    			onUpdateResultList();
    			adapter.notifyDataSetChanged();
    			onUpdateTitle();
    			getParent().setProgressBarIndeterminateVisibility(false);
    	        searching = false;
    		}
    	};
     
    	private Context context;
    	private SimpleAdapter adapter;
     
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.ad_list);
     
    		context = this;
     
    		String[] from = {"id", "name", "locality", "subAdminArea", "category", "date", "price", "image", "urgent"};
    		int[] to = {R.id.ad_detail_id, R.id.ad_detail_name, R.id.ad_detail_locality, R.id.ad_detail_subadmin_area, R.id.ad_detail_category, R.id.ad_detail_date, R.id.ad_detail_price};
    		adapter = new SimpleAdapterWithRemoteImage(this.getApplicationContext(), resultList, R.layout.ad_row, from, to);
    		setListAdapter(adapter);
     
    		ListView listView = getListView();
    		listView.setOnScrollListener(new OnScrollListener() {
    			int lastItem = 0;
     
    			public void onScrollStateChanged(AbsListView view, int scrollState) {
    				if ( adapter!=null && mainResult!=null && currentQuery!=null && !searching) {
    			    	if (lastItem == getListAdapter().getCount() && scrollState == OnScrollListener.SCROLL_STATE_IDLE && adapter.getCount()<mainResult.nbAds) {
    			    		searching = true;
    			    		getParent().setProgressBarIndeterminateVisibility(true);
     
    						new Thread() {
    							public void run() {
    								try {
    									currentQuery.page++;
    									ResultSearch rs = ProjectService.searchItems(context, currentQuery);
    									if ( mainResult==null) {
    										mainResult = rs;
    									} else if (mainResult.ads==null) {
    										mainResult.ads = rs.ads;
    									} else {
    										mainResult.ads.addAll(rs.ads);
    									}
     
    									prepare(rs);
    								} catch (ProjectException e) {
    									currentQuery.page--;
    								}
     
    								uiThreadCallback.post(runInUIThreadOnScroll);
    							}
    						}.start();
    			    	} else {}
    				} else {}
    		    }
     
    			public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    		    	lastItem = firstVisibleItem + visibleItemCount;
    			}
    		});
     
    		final Intent queryIntent = getIntent();
    		final String queryAction = queryIntent.getAction();
    		if (Intent.ACTION_SEARCH.equals(queryAction)) {
    			doSearchQuery(queryIntent);
    		} else {}
    	}
     
    	public void onResume() {
    		super.onResume();
    		hasFocus = true;
    		if (searching==false) {
    			onUpdateTitle();
    		}
    	}
     
    	public void onPause() {
    		super.onPause();
    		hasFocus = false;
    	}
     
    	public void onNewIntent(final Intent newIntent) {
    		super.onNewIntent(newIntent);
     
    		final Intent queryIntent = getIntent();
    		final String queryAction = queryIntent.getAction();
    		if (Intent.ACTION_SEARCH.equals(queryAction)) {
    			doSearchQuery(queryIntent);
    		} else {}
    	}
     
    	private void doSearchQuery(final Intent queryIntent) {
    		SearchQuery query = queryIntent.getExtras().getParcelable(SearchResultsActivity.INTENT_EXTRA_SEARCH_QUERY);
    		query = (SearchQuery)query.clone();
    		doSearchQuery(query);
    	}
     
    	private void doSearchQuery(SearchQuery query) {
    		if (mainResult!=null) {
    			mainResult = null;
    			resultList.clear();
    			prepareList.clear();
    		}
    		currentQuery = query;
    		searching = true;
    		getParent().setProgressBarIndeterminateVisibility(true);
    		getParent().setTitle(getString(R.string.search_title_processing, currentQuery.search));
     
    		new Thread() {
    			public void run() {
    				try {
    					mainResult = ProjectService.searchItems(context, currentQuery);
    					prepare(mainResult);
    				} catch ( ProjectException e) {
    				}
     
    				uiThreadCallback.post(runInUIThreadOnResultSearch);
    			}
    		}.start();
    	}
     
    	private void onUpdateTitle() {
    		if ( currentQuery!=null/* && hasWindowFocus()*/ && hasFocus) {
    			if ( mainResult!=null && mainResult.nbAds>0) {
    				if ( currentQuery.search!=null && currentQuery.search.length()>0) {
    					getParent().setTitle(getString(R.string.search_title_result, Math.min(currentQuery.page*ProjectService.SEARCH_PAGE_SIZE, mainResult.nbAds), mainResult.nbAds, currentQuery.search));
    				} else {
    					getParent().setTitle(getString(R.string.search_title_result_for_category, Math.min(currentQuery.page*ProjectService.SEARCH_PAGE_SIZE, mainResult.nbAds), mainResult.nbAds));
    				}
    			} else {
    				getParent().setTitle(getString(R.string.search_title_no_results));
    			}
    		} else {
    			getParent().setTitle(getString(R.string.search_query_results));
    		}
    	}
     
    	private void prepare(ResultSearch rs) {
    		if ( rs!=null && rs.ads!=null) {
    			if ( !rs.ads.isEmpty()) {
    				for (ClassifiedAd classifiedAd : rs.ads) {
    					if ( classifiedAd!=null) {
    						Map<String, String> map = new HashMap<String, String>();
    						map.put("id", classifiedAd.id);
    						map.put("url", classifiedAd.url);
    						map.put("name", classifiedAd.name);
    						map.put("locality", classifiedAd.city);
    						map.put("subAdminArea", classifiedAd.department);
    						map.put("category", classifiedAd.category);
    						map.put("date", classifiedAd.createDate);
    						map.put("price", classifiedAd.price);
    						map.put("image", classifiedAd.thumb);
     
    						prepareList.add(map);
    					}
    				}
    			}
    		} else {}
    	}
     
    	private void onUpdateResultList() {
    		resultList.addAll(prepareList);
    		prepareList.clear();
    	}
    }
    Lors de l'ouverture de l'activité, la liste des N premiers éléments à afficher est récupérée (via l'appel à ProjectService.searchItems()).

    Ensuite, si l'utilisateur scrolle et arrive en fin de liste, les N élements suivants sont récupérés s'ils existent.

    La liste n'est jamais nulle à priori. Au pire, elle est vide.

    J'ai l'impression (sans pouvoir l'affirmer) que la première exception arrive lorsque l'activité s'ouvre et la seconde lorsque l'utilisateur scrolle dans la liste.

    Merci beaucoup pour ton aide.

    PS : En relisant, je me rends compte que les paramètres String[] from et int[] to n'ont pas la même taille puisque le dernier élément ("image" l'image distante) de from est positionné à la main. Je n'ai donc pas mis sa correspondance dans to.
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Personne n'a d'idée ?

    Sinon, j'ai vu que je pouvais simplement surcharger la méthode SimpleAdapter.setImageView() pour charger mon image distante. Enfin, je me demande si l'une des exceptions ne vient pas du fait que je charge l'image avec une AsyncTask...

    En revanche, quelles sont des bonnes pratiques pour personnaliser l'affichage des éléments d'une liste ? Par exemple, j'ai un champ qui m'indique si l'utilisateur a déjà cliqué dessus. Dans ce cas, je n'utilise pas la même couleur de fond. J'ai ré-implémenté complètement la méthode SimpleAdapter.getView(). Mais il y a peut-être une façon de faire plus simple ou plus propre ?

    Merci pour votre aide !
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  5. #5
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    Ici tu as un souci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    final Runnable runInUIThreadOnScroll = new Runnable() {
    		public void run() {
    			onUpdateResultList();
    			adapter.notifyDataSetChanged();
    			onUpdateTitle();
    			getParent().setProgressBarIndeterminateVisibility(false);
    	        searching = false;
    		}
    	};
     
    	final Runnable runInUIThreadOnResultSearch = new Runnable() {
    		public void run() {
    			onUpdateResultList();
    			adapter.notifyDataSetChanged();
    			onUpdateTitle();
    			getParent().setProgressBarIndeterminateVisibility(false);
    	        searching = false;
    		}
    	};
    Tu n'es pas du tout dans l'UIThread , donc tu ne peux pas à partir d'ici modifier ton graphique .

    Tu peux utiliser cette fonction de ton Activity public final void runOnUiThread
    http://developer.android.com/referen...ng.Runnable%29

    OU sinon il faut que tu modifies les appels de changement de ton graphique dans tes runnables pour qu'ils s'exécutent dans l'UIThread .
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Je pensais que l'Handler permettait d'exécuter du code dans UIThread. Ce n'est pas le cas ?

    Ça veut donc dire que je dois remplacer tous mes uiThreadCallback.post(monRunnableQuiMetAJourMonUI) par runOnUiThread(monRunnableQuiMetAJourMonUI) ?
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  7. #7
    Membre averti
    Homme Profil pro
    Ingénieur Informatique et Développeur Android
    Inscrit en
    Janvier 2010
    Messages
    384
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Ingénieur Informatique et Développeur Android

    Informations forums :
    Inscription : Janvier 2010
    Messages : 384
    Points : 321
    Points
    321
    Par défaut
    voilà des methodes qui vont vous aider à resoudre votre problème. tu l'integre dans votre code. il permet à partir d'une url d'une image de recuperer l'image et de l'afficher dans un composant imageview dans listview...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
     
    maListViewPerso = (ListView) findViewById(android.R.id.list);
    SimpleAdapter notes = new SimpleAdapter(Theme.this, list, R.layout.afficheitemteme, PARAM, new int[] { R.id.imgt,R.id.titrethemet,R.id.descriptiontt, R.id.descriptiont /*,R.id.key*/});
     
     
    maListViewPerso.setAdapter(notes);
    notes.setViewBinder(new MyViewBinder());
     
     
     
    setListAdapter(notes);
     
    try { 
    	URL aURL = new URL(v.elementAt(0)); 
    	URLConnection conn = aURL.openConnection(); 
    	conn.connect(); 
    	InputStream is = conn.getInputStream(); 
    	Bitmap  here_comes_it = BitmapFactory.decodeStream(is); 
    	is.close(); 
     
    	addItem(list, here_comes_it,v2.elementAt(0),v2.elementAt(1), new Intent(this, Main.class)); 
     
    	} catch (Exception e) { 
    	e.printStackTrace(); 
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    public void addItem(List<Map<String, Object>> data, Bitmap here_comes_it , String name, String content, Intent intent) { 
    Map<String, Object> map = new HashMap<String, Object>(); 
     
    map.put(NAME,name); 
    map.put(CONTENT, content); 
    map.put(INTENT, intent); 
    map.put(ICON, here_comes_it); 
    data.add(map); 
     
    }
     
    public class MyViewBinder implements ViewBinder {
     
     
     
        @Override
     
        public boolean setViewValue(View view, Object data,
     
                        String textRepresentation) {
     
     
     
                if( (view instanceof ImageView) & (data instanceof Bitmap) ) {
     
                        ImageView iv = (ImageView) view;
     
                        Bitmap bm = (Bitmap) data;     
     
                        iv.setImageBitmap(bm); 
     
                        return true;
     
                }
     
     
     
                return false;
     
        }
     
    }
    tu peux l'adapter à votre application
    bon chance

  8. #8
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    Ça veut donc dire que je dois remplacer tous mes uiThreadCallback.post(monRunnableQuiMetAJourMonUI) par runOnUiThread(monRunnableQuiMetAJourMonUI) ?
    Oui

    NB: il y a d'autres manière pour réactualisé le graphique comme le post http://developer.android.com/referen...ng.Runnable%29

    Mais elle ne se fait qu'à partir d'une View et non d'un Handler avec un runnable .

    Tu trouveras ici le fonctionnement des threads dans Android .
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Merci beaucoup pour tes explications.

    J'ai publié une nouvelle version de mon application avec ses corrections mais j'ai toujours des rapports d'erreur avec les deux exceptions citées plus haut.

    Le code de la méthode SimpleAdapter.getView() s'exécute bien dans le ThreadUI ?
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  10. #10
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,
    Le code de la méthode SimpleAdapter.getView() s'exécute bien dans le ThreadUI ?
    Oui .

    J'ai publié une nouvelle version de mon application avec ses corrections mais j'ai toujours des rapports d'erreur avec les deux exceptions citées plus haut.
    Tu fais des test sur ton emulateur ou ton téléphone de test chez toi avant de publier ton application ?

    Essayes de reproduire les erreurs sur ton emulateur ou ton téléphone de test .
    Je pense que comme cela tu trouveras plus facilement ton pointeur null.

    Pour la deuxième exception , il doit bien y avoir un endroit ou tu notifies pas le changement des données de l'adapter .
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Le souci, c'est que je n'arrive pas à reproduire l'erreur, ni avec l'émulateur ni avec les trois téléphones que j'ai sous la main.

    De plus, j'ai plusieurs milliers d'utilisateurs quotidien mais "seulement" 18 reports hebdomadaire pour le NullPointerException et 4 reports hebdomadaire pour le IllegalStateException. Ce sont donc des erreurs très rares mais qui surviennent assez souvent pour essayer de les corriger.

    Je comprends que tu ne puisses pas m'aider plus. Ce n'est pas évident. Je me demande si ce n'est pas tout simplement mon SimpleAdapterWithRemoteImage qui fragilise la stabilité de mon application. Je vais chercher une solution alternative pour afficher dans une ListActivity des éléments qui contiennent des images accessibles en HTTP et dont le texte change de style en fonction des valeurs...

    Encore merci pour le temps pris à me répondre !
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  12. #12
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    Je comprends que tu ne puisses pas m'aider plus. Ce n'est pas évident. Je me demande si ce n'est pas tout simplement mon SimpleAdapterWithRemoteImage qui fragilise la stabilité de mon application. Je vais chercher une solution alternative pour afficher dans une ListActivity des éléments qui contiennent des images accessibles en HTTP et dont le texte change de style en fonction des valeurs...
    C'est surtout pas évident pour n'importe qui de corriger une erreur que l'on arrive pas à reproduire.

    Ça peut être une idée , il faudrait également voir de quel genre de smartphone proviennent les erreurs cela peut également être une piste

    Pour le pointeur null , essaye de poser un peu plus de conditions (if) dans ton code avant un appel à une procédure grâce à un objet . tu peux également remonter des exception cela te permettra de cibler un peu mieux l'erreur.
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Salut,

    Citation Envoyé par Feanorin Voir le message
    C'est surtout pas évident pour n'importe qui de corriger une erreur que l'on arrive pas à reproduire.
    C'est bien mon souci...

    Citation Envoyé par Feanorin Voir le message
    Ça peut être une idée , il faudrait également voir de quel genre de smartphone proviennent les erreurs cela peut également être une piste
    J'ai l'impression qu'il n'y a pas de modèle de téléphone spécifique (toutes marques, tous modèles), ni de version d'Android en particulier (1.6 à 2.3.4).
    J'ai en ma possession un Nexus S en 2.3.3 et un HTC Hero en 2.1-update1. Je n'ai jamais réussi à reproduire les exceptions pourtant j'ai des rapports d'erreurs pour ces deux configurations.

    Citation Envoyé par Feanorin Voir le message
    Pour le pointeur null , essaye de poser un peu plus de conditions (if) dans ton code avant un appel à une procédure grâce à un objet . tu peux également remonter des exception cela te permettra de cibler un peu mieux l'erreur.
    J'ai déjà un maximum de (if) pour éviter les NullPointerException. J'ai même fait des tests aux limites en forçant des null pour essayer de reproduire l'anomalie. Mais il n'y a pas moyen !

    Je viens même d'empêcher les threads concurrents mais ça n'a pas résolu mon erreur.

    De plus, la pile d'exception ne passe pas par mon code. Elle touche le code Android. Il faut que j'arrive à retrouver le code source exact d'Android et je ne suis pas sûr de pouvoir déterminer comment contourner l'erreur.

    D'ailleurs, il y a-t-il un moyen élégant de gérer toutes les exceptions qui ne sont pas dues au code de sa propre application ?
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

  14. #14
    Expert éminent

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Points : 9 149
    Points
    9 149
    Par défaut
    Bonjour,

    Juste une petite précision sur ce que j'ai pu écrire avant. Je me suis trompé.

    Je pensais que l'Handler permettait d'exécuter du code dans UIThread. Ce n'est pas le cas ?
    Donc je me rectifie.
    Un handler de ton activity appartient à l'UIThread.

    Si tu appelles ton runnable par un 'post' sur ton handler , le runnable appelé appartiendra à ton UIThread.
    public final boolean post (Runnable r)
    Since: API Level 1

    Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
    Parameters
    r The Runnable that will be executed.
    Returns

    * Returns true if the Runnable was successfully placed in to the message queue. Returns false on failure, usually because the looper processing the message queue is exiting.
    Donc le code que tu avais avant était valide.
    Désolé de t'avoir induit en erreur là-dessus . (je pensais que le runnable lancer par le handler n'appartenait pas à l'UIThread).


    De plus, la pile d'exception ne passe pas par mon code. Elle touche le code Android. Il faut que j'arrive à retrouver le code source exact d'Android et je ne suis pas sûr de pouvoir déterminer comment contourner l'erreur.

    D'ailleurs, il y a-t-il un moyen élégant de gérer toutes les exceptions qui ne sont pas dues au code de sa propre application ?
    Pour le pointeur null , essaye de voir le code source alors à la ligne 1735 de la bonne version d'API ,
    Sur ce lien tu trouveras celle de l'API3 je ne pense pas que cela soit la bonne
    http://grepcode.com/file/repository....n%2Cboolean%29

    Quand à la seconde erreur tu pourrais également regarder dans le code source mais j'ai bien l'impression que cela provient d'ailleurs .


    J'ai l'impression qu'il n'y a pas de modèle de téléphone spécifique (toutes marques, tous modèles), ni de version d'Android en particulier (1.6 à 2.3.4).
    J'ai en ma possession un Nexus S en 2.3.3 et un HTC Hero en 2.1-update1. Je n'ai jamais réussi à reproduire les exceptions pourtant j'ai des rapports d'erreurs pour ces deux configurations.
    Après (juste une hypothèse) je ne sais pas si cela peut jouer mais si le téléphone n'as pas l'API de base mais une Custom/ROM? Je ne sais pas si cela peut interférer sur certains éléments.
    Responsable Android de Developpez.com (Twitter et Facebook)
    Besoin d"un article/tutoriel/cours sur Android, consulter la page cours
    N'hésitez pas à consulter la FAQ Android et à poser vos questions sur les forums d'entraide mobile d'Android.

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    92
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2002
    Messages : 92
    Points : 84
    Points
    84
    Par défaut
    Bonjour,

    Je reviens à la charge car je viens enfin de reproduire la première exception et j'ai donc un scenario :
    - l'activité charge la liste
    - une fois chargée, je change l'ordre tri via un menu
    - pendant le chargement de la liste avec le nouveau tri, je tente scroller dans la liste
    - force close

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    	public boolean onOptionsItemSelected(MenuItem item) {
    		final Context context = this;
     
    		switch (item.getItemId()) {
    			case ACTION_ACTUALISER:
    				currentQuery.page = 1;
    				doSearchQuery(currentQuery);
     
    				break;
     
    			case ACTION_CHANGER_TRI:
    				currentQuery.page = 1;
    				currentQuery.sortType = SortType.DATE.equals(currentQuery.sortType)?SortType.PRICE:SortType.DATE;
    				doSearchQuery(currentQuery);
     
    				break;
     
    			default:
    				break;
    		}
     
    		return super.onOptionsItemSelected(item);
    	}
    Ce qui a changé (à cause d'une ConcurrentModificationException) depuis mes derniers messages :
    - La liste rs.ads est initialisée avec un Collections.synchronizedList().
    - J'ai ajouté un synchronized(rs.ads) dans la méthode prepare(ResultSearch rs).

    Je dois avoir un souci avec mes List et mon Adapter mais j'ai le nez dans le code depuis trop longtemps pour avoir assez de recul. Auriez-vous une idée ?

    Merci !
    Zero
    My site : http://blog.lecacheur.com
    GWhere project : http://www.gwhere.org
    Debian Addict site : http://www.debianaddict.org

Discussions similaires

  1. Problème d'utilisation des attributs width et height avec une image distante
    Par Ptit_Mouss dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 21/09/2006, 15h40
  2. projet de base Interbase 7.5 avec images
    Par KRis dans le forum InterBase
    Réponses: 8
    Dernier message: 13/06/2005, 10h17
  3. alignement input avec image
    Par Shabata dans le forum Balisage (X)HTML et validation W3C
    Réponses: 5
    Dernier message: 24/02/2005, 09h45
  4. Formulaire et bouton submit avec image mapée
    Par dody dans le forum Général JavaScript
    Réponses: 7
    Dernier message: 06/12/2004, 16h00
  5. boîte de dialogue avec image de fond + texte
    Par Eugénie dans le forum MFC
    Réponses: 13
    Dernier message: 31/08/2004, 13h32

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo