diff options
author | Tor Norbye <tnorbye@google.com> | 2011-09-02 10:40:57 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2011-09-02 12:25:51 -0700 |
commit | 6a41615061dab508e87cbb18f005c5f7edb79dbd (patch) | |
tree | 86f1ae41cb5868491589fe2bae77516872527973 /ide_common/src | |
parent | 0c96c744e157c450f7d66bf62f9d569b9514e747 (diff) | |
download | sdk-6a41615061dab508e87cbb18f005c5f7edb79dbd.zip sdk-6a41615061dab508e87cbb18f005c5f7edb79dbd.tar.gz sdk-6a41615061dab508e87cbb18f005c5f7edb79dbd.tar.bz2 |
Clean up layout and menu file scanning code
This changeset fixes some issues around the new lazy scanning of
layout and menu files.
First, it partly fixes "19657: AAPT errors aren't shown when adding an
error to a valid XML file". With the new optimization of not running
aapt on layout files where no ids have changed, we would no longer
pick up changes where an invalid or nonexistent resource is added. We
now perform some basic validation of resources as well as XML parsing
errors.
Second, it fixes a bug in the id before and after comparison used to
determine if aapt needs to run: The code would call map.keySet()
before and after the ids were added, but this resolved to the same
keyset so the equals comparison was always true regardless of the
content.
Third, it fixes an infinite loop issue with library projects, and
avoids doing unnecessary classpath modifications when there are no
changed projects.
Finally, it changes the "needsId" flag. The state of whether aapt
needs to be run was stored per repository, and there is a bug where it
does not get cleared properly which can yield a compilation loop. This
changeset introduces a new "ScanningContext" object which is passed
down to the various resource file updater methods. This context object
now holds the needsId state object (which is renamed to
"needsFullAapt"), and it is also the object where errors can be
registered.
Change-Id: I5632612c2d93e2f10f0803e9223921adb67602be
Diffstat (limited to 'ide_common/src')
8 files changed, 330 insertions, 103 deletions
diff --git a/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java index 6706715..e4b6730 100644 --- a/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java @@ -24,8 +24,6 @@ import com.android.io.IAbstractFile; import com.android.io.StreamException; import com.android.resources.ResourceType; -import org.xml.sax.SAXException; - import java.io.IOException; import java.util.Collection; import java.util.HashMap; @@ -33,10 +31,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - /** * Represents a resource file that also generates ID resources. * <p/> @@ -45,11 +39,6 @@ import javax.xml.parsers.SAXParserFactory; public final class IdGeneratingResourceFile extends ResourceFile implements IValueResourceRepository { - private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance(); - static { - sParserFactory.setNamespaceAware(true); - } - private final Map<String, ResourceValue> mIdResources = new HashMap<String, ResourceValue>(); @@ -75,44 +64,49 @@ public final class IdGeneratingResourceFile extends ResourceFile mFileName = getFileName(type); // Get the resource value of this file as a whole layout - mFileValue = getFileValue(file,folder); + mFileValue = getFileValue(file, folder); } @Override - protected void load() { + protected void load(ScanningContext context) { // Parse the file and look for @+id/ entries - parseFileForIds(); + parseFileForIds(context); // create the resource items in the repository - updateResourceItems(); + updateResourceItems(context); } @Override - protected void update() { + protected void update(ScanningContext context) { // Copy the previous list of ID names - Set<String> oldIdNames = mIdResources.keySet(); + Set<String> oldIdNames = new HashSet<String>(mIdResources.keySet()); // reset current content. mIdResources.clear(); // need to parse the file and find the IDs. - parseFileForIds(); + if (!parseFileForIds(context)) { + context.requestFullAapt(); + return; + } // We only need to update the repository if our IDs have changed - if (oldIdNames.equals(mIdResources.keySet()) == false) { - updateResourceItems(); + Set<String> keySet = mIdResources.keySet(); + assert keySet != oldIdNames; + if (oldIdNames.equals(keySet) == false) { + updateResourceItems(context); } } @Override - protected void dispose() { + protected void dispose(ScanningContext context) { ResourceRepository repository = getRepository(); // Remove declarations from this file from the repository repository.removeFile(mResourceTypeList, this); // Ask for an ID refresh since we'll be taking away ID generating items - repository.markForIdRefresh(); + context.requestFullAapt(); } @Override @@ -145,22 +139,27 @@ public final class IdGeneratingResourceFile extends ResourceFile /** * Looks through the file represented for Ids and adds them to * our id repository + * + * @return true if parsing succeeds and false if it fails */ - private void parseFileForIds() { + private boolean parseFileForIds(ScanningContext context) { + IdResourceParser parser = new IdResourceParser(this, context, isFramework()); try { - SAXParser parser = sParserFactory.newSAXParser(); - parser.parse(getFile().getContents(), new IdResourceParser(this, isFramework())); - } catch (ParserConfigurationException e) { - } catch (SAXException e) { + IAbstractFile file = getFile(); + return parser.parse(mFileType, file.getOsLocation(), file.getContents()); } catch (IOException e) { + // Pass } catch (StreamException e) { + // Pass } + + return false; } /** * Add the resources represented by this file to the repository */ - private void updateResourceItems() { + private void updateResourceItems(ScanningContext context) { ResourceRepository repository = getRepository(); // remove this file from all existing ResourceItem. @@ -178,7 +177,7 @@ public final class IdGeneratingResourceFile extends ResourceFile } // Ask the repository for an ID refresh - repository.markForIdRefresh(); + context.requestFullAapt(); } /** diff --git a/ide_common/src/com/android/ide/common/resources/IdResourceParser.java b/ide_common/src/com/android/ide/common/resources/IdResourceParser.java index 27195a9..324ad2b 100644 --- a/ide_common/src/com/android/ide/common/resources/IdResourceParser.java +++ b/ide_common/src/com/android/ide/common/resources/IdResourceParser.java @@ -20,35 +20,136 @@ import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository; import com.android.resources.ResourceType; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; +import org.kxml2.io.KXmlParser; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; -public class IdResourceParser extends DefaultHandler { +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +/** + * Parser for scanning an id-generating resource file such as a layout or a menu + * file, which registers any ids it encounters with an + * {@link IValueResourceRepository}, and which registers errors with a + * {@link ScanningContext}. + */ +public class IdResourceParser { private final IValueResourceRepository mRepository; private final boolean mIsFramework; + private ScanningContext mContext; - public IdResourceParser(IValueResourceRepository repository, boolean isFramework) { - super(); + /** + * Creates a new {@link IdResourceParser} + * + * @param repository value repository for registering resource declaration + * @param context a context object with state for the current update, such + * as a place to stash errors encountered + * @param isFramework true if scanning a framework resource + */ + public IdResourceParser(IValueResourceRepository repository, ScanningContext context, + boolean isFramework) { mRepository = repository; + mContext = context; mIsFramework = isFramework; } - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - for (int i = 0; i < attributes.getLength(); ++i) { - // Let's look up the value to look for the @+*id/ pattern - String candidate = attributes.getValue(i); - // Right now the only things that start with the @+ pattern are IDs. If this changes - // in the future we'll have to change this line - if (candidate != null && candidate.startsWith("@+")) { - // Strip out the @+id/ or @+android:id/ section - String id = candidate.substring(candidate.indexOf('/') + 1); - ResourceValue newId = new ResourceValue(ResourceType.ID, id, mIsFramework); - mRepository.addResourceValue(newId); + /** + * Parse the given input and register ids with the given + * {@link IValueResourceRepository}. + * + * @param type the type of resource being scanned + * @param path the full OS path to the file being parsed + * @param input the input stream of the XML to be parsed + * @return true if parsing succeeds and false if it fails + * @throws IOException if reading the contents fails + */ + public boolean parse(ResourceType type, final String path, InputStream input) + throws IOException { + KXmlParser parser = new KXmlParser(); + try { + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + + if (input instanceof FileInputStream) { + input = new BufferedInputStream(input); } + parser.setInput(input, "UTF-8"); //$NON-NLS-1$ + + return parse(type, path, parser); + } catch (XmlPullParserException e) { + String message = e.getMessage(); + + // Strip off position description + int index = message.indexOf("(position:"); //$NON-NLS-1$ (Hardcoded in KXml) + if (index != -1) { + message = message.substring(0, index); + } + + String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$ + path, parser.getLineNumber(), message); + mContext.addError(error); + return false; + } catch (RuntimeException e) { + // Some exceptions are thrown by the KXmlParser that are not XmlPullParserExceptions, + // such as this one: + // java.lang.RuntimeException: Undefined Prefix: w in org.kxml2.io.KXmlParser@... + // at org.kxml2.io.KXmlParser.adjustNsp(Unknown Source) + // at org.kxml2.io.KXmlParser.parseStartTag(Unknown Source) + String message = e.getMessage(); + String error = String.format("%1$s:%2$d: Error: %3$s", //$NON-NLS-1$ + path, parser.getLineNumber(), message); + mContext.addError(error); + return false; } } + + private boolean parse(ResourceType type, String path, KXmlParser parser) + throws XmlPullParserException, IOException { + boolean valid = true; + ResourceRepository resources = mContext.getRepository(); + boolean checkForErrors = !mIsFramework && !mContext.needsFullAapt(); + + while (true) { + int event = parser.next(); + if (event == XmlPullParser.START_TAG) { + for (int i = 0, n = parser.getAttributeCount(); i < n; i++) { + String attribute = parser.getAttributeName(i); + String value = parser.getAttributeValue(i); + assert value != null : attribute; + + if (value.startsWith("@")) { //$NON-NLS-1$ + // Gather IDs + if (value.startsWith("@+")) { //$NON-NLS-1$ + // Strip out the @+id/ or @+android:id/ section + String id = value.substring(value.indexOf('/') + 1); + ResourceValue newId = new ResourceValue(ResourceType.ID, id, + mIsFramework); + mRepository.addResourceValue(newId); + } else if (checkForErrors){ + // Validate resource references (unless we're scanning a framework + // resource or if we've already scheduled a full aapt run) + boolean exists = resources.hasResourceItem(value); + if (!exists) { + String error = String.format( + // Don't localize because the exact pattern matches AAPT's + // output which has hardcoded regexp matching in + // AaptParser. + "%1$s:%2$d: Error: No resource found that matches " + //$NON-NLS-1$ + "the given name (at '%3$s' with value '%4$s')", //$NON-NLS-1$ + path, parser.getLineNumber(), + attribute, value); + mContext.addError(error); + valid = false; + } + } + } + } + } else if (event == XmlPullParser.END_DOCUMENT) { + break; + } + } + + return valid; + } } diff --git a/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java b/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java index b3e35d9..b95a98c 100644 --- a/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/MultiResourceFile.java @@ -59,7 +59,7 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou private boolean mNeedIdRefresh; @Override - protected void load() { + protected void load(ScanningContext context) { // need to parse the file and find the content. parseFile(); @@ -70,11 +70,11 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou mNeedIdRefresh = true; // create/update the resource items. - updateResourceItems(); + updateResourceItems(context); } @Override - protected void update() { + protected void update(ScanningContext context) { // Reset the ID generation flag mNeedIdRefresh = false; @@ -107,18 +107,18 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou mNeedIdRefresh = true; } // create/update the resource items. - updateResourceItems(); + updateResourceItems(context); } @Override - protected void dispose() { + protected void dispose(ScanningContext context) { ResourceRepository repository = getRepository(); // only remove this file from all existing ResourceItem. repository.removeFile(mResourceTypeList, this); // We'll need an ID refresh because we deleted items - repository.markForIdRefresh(); + context.requestFullAapt(); // don't need to touch the content, it'll get reclaimed as this objects disappear. // In the mean time other objects may need to access it. @@ -135,7 +135,7 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou return (list != null && list.size() > 0); } - private void updateResourceItems() { + private void updateResourceItems(ScanningContext context) { ResourceRepository repository = getRepository(); // remove this file from all existing ResourceItem. @@ -157,7 +157,7 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou // If we need an ID refresh, ask the repository for that now if (mNeedIdRefresh) { - repository.markForIdRefresh(); + context.requestFullAapt(); } } diff --git a/ide_common/src/com/android/ide/common/resources/ResourceFile.java b/ide_common/src/com/android/ide/common/resources/ResourceFile.java index 03f0b34..bc5b750 100644 --- a/ide_common/src/com/android/ide/common/resources/ResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/ResourceFile.java @@ -37,9 +37,9 @@ public abstract class ResourceFile implements Configurable { mFolder = folder; } - protected abstract void load(); - protected abstract void update(); - protected abstract void dispose(); + protected abstract void load(ScanningContext context); + protected abstract void update(ScanningContext context); + protected abstract void dispose(ScanningContext context); public FolderConfiguration getConfiguration() { return mFolder.getConfiguration(); diff --git a/ide_common/src/com/android/ide/common/resources/ResourceFolder.java b/ide_common/src/com/android/ide/common/resources/ResourceFolder.java index e55e14c..b8e0cda 100644 --- a/ide_common/src/com/android/ide/common/resources/ResourceFolder.java +++ b/ide_common/src/com/android/ide/common/resources/ResourceFolder.java @@ -47,7 +47,7 @@ public final class ResourceFolder implements Configurable { * @param type The type of the folder * @param config The configuration of the folder * @param folder The associated {@link IAbstractFolder} object. - * @param isFrameworkRepository + * @param repository The associated {@link ResourceRepository} */ protected ResourceFolder(ResourceFolderType type, FolderConfiguration config, IAbstractFolder folder, ResourceRepository repository) { @@ -59,12 +59,15 @@ public final class ResourceFolder implements Configurable { /** * Processes a file and adds it to its parent folder resource. + * * @param file the underlying resource file. - * @param folder the parent of the resource file. * @param kind the file change kind. + * @param context a context object with state for the current update, such + * as a place to stash errors encountered * @return the {@link ResourceFile} that was created. */ - public ResourceFile processFile(IAbstractFile file, ResourceDeltaKind kind) { + public ResourceFile processFile(IAbstractFile file, ResourceDeltaKind kind, + ScanningContext context) { // look for this file if it's already been created ResourceFile resFile = getFile(file); @@ -84,7 +87,7 @@ public final class ResourceFolder implements Configurable { if (types.size() == 1) { resFile = new SingleResourceFile(file, this); - } else if (types.contains(ResourceType.LAYOUT)){ + } else if (types.contains(ResourceType.LAYOUT)) { resFile = new IdGeneratingResourceFile(file, this, ResourceType.LAYOUT); } else if (types.contains(ResourceType.MENU)) { resFile = new IdGeneratingResourceFile(file, this, ResourceType.MENU); @@ -92,16 +95,16 @@ public final class ResourceFolder implements Configurable { resFile = new MultiResourceFile(file, this); } - resFile.load(); + resFile.load(context); // add it to the folder addFile(resFile); } } else { if (kind == ResourceDeltaKind.REMOVED) { - removeFile(resFile); + removeFile(resFile, context); } else { - resFile.update(); + resFile.update(context); } } @@ -122,15 +125,15 @@ public final class ResourceFolder implements Configurable { mFiles.add(file); } - protected void removeFile(ResourceFile file) { - file.dispose(); + protected void removeFile(ResourceFile file, ScanningContext context) { + file.dispose(context); mFiles.remove(file); } - protected void dispose() { + protected void dispose(ScanningContext context) { if (mFiles != null) { for (ResourceFile file : mFiles) { - file.dispose(); + file.dispose(context); } mFiles.clear(); diff --git a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java index 4af4a1a..d78f1d1 100644 --- a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java +++ b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java @@ -68,8 +68,6 @@ public abstract class ResourceRepository { protected final IntArrayWrapper mWrapper = new IntArrayWrapper(null); - private boolean mNeedsIdRefresh; - /** * Makes a resource repository * @param isFrameworkRepository whether the repository is for framework resources. @@ -129,7 +127,8 @@ public abstract class ResourceRepository { * @param removedFolder the IAbstractFolder object. * @return the {@link ResourceFolder} that was removed, or null if no matches were found. */ - public ResourceFolder removeFolder(ResourceFolderType type, IAbstractFolder removedFolder) { + public ResourceFolder removeFolder(ResourceFolderType type, IAbstractFolder removedFolder, + ScanningContext context) { // get the list of folders for the resource type. List<ResourceFolder> list = mFolderMap.get(type); @@ -143,7 +142,7 @@ public abstract class ResourceRepository { list.remove(i); // remove its content - resFolder.dispose(); + resFolder.dispose(context); return resFolder; } @@ -154,6 +153,60 @@ public abstract class ResourceRepository { } /** + * Returns true if this resource repository contains a resource of the given + * name. + * + * @param url the resource URL + * @return true if the resource is known + */ + public boolean hasResourceItem(String url) { + assert url.startsWith("@") : url; + + int typeEnd = url.indexOf('/', 1); + if (typeEnd != -1) { + int nameBegin = typeEnd + 1; + + // Skip @ and @+ + int typeBegin = url.startsWith("@+") ? 2 : 1; //$NON-NLS-1$ + + int colon = url.lastIndexOf(':', typeEnd); + if (colon != -1) { + typeBegin = colon + 1; + } + String typeName = url.substring(typeBegin, typeEnd); + ResourceType type = ResourceType.getEnum(typeName); + if (type != null) { + String name = url.substring(nameBegin); + return hasResourceItem(type, name); + } + } + + return false; + } + + /** + * Returns true if this resource repository contains a resource of the given + * name. + * + * @param type the type of resource to look up + * @param name the name of the resource + * @return true if the resource is known + */ + public boolean hasResourceItem(ResourceType type, String name) { + List<ResourceItem> list = mResourceMap.get(type); + + if (list != null) { + for (ResourceItem item : list) { + if (name.equals(item.getName())) { + return true; + } + } + } + + return false; + } + + /** * Returns a {@link ResourceItem} matching the given {@link ResourceType} and name. If none * exist, it creates one. * @@ -196,29 +249,6 @@ public abstract class ResourceRepository { protected abstract ResourceItem createResourceItem(String name); /** - * Sets a flag which determines whether aapt needs to be run to regenerate resource IDs - */ - protected void markForIdRefresh() { - mNeedsIdRefresh = true; - } - - /** - * Returns whether this repository has been marked as "dirty"; if one or more of the constituent - * files have declared that the resource item names that they provide have changed. - */ - public boolean needsIdRefresh() { - return mNeedsIdRefresh; - } - - /** - * Indicates that the resources IDs have been regenerated, so the repository is now in a clean - * state - */ - public void setIdsRefreshed() { - mNeedsIdRefresh = false; - } - - /** * Processes a folder and adds it to the list of existing folders. * @param folder the folder to process * @return the ResourceFolder created from this folder, or null if the process failed. @@ -496,6 +526,8 @@ public abstract class ResourceRepository { */ public void loadResources(IAbstractFolder rootFolder) throws IOException { + ScanningContext context = new ScanningContext(this); + IAbstractResource[] files = rootFolder.listMembers(); for (IAbstractResource file : files) { if (file instanceof IAbstractFolder) { @@ -509,7 +541,7 @@ public abstract class ResourceRepository { for (IAbstractResource childRes : children) { if (childRes instanceof IAbstractFile) { resFolder.processFile((IAbstractFile) childRes, - ResourceDeltaKind.ADDED); + ResourceDeltaKind.ADDED, context); } } } diff --git a/ide_common/src/com/android/ide/common/resources/ScanningContext.java b/ide_common/src/com/android/ide/common/resources/ScanningContext.java new file mode 100644 index 0000000..e4ed275 --- /dev/null +++ b/ide_common/src/com/android/ide/common/resources/ScanningContext.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.common.resources; + +import java.util.ArrayList; +import java.util.List; + +/** + * A {@link ScanningContext} keeps track of state during a resource file scan, + * such as any parsing errors encountered, whether Android ids have changed, and + * so on. + */ +public class ScanningContext { + private final ResourceRepository mRepository; + private boolean mNeedsFullAapt; + private List<String> mErrors = null; + + /** + * Constructs a new {@link ScanningContext} + * + * @param repository the associated resource repository + */ + public ScanningContext(ResourceRepository repository) { + super(); + mRepository = repository; + } + + /** + * Returns a list of errors encountered during scanning + * + * @return a list of errors encountered during scanning (or null) + */ + public List<String> getErrors() { + return mErrors; + } + + /** + * Adds the given error to the scanning context. The error should use the + * same syntax as real aapt error messages such that the aapt parser can + * properly detect the filename, line number, etc. + * + * @param error the error message, including file name and line number at + * the beginning + */ + public void addError(String error) { + if (mErrors == null) { + mErrors = new ArrayList<String>(); + } + mErrors.add(error); + } + + /** + * Returns the repository associated with this scanning context + * + * @return the associated repository, never null + */ + public ResourceRepository getRepository() { + return mRepository; + } + + /** + * Marks that a full aapt compilation of the resources is necessary because it has + * detected a change that cannot be incrementally handled. + */ + protected void requestFullAapt() { + mNeedsFullAapt = true; + } + + /** + * Returns whether this repository has been marked as "dirty"; if one or + * more of the constituent files have declared that the resource item names + * that they provide have changed. + * + * @return true if a full aapt compilation is required + */ + public boolean needsFullAapt() { + return mNeedsFullAapt; + } +} diff --git a/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java b/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java index b589b35..6b663e9 100644 --- a/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java +++ b/ide_common/src/com/android/ide/common/resources/SingleResourceFile.java @@ -73,7 +73,7 @@ public class SingleResourceFile extends ResourceFile { } @Override - protected void load() { + protected void load(ScanningContext context) { // get a resource item matching the given type and name ResourceItem item = getRepository().getResourceItem(mType, mResourceName); @@ -81,22 +81,22 @@ public class SingleResourceFile extends ResourceFile { item.add(this); // Ask for an ID refresh since we're adding an item that will generate an ID - getRepository().markForIdRefresh(); + context.requestFullAapt(); } @Override - protected void update() { + protected void update(ScanningContext context) { // when this happens, nothing needs to be done since the file only generates // a single resources that doesn't actually change (its content is the file path) } @Override - protected void dispose() { + protected void dispose(ScanningContext context) { // only remove this file from the existing ResourceItem. getFolder().getRepository().removeFile(mType, this); // Ask for an ID refresh since we're removing an item that previously generated an ID - getRepository().markForIdRefresh(); + context.requestFullAapt(); // don't need to touch the content, it'll get reclaimed as this objects disappear. // In the mean time other objects may need to access it. |