I'm trying to implement Google Play Service Location APIs to use localization in my APP.
protected void createLocationRequest() {
// Create an instance of GoogleAPIClient.
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(10000);
mLocationRequest.setFastestInterval(5000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
final LocationSettingsStates states = result.getLocationSettingsStates();
}
I suppose to already import all needed libraries, anyway AndroidStudio notify to 'Cannot resolve method getLocationSettingsStates()'.
I does not get other error.
I can't figure out about this.
result is a PendingResult<LocationSettingsResult>, not a LocationSettingsResult itself which implements getLocationSettingsStates(). You need to do something like:
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates states = result.getLocationSettingsStates();
// Call states.isBlePresent(), etc.
Related
I'm trying to add custom tags - the path variables and their values from each request - to each metric micrometer generates. I'm using spring-boot with java 16.
From my research i've found that creating a bean of type WebMvcTagsContributor alows me to do just that.
This is the code
public class CustomWebMvcTagsContributor implements WebMvcTagsContributor {
private static int PRINT_ERROR_COUNTER = 0;
#Override
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response,
Object handler,
Throwable exception) {
return Tags.of(getAllTags(request));
}
private static List<Tag> getAllTags(HttpServletRequest request) {
Object attributesMapObject = request.getAttribute(View.PATH_VARIABLES);
if (isNull(attributesMapObject)) {
attributesMapObject = request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
if (isNull(attributesMapObject)) {
attributesMapObject = extractPathVariablesFromURI(request);
}
}
if (nonNull(attributesMapObject)) {
return getPathVariablesTags(attributesMapObject);
}
return List.of();
}
private static Object extractPathVariablesFromURI(HttpServletRequest request) {
Long currentUserId = SecurityUtils.getCurrentUserId().orElse(null);
try {
URI uri = new URI(request.getRequestURI());
String path = uri.getPath(); //get the path
UriTemplate uriTemplate = new UriTemplate((String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE)); //create template
return uriTemplate.match(path); //extract values form template
} catch (Exception e) {
log.warn("[Error on 3rd attempt]", e);
}
return null;
}
private static List<Tag> getPathVariablesTags(Object attributesMapObject) {
try {
Long currentUserId = SecurityUtils.getCurrentUserId().orElse(null);
if (nonNull(attributesMapObject)) {
var attributesMap = (Map<String, Object>) attributesMapObject;
List<Tag> tags = attributesMap.entrySet().stream()
.map(stringObjectEntry -> Tag.of(stringObjectEntry.getKey(),
String.valueOf(stringObjectEntry.getValue())))
.toList();
log.warn("[CustomTags] [{}]", CommonUtils.toJson(tags));
return tags;
}
} catch (Exception e) {
if (PRINT_ERROR_COUNTER < 5) {
log.error("[Error while getting attributes map object]", e);
PRINT_ERROR_COUNTER++;
}
}
return List.of();
}
#Override
public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
return null;
}
}
#Bean
public WebMvcTagsContributor webMvcTagsContributor() {
return new CustomWebMvcTagsContributor();
}
In order to test this, i've created a small spring boot app, added an endpoint to it. It works just fine.
The problem is when I add this code to the production app.
The metrics generates are the default ones and i can't figure out why.
What can I check to see why the tags are not added?
local test project
http_server_requests_seconds_count {exception="None", method="GET",id="123",outcome="Success",status="200",test="test",uri="/test/{id}/compute/{test}",)1.0
in prod - different (& bigger) app
http_server_requests_seconds_count {exception="None", method="GET",outcome="Success",status="200",uri="/api/{something}/test",)1.0
What i've tried and didn't work
Created a bean that implemented WebMvcTagsProvider - this one had an odd behaviour - it wasn't creating metrics for endpoints that had path variables in the path - though in my local test project it worked as expected
I added that log there in order to see what the extra tags are but doesn't seem to reach there as i don't see anything in the logs - i know, you might say that the current user id stops it, but it's not that.
I'm writing unit tests for a load balancer, the goal is to be able to filter out certain services based off its URI. However, the test always fails because it doesn't get the right URI at all! Here's the test class:
public class FilteringDiscoveryClientTest {
private static DiscoveryClient mockClient;
#BeforeAll
public static void setUp(){
SimpleDiscoveryProperties properties = new SimpleDiscoveryProperties();
Map<String, List<DefaultServiceInstance>> instances = new HashMap<>();
DefaultServiceInstance testInstance1_1 = new DefaultServiceInstance();
testInstance1_1.setUri(URI.create("http://my.service.id.1/1"));
testInstance1_1.setServiceId("my.service.id.1");
DefaultServiceInstance testInstance1_2 = new DefaultServiceInstance();
testInstance1_2.setUri(URI.create("http://my.service.id.1/2"));
testInstance1_2.setServiceId("my.service.id.1");
DefaultServiceInstance testInstance2_1 = new DefaultServiceInstance();
testInstance2_1.setUri(URI.create("http://my.service.id.2/1"));
testInstance2_1.setServiceId("my.service.id.2");
DefaultServiceInstance testInstance2_2 = new DefaultServiceInstance();
testInstance2_2.setUri(URI.create("http://my.service.id.2/2"));
testInstance2_2.setServiceId("my.service.id.2");
instances.put(
"my.service.id.1",
Arrays.asList(testInstance1_1, testInstance1_2)
);
instances.put(
"my.service.id.2",
Arrays.asList(testInstance2_1, testInstance2_2)
);
properties.setInstances(instances);
SimpleDiscoveryClient client = new SimpleDiscoveryClient(properties);
mockClient = client;
}
#Test
public void testGetServicesFilteringOutSingleService() {
FilteringDiscoveryClient client = new FilteringDiscoveryClient(
mockClient,
i -> !i.getUri().getAuthority().equals("my.service.id.1")
);
assertFalse(client.getServices().contains("my.service.id.1"), "list of services not expected to contain service 1");
assertTrue(client.getServices().contains("my.service.id.2"), "list of services expected to contain service 2");
}
}
the assertFalse fails because the i.getUri().getAuthority() returns null:80 instead of what the actual URI being passed is. It all seems to be set right according to the debugger during setup(). Any ideas where my test has gone wrong? Should I be setting URIs differently to begin with?
Edit: maybe I should add what the FilteringDiscoveryClient looks like
public class FilteringDiscoveryClient implements DiscoveryClient {
private final DiscoveryClient delegate;
private final Predicate<ServiceInstance> filter;
public FilteringDiscoveryClient(DiscoveryClient delegate, Predicate<ServiceInstance> filter) {
Assert.notNull(delegate, "delegate must not be null");
Assert.notNull(delegate, "filter must not be null");
this.delegate = delegate;
this.filter = filter;
}
#Override
public String description() {
return delegate.description();
}
#Override
public List<ServiceInstance> getInstances(String serviceId) {
return delegate.getInstances(serviceId).parallelStream().filter(filter).collect(Collectors.toList());
}
#Override
public List<String> getServices() {
return delegate.getServices().parallelStream().filter(s -> !getInstances(s).isEmpty()).collect(Collectors.toList());
}
}
maybe not an optimal solution but at least a workaround? Turns out that using .setUri() calls upon the overridden one within the class DefaultInstanceService, which does not set it the way I expected it to. It creates a new URI every time a new DefaultInstanceService is made from what I can tell, and that seems to not take the URI I give within setUri(). So I created constructors like so:
DefaultServiceInstance testInstance1_1 = new DefaultServiceInstance("http://my.service.id.1/1", "my.service.id.1", "my.service.id.1", -1, false);
DefaultServiceInstance testInstance1_2 = new DefaultServiceInstance("http://my.service.id.1/2", "my.service.id.1", "my.service.id.1", -1, false);
DefaultServiceInstance testInstance2_1 = new DefaultServiceInstance("http://my.service.id.2/1", "my.service.id.2", "my.service.id.2", -1, false);
DefaultServiceInstance testInstance2_2 = new DefaultServiceInstance("http://my.service.id.2/2", "my.service.id.2", "my.service.id.2", -1, false);
my tests work now but there is one small kink when trying to get the path, which I expected to be /2. Instead, no path is set at all because the setUri() within DefaultServiceInstance never sets a path explicitly, so it's always just an empty string. I cannot do calls like instance.getUri().getPath() because it will just give me an empty string back. To get to the "/2" I'm looking for I have to do instance.toString() and get it from there. All in all, not a great workaround but it's progress! If anyone has a better idea in the future I'd love to know.
In my Sling app I have data presenting documents, with pages, and content nodes. We mostly server those documents as HTML, but now I would like to have a servlet to serve these documents as PDF and PPT.
Basically, I thought about implementing the factory pattern : in my servlet, dependending on the extension of the request (pdf or ppt), I would get from a DocumentBuilderFactory, the proper DocumentBuilder implementation, either PdfDocumentBuilder or PptDocumentBuilder.
So first I had this:
public class PlanExportBuilderFactory {
public PlanExportBuilder getBuilder(String type) {
PlanExportBuilder builder = null;
switch (type) {
case "pdf":
builder = new PdfPlanExportBuilder();
break;
default:
logger.error("Unsupported plan export builder, type: " + type);
}
return builder;
}
}
In the servlet:
#Component(metatype = false)
#Service(Servlet.class)
#Properties({
#Property(name = "sling.servlet.resourceTypes", value = "myApp/document"),
#Property(name = "sling.servlet.extensions", value = { "ppt", "pdf" }),
#Property(name = "sling.servlet.methods", value = "GET")
})
public class PlanExportServlet extends SlingSafeMethodsServlet {
#Reference
PlanExportBuilderFactory builderFactory;
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
Resource resource = request.getResource();
PlanExportBuilder builder = builderFactory.getBuilder(request.getRequestPathInfo().getExtension());
}
}
But the problem is that in the builder I would like to reference other services to access Sling resources, and with this solution, they're not bound.
I looked at Services Factory with OSGi but from what I've understood, you use them to configure differently the same implementation of a service.
Then I found that you can get a specific implementation by naming it, or use a property and a filter.
So I've ended up with this:
public class PlanExportBuilderFactory {
#Reference(target = "(builderType=pdf)")
PlanExportBuilder pdfPlanExportBuilder;
public PlanExportBuilder getBuilder(String type) {
PlanExportBuilder builder = null;
switch (type) {
case "pdf":
return pdfPlanExportBuilder;
default:
logger.error("Unsupported plan export builder, type: " + type);
}
return builder;
}
}
The builder defining a "builderType" property :
// AbstractPlanExportBuilder implements PlanExportBuilder interface
#Component
#Service(value=PlanExportBuilder.class)
public class PdfPlanExportBuilder extends AbstractPlanExportBuilder {
#Property(name="builderType", value="pdf")
public PdfPlanExportBuilder() {
planDocument = new PdfPlanDocument();
}
}
I would like to know if it's a good way to retrieve my PDF builder implementation regarding OSGi good practices.
EDIT 1
From Peter's answer I've tried to add multiple references but with Felix it doesn't seem to work:
#Reference(name = "planExportBuilder", cardinality = ReferenceCardinality.MANDATORY_MULTIPLE, policy = ReferencePolicy.DYNAMIC)
private Map<String, PlanExportBuilder> builders = new ConcurrentHashMap<String, PlanExportBuilder>();
protected final void bindPlanExportBuilder(PlanExportBuilder b, Map<String, Object> props) {
final String type = PropertiesUtil.toString(props.get("type"), null);
if (type != null) {
this.builders.put((String) props.get("type"), b);
}
}
protected final void unbindPlanExportBuilder(final PlanExportBuilder b, Map<String, Object> props) {
final String type = PropertiesUtil.toString(props.get("type"), null);
if (type != null) {
this.builders.remove(type);
}
}
I get these errors :
#Reference(builders) : Missing method bind for reference planExportBuilder
#Reference(builders) : Something went wrong: false - true - MANDATORY_MULTIPLE
#Reference(builders) : Missing method unbind for reference planExportBuilder
The Felix documentation here http://felix.apache.org/documentation/subprojects/apache-felix-maven-scr-plugin/scr-annotations.html#reference says for the bind method:
The default value is the name created by appending the reference name to the string bind. The method must be declared public or protected and take single argument which is declared with the service interface type
So according to this, I understand it cannot work with Felix, as I'm trying to pass two arguments. However, I found an example here that seems to match what you've suggested but I cannot make it work: https://github.com/Adobe-Consulting-Services/acs-aem-samples/blob/master/bundle/src/main/java/com/adobe/acs/samples/services/impl/SampleMultiReferenceServiceImpl.java
EDIT 2
Just had to move the reference above the class to make it work:
#References({
#Reference(
name = "planExportBuilder",
referenceInterface = PlanExportBuilder.class,
policy = ReferencePolicy.DYNAMIC,
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
})
public class PlanExportServlet extends SlingSafeMethodsServlet {
Factories are evil :-) Main reason is of course the yucky class loading hacks that are usually used but also because they tend to have global knowledge. In general, you want to be able to add a bundle with a new DocumentBuilder and then that type should become available.
A more OSGi oriented solution is therefore to use service properties. This could look like:
#Component( property=HTTP_WHITEBOARD_FILTER_REGEX+"=/as")
public class DocumentServlet {
final Map<String,DocBuilder> builders = new ConcurrentHashMap<>();
public void doGet( HttpServletRequest rq, HttpServletResponse rsp )
throws IOException, ServletException {
InputStream in = getInputStream( rq.getPathInfo() );
if ( in == null )
....
String type = toType( rq.getPathInfo(), rq.getParameter("type") );
DocBuilder docbuilder = builders.get( type );
if ( docbuilder == null)
....
docbuilder.convert( type, in, rsp.getOutputStream() );
}
#Reference( cardinality=MULTIPLE, policy=DYNAMIC )
void addDocBuilder( DocBuilder db, Map<String,Object> props ) {
docbuilders.put(props.get("type"), db );
}
void removeDocBuilder(Map<String,Object> props ) {
docbuilders.remove(props.get("type"));
}
}
A DocBuilder could look like:
#Component( property = "type=ppt-pdf" )
public class PowerPointToPdf implements DocBuilder {
...
}
I'm trying to create a unified error handling/reporting in ASP.NET Web API 2.1 Project built on top of OWIN middleware (IIS HOST using Owin.Host.SystemWeb).
Currently I used a custom exception logger which inherits from System.Web.Http.ExceptionHandling.ExceptionLogger and uses NLog to log all exceptions as the code below:
public class NLogExceptionLogger : ExceptionLogger
{
private static readonly Logger Nlog = LogManager.GetCurrentClassLogger();
public override void Log(ExceptionLoggerContext context)
{
//Log using NLog
}
}
I want to change the response body for all API exceptions to a friendly unified response which hides all exception details using System.Web.Http.ExceptionHandling.ExceptionHandler as the code below:
public class ContentNegotiatedExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
var errorDataModel = new ErrorDataModel
{
Message = "Internal server error occurred, error has been reported!",
Details = context.Exception.Message,
ErrorReference = context.Exception.Data["ErrorReference"] != null ? context.Exception.Data["ErrorReference"].ToString() : string.Empty,
DateTime = DateTime.UtcNow
};
var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, errorDataModel);
context.Result = new ResponseMessageResult(response);
}
}
And this will return the response below for the client when an exception happens:
{
"Message": "Internal server error occurred, error has been reported!",
"Details": "Ooops!",
"ErrorReference": "56627a45d23732d2",
"DateTime": "2015-12-27T09:42:40.2982314Z"
}
Now this is working all great if any exception occurs within an Api Controller request pipeline.
But in my situation I'm using the middleware Microsoft.Owin.Security.OAuth for generating bearer tokens, and this middleware doesn't know anything about Web API exception handling, so for example if an exception has been in thrown in method ValidateClientAuthentication my NLogExceptionLogger not ContentNegotiatedExceptionHandler will know anything about this exception nor try to handle it, the sample code I used in the AuthorizationServerProvider is as the below:
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//Expcetion occurred here
int x = int.Parse("");
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
if (context.UserName != context.Password)
{
context.SetError("invalid_credentials", "The user name or password is incorrect.");
return;
}
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
context.Validated(identity);
}
}
So I will appreciate any guidance in implementing the below 2 issues:
1 - Create a global exception handler which handles only exceptions generated by OWIN middle wares? I followed this answer and created a middleware for exception handling purposes and registered it as the first one and I was able to log exceptions originated from "OAuthAuthorizationServerProvider", but I'm not sure if this is the optimal way to do it.
2 - Now when I implemented the logging as the in the previous step, I really have no idea how to change the response of the exception as I need to return to the client a standard JSON model for any exception happening in the "OAuthAuthorizationServerProvider". There is a related answer here I tried to depend on but it didn't work.
Here is my Startup class and the custom GlobalExceptionMiddleware I created for exception catching/logging. The missing peace is returning a unified JSON response for any exception. Any ideas will be appreciated.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());
httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
app.Use<GlobalExceptionMiddleware>();
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(httpConfig);
}
}
public class GlobalExceptionMiddleware : OwinMiddleware
{
public GlobalExceptionMiddleware(OwinMiddleware next)
: base(next)
{ }
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
NLogLogger.LogError(ex, context);
}
}
}
Ok, so this was easier than anticipated, thanks for #Khalid for the heads up, I have ended up creating an owin middleware named OwinExceptionHandlerMiddleware which is dedicated for handling any exception happening in any Owin Middleware (logging it and manipulating the response before returning it to the client).
You need to register this middleware as the first one in the Startup class as the below:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes();
httpConfig.Services.Replace(typeof(IExceptionHandler), new ContentNegotiatedExceptionHandler());
httpConfig.Services.Add(typeof(IExceptionLogger), new NLogExceptionLogger());
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
//Should be the first handler to handle any exception happening in OWIN middlewares
app.UseOwinExceptionHandler();
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseWebApi(httpConfig);
}
}
And the code used in the OwinExceptionHandlerMiddleware as the below:
using AppFunc = Func<IDictionary<string, object>, Task>;
public class OwinExceptionHandlerMiddleware
{
private readonly AppFunc _next;
public OwinExceptionHandlerMiddleware(AppFunc next)
{
if (next == null)
{
throw new ArgumentNullException("next");
}
_next = next;
}
public async Task Invoke(IDictionary<string, object> environment)
{
try
{
await _next(environment);
}
catch (Exception ex)
{
try
{
var owinContext = new OwinContext(environment);
NLogLogger.LogError(ex, owinContext);
HandleException(ex, owinContext);
return;
}
catch (Exception)
{
// If there's a Exception while generating the error page, re-throw the original exception.
}
throw;
}
}
private void HandleException(Exception ex, IOwinContext context)
{
var request = context.Request;
//Build a model to represet the error for the client
var errorDataModel = NLogLogger.BuildErrorDataModel(ex);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ReasonPhrase = "Internal Server Error";
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(errorDataModel));
}
}
public static class OwinExceptionHandlerMiddlewareAppBuilderExtensions
{
public static void UseOwinExceptionHandler(this IAppBuilder app)
{
app.Use<OwinExceptionHandlerMiddleware>();
}
}
There are a few ways to do what you want:
Create middleware that is registered first, then all exceptions will bubble up to that middleware. At this point just write out your JSON out via the Response object via the OWIN context.
You can also create a wrapping middleware which wraps the Oauth middleware. In this case it will on capture errors originating from this specific code path.
Ultimately writing your JSON message is about creating it, serializing it, and writing it to the Response via the OWIN context.
It seems like you are on the right path with #1. Hope this helps, and good luck :)
The accepted answer is unnecessarily complex and doesn't inherit from OwinMiddleware class
All you need to do is this:
public class HttpLogger : OwinMiddleware
{
public HttpLogger(OwinMiddleware next) : base(next) { }
public override async Task Invoke(IOwinContext context)
{
await Next.Invoke(context);
Log(context)
}
}
Also, no need to create extension method.. it is simple enough to reference without
appBuilder.Use(typeof(HttpErrorLogger));
And if you wanna log only specific requests, you can filter on context properties:
ex:
if (context.Response.StatusCode != 200) { Log(context) }
I have two activies that use UIL.
My general configuration application of UIL is:
public static void configureDefaultImageLoader(Context context) {
DisplayImageOptions thumbOptions = new DisplayImageOptions.Builder()
.showImageOnFail(R.drawable.ic_error_red_24dp)
.cacheInMemory(true)
.cacheOnDisk(true)
.displayer(new RoundedBitmapDisplayer(90))
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.defaultDisplayImageOptions(thumbOptions)
.threadPriority(Thread.MAX_PRIORITY)
.tasksProcessingOrder(QueueProcessingType.LIFO)
.threadPoolSize(5)
.build();
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(config);
}
Either activies have a custom adapter, that initialize UIL in constructor.
In my first activity the loading is fast, and anything work. The code's adapter is:
private ImageLoader imageLoader;
public ListViewAdapter(Context context)
{
layoutInflater = LayoutInflater.from(context);
imageLoader = ImageLoader.getInstance();
}
and in getView method:
if(thumbName != null ) {
imageLoader.displayImage("assets://coralsImages/" + thumbName, viewHolder.imageView);
}
The code's adapter in second activity is ugual, but loading is more slowly and difficult.How can resolve this problem?