Set GIF image to Custom ImageView - android

I have custom ImageView for animated GIF image. i want to show GIF image, I tried but in this case it is contain url in Async instead I want to show GIF image from raw folder without using Glide. Anyone have any idea how to show image? Please guyz help to solve this problem!!!
I tried this for set raw file
new GifStaticData() {
#Override
protected void onPostExecute(Resource drawable) {
super.onPostExecute(drawable);
gifImageView.setImageResource(R.raw.earth_tilt_animation);
// Log.d(TAG, "GIF width is " + gifImageView.getGifWidth());
// Log.d(TAG, "GIF height is " + gifImageView.getGifHeight());
}
}.execute(R.raw.earth_tilt_animation);
GifStaticData.java
public class GifStaticData extends AsyncTask<Resource, Void, Resource> {
private static final String TAG = "GifDataDownloader";
#Override protected Resource doInBackground(final Resource... params) {
final Resource gifUrl = params[0];
if (gifUrl == null)
return null;
try {
// return ByteArrayHttpClient.get(gifUrl);
return gifUrl;
} catch (OutOfMemoryError e) {
Log.e(TAG, "GifDecode OOM: " + gifUrl, e);
return null;
}
}
}
GifImageView.java
public class GifImageView extends ImageView implements Runnable {
private static final String TAG = "GifDecoderView";
private GifDecoder gifDecoder;
private Bitmap tmpBitmap;
private final Handler handler = new Handler(Looper.getMainLooper());
private boolean animating;
private boolean shouldClear;
private Thread animationThread;
private OnFrameAvailable frameCallback = null;
private long framesDisplayDuration = -1L;
private OnAnimationStop animationStopCallback = null;
private final Runnable updateResults = new Runnable() {
#Override
public void run() {
if (tmpBitmap != null && !tmpBitmap.isRecycled()) {
setImageBitmap(tmpBitmap);
}
}
};
private final Runnable cleanupRunnable = new Runnable() {
#Override
public void run() {
tmpBitmap = null;
gifDecoder = null;
animationThread = null;
shouldClear = false;
}
};
public GifImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public GifImageView(final Context context) {
super(context);
}
public void setBytes(final byte[] bytes) {
gifDecoder = new GifDecoder();
try {
gifDecoder.read(bytes);
gifDecoder.advance();
} catch (final OutOfMemoryError e) {
gifDecoder = null;
Log.e(TAG, e.getMessage(), e);
return;
}
if (canStart()) {
animationThread = new Thread(this);
animationThread.start();
}
}
public long getFramesDisplayDuration() {
return framesDisplayDuration;
}
/**
* Sets custom display duration in milliseconds for the all frames. Should be called before {#link
* #startAnimation()}
*
* #param framesDisplayDuration Duration in milliseconds. Default value = -1, this property will
* be ignored and default delay from gif file will be used.
*/
public void setFramesDisplayDuration(long framesDisplayDuration) {
this.framesDisplayDuration = framesDisplayDuration;
}
public void startAnimation() {
animating = true;
if (canStart()) {
animationThread = new Thread(this);
animationThread.start();
}
}
public boolean isAnimating() {
return animating;
}
public void stopAnimation() {
animating = false;
if (animationThread != null) {
animationThread.interrupt();
animationThread = null;
}
}
public void clear() {
animating = false;
shouldClear = true;
stopAnimation();
handler.post(cleanupRunnable);
}
private boolean canStart() {
return animating && gifDecoder != null && animationThread == null;
}
public int getGifWidth() {
return gifDecoder.getWidth();
}
public int getGifHeight() {
return gifDecoder.getHeight();
}
#Override public void run() {
if (shouldClear) {
handler.post(cleanupRunnable);
return;
}
final int n = gifDecoder.getFrameCount();
do {
for (int i = 0; i < n; i++) {
if (!animating) {
break;
}
//milliseconds spent on frame decode
long frameDecodeTime = 0;
try {
long before = System.nanoTime();
tmpBitmap = gifDecoder.getNextFrame();
frameDecodeTime = (System.nanoTime() - before) / 1000000;
if (frameCallback != null) {
tmpBitmap = frameCallback.onFrameAvailable(tmpBitmap);
}
if (!animating) {
break;
}
handler.post(updateResults);
} catch (final ArrayIndexOutOfBoundsException | IllegalArgumentException e) {
Log.w(TAG, e);
}
if (!animating) {
break;
}
gifDecoder.advance();
try {
int delay = gifDecoder.getNextDelay();
// Sleep for frame duration minus time already spent on frame decode
// Actually we need next frame decode duration here,
// but I use previous frame time to make code more readable
delay -= frameDecodeTime;
if (delay > 0) {
Thread.sleep(framesDisplayDuration > 0 ? framesDisplayDuration : delay);
}
} catch (final Exception e) {
// suppress any exception
// it can be InterruptedException or IllegalArgumentException
}
}
} while (animating);
if (animationStopCallback != null) {
animationStopCallback.onAnimationStop();
}
}
public OnFrameAvailable getOnFrameAvailable() {
return frameCallback;
}
public void setOnFrameAvailable(OnFrameAvailable frameProcessor) {
this.frameCallback = frameProcessor;
}
public interface OnFrameAvailable {
Bitmap onFrameAvailable(Bitmap bitmap);
}
public OnAnimationStop getOnAnimationStop() {
return animationStopCallback;
}
public void setOnAnimationStop(OnAnimationStop animationStop) {
this.animationStopCallback = animationStop;
}
public interface OnAnimationStop {
void onAnimationStop();
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
clear();
}
}

I had to play and pause the Gif image Glide - Cannot stop gif onClick- Getting TransitionDrawable instead of Animate/GifDrawable
The idea is to get drawable from view,checking if it is an instance of Gifdrawable and playing and pausing it.(Hoping the gif image is already playing)
Add this In OnClick of GifImageView
Drawable drawable = ((ImageView) v).getDrawable();
if (drawable instanceof GifDrawable) {
GifDrawable animatable = (GifDrawable) drawable;
if (animatable.isRunning()) {
animatable.stop();
} else {
animatable.start();
}
}

I found the solution of above problem using GifMovieView!!!
GifMovieViewer.java
public class GifMovieViewer extends Activity {
private Button btnStart;
private GifMovieView gif1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gif_movie_viewer);
gif1 = (GifMovieView) findViewById(R.id.gif1);
btnStart = (Button) findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gif1.setMovieResource(R.drawable.earth_tilt_animation);
//for pause
// gif1.setPaused(gif1.isPaused());
}
});
}
public void onGifClick(View v) {
GifMovieView gif = (GifMovieView) v;
gif.setPaused(!gif.isPaused());
}
}

Related

how to track percentage of progressing download of each downloading file in exoplayer library?

I am working on a media player app. I'm using ExoPlayer library. I have a playlist of videos, and I want to download videos simultaneously. I done it by using available demo app of exoplayer library on GitHub. I want to show progress of each downloading in the UI. For this job I get help from DownloadNotificationUtil.buildProgressNotification method.
#Override
protected Notification getForegroundNotification(TaskState[] taskStates) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadTasks = false;
boolean haveRemoveTasks = false;
Log.e(TAG,"size task state: "+taskStates.length);
for (TaskState taskState : taskStates) {
Log.e(TAG,"taskId= "+taskState.taskId);
if (taskState.state != TaskState.STATE_STARTED
&& taskState.state != TaskState.STATE_COMPLETED) {
continue;
}
if (taskState.action.isRemoveAction) {
haveRemoveTasks = true;
continue;
}
haveDownloadTasks = true;
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += taskState.downloadPercentage;
}
haveDownloadedBytes |= taskState.downloadedBytes > 0;
downloadTaskCount++;
}
int progress = 0;
boolean indeterminate = true;
if (haveDownloadTasks) {
progress = (int) (totalPercentage / downloadTaskCount);
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
Log.e(TAG,"notifi "+progress);
}
return DownloadNotificationUtil.buildProgressNotification(
this,
R.drawable.exo_icon_play,
DOWNLOAD_CHANNEL_ID,
null,
null,
taskStates);
}
Now,I can track the progress downloading. But I still have a problem. I can't understand which item is downloading to update it's progress bar in the UI. Is there a Identical id of each download to recognize it? For example Android Download Manager has a download ID for each downloading file. But I don't know , how to handle this problem.
This is MediaDownloadService:
public class MediaDownloadService extends DownloadService {
public static String TAG="MediaDownloadService";
private static final int FOREGROUND_NOTIFICATION_ID = 1;
public MediaDownloadService() {
super(
DOWNLOAD_NOTIFICATION_ID,
DEFAULT_FOREGROUND_NOTIFICATION_UPDATE_INTERVAL,
DOWNLOAD_CHANNEL_ID,
R.string.download_channel_name);
}
#Override
protected DownloadManager getDownloadManager() {
return ((MyApplication) getApplication()).getDownloadManager();
}
#Nullable
#Override
protected Scheduler getScheduler() {
return null;
}
#Override
protected Notification getForegroundNotification(TaskState[] taskStates) {
float totalPercentage = 0;
int downloadTaskCount = 0;
boolean allDownloadPercentagesUnknown = true;
boolean haveDownloadedBytes = false;
boolean haveDownloadTasks = false;
boolean haveRemoveTasks = false;
for (TaskState taskState : taskStates) {
if (taskState.state != TaskState.STATE_STARTED
&& taskState.state != TaskState.STATE_COMPLETED) {
continue;
}
if (taskState.action.isRemoveAction) {
haveRemoveTasks = true;
continue;
}
haveDownloadTasks = true;
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += taskState.downloadPercentage;
}
haveDownloadedBytes |= taskState.downloadedBytes > 0;
downloadTaskCount++;
}
int progress = 0;
boolean indeterminate = true;
if (haveDownloadTasks) {
progress = (int) (totalPercentage / downloadTaskCount);
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
Log.e(TAG,"notifi "+progress);
sendIntent(progress);
}
return DownloadNotificationUtil.buildProgressNotification(
this,
R.drawable.exo_icon_play,
DOWNLOAD_CHANNEL_ID,
null,
null,
taskStates);
}
private void sendIntent(int progress){
Intent intent = new Intent(ConstantUtil.MESSAGE_PROGRESS);
intent.putExtra("progress",progress);
LocalBroadcastManager.getInstance(MediaDownloadService.this).sendBroadcast(intent);
}
#Override
protected void onTaskStateChanged(TaskState taskState) {
if (taskState.action.isRemoveAction) {
return;
}
Notification notification = null;
if (taskState.state == TaskState.STATE_COMPLETED) {
Log.e(TAG,"STATE_COMPLETED");
notification =
DownloadNotificationUtil.buildDownloadCompletedNotification(
/* context= */ this,
R.drawable.exo_controls_play,
DOWNLOAD_CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
} else if (taskState.state == TaskState.STATE_FAILED) {
Log.e(TAG,"STATE_FAILED");
notification =
DownloadNotificationUtil.buildDownloadFailedNotification(
/* context= */ this,
R.drawable.exo_controls_play,
DOWNLOAD_CHANNEL_ID,
/* contentIntent= */ null,
Util.fromUtf8Bytes(taskState.action.data));
}
int notificationId = FOREGROUND_NOTIFICATION_ID + 1 + taskState.taskId;
NotificationUtil.setNotification(this, notificationId, notification);
}
}
This is DownloadTracker class:
public class DownloadTracker implements DownloadManager.Listener {
/** Listens for changes in the tracked downloads. */
public interface Listener {
/** Called when the tracked downloads changed. */
void onDownloadsChanged();
}
private static final String TAG = "DownloadTracker";
private final Context context;
private final DataSource.Factory dataSourceFactory;
private final TrackNameProvider trackNameProvider;
private final CopyOnWriteArraySet<Listener> listeners;
private Listener onDownloadsChanged;
private final HashMap<Uri, DownloadAction> trackedDownloadStates;
private final ActionFile actionFile;
private final Handler actionFileWriteHandler;
public DownloadTracker(
Context context,
DataSource.Factory dataSourceFactory,
File actionFile,
DownloadAction.Deserializer... deserializers) {
this.context = context.getApplicationContext();
this.dataSourceFactory = dataSourceFactory;
this.actionFile = new ActionFile(actionFile);
trackNameProvider = new DefaultTrackNameProvider(context.getResources());
listeners = new CopyOnWriteArraySet<>();
trackedDownloadStates = new HashMap<>();
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
actionFileWriteThread.start();
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
loadTrackedActions(
deserializers.length > 0 ? deserializers : DownloadAction.getDefaultDeserializers());
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
public boolean isDownloaded(Uri uri) {
return trackedDownloadStates.containsKey(uri);
}
#SuppressWarnings("unchecked")
public List<StreamKey> getOfflineStreamKeys(Uri uri) {
if (!trackedDownloadStates.containsKey(uri)) {
return Collections.emptyList();
}
return trackedDownloadStates.get(uri).getKeys();
}
public int toggleDownload(Activity activity, String name, Uri uri, String extension) {
if (isDownloaded(uri)) {
Log.e(TAG,"isDownloaded");
DownloadAction removeAction =
getDownloadHelper(uri, extension).getRemoveAction(Util.getUtf8Bytes(name));
startServiceWithAction(removeAction);
return -1;
} else {
StartDownloadDialogHelper helper =
new StartDownloadDialogHelper(activity, getDownloadHelper(uri, extension), name);
helper.prepare();
return helper.getTaskId();
}
}
#Override
public void onInitialized(DownloadManager downloadManager) {
// Do nothing.
}
#Override
public void onTaskStateChanged(DownloadManager downloadManager, TaskState taskState) {
DownloadAction action = taskState.action;
Uri uri = action.uri;
if ((action.isRemoveAction && taskState.state == TaskState.STATE_COMPLETED)
|| (!action.isRemoveAction && taskState.state == TaskState.STATE_FAILED)) {
// A download has been removed, or has failed. Stop tracking it.
if (trackedDownloadStates.remove(uri) != null) {
handleTrackedDownloadStatesChanged();
}
}
}
#Override
public void onIdle(DownloadManager downloadManager) {
// Do nothing.
}
// Internal methods
private void loadTrackedActions(DownloadAction.Deserializer[] deserializers) {
try {
DownloadAction[] allActions = actionFile.load(deserializers);
for (DownloadAction action : allActions) {
trackedDownloadStates.put(action.uri, action);
}
} catch (IOException e) {
Log.e(TAG, "Failed to load tracked actions", e);
}
}
private void handleTrackedDownloadStatesChanged() {
for (Listener listener : listeners) {
listener.onDownloadsChanged();
}
final DownloadAction[] actions = trackedDownloadStates.values().toArray(new DownloadAction[0]);
Log.e(TAG,"actions: "+actions.toString());
actionFileWriteHandler.post(
() -> {
try {
actionFile.store(actions);
} catch (IOException e) {
Log.e(TAG, "Failed to store tracked actions", e);
}
});
}
private void startDownload(DownloadAction action) {
if (trackedDownloadStates.containsKey(action.uri)) {
// This content is already being downloaded. Do nothing.
Log.e(TAG,"download already exsit");
return;
}
trackedDownloadStates.put(action.uri, action);
handleTrackedDownloadStatesChanged();
startServiceWithAction(action);
}
private void startServiceWithAction(DownloadAction action) {
DownloadService.startWithAction(context, MediaDownloadService.class, action, false);
}
private DownloadHelper getDownloadHelper(Uri uri, String extension) {
int type = Util.inferContentType(uri, extension);
switch (type) {
case C.TYPE_DASH:
return new DashDownloadHelper(uri, dataSourceFactory);
case C.TYPE_SS:
return new SsDownloadHelper(uri, dataSourceFactory);
case C.TYPE_HLS:
return new HlsDownloadHelper(uri, dataSourceFactory);
case C.TYPE_OTHER:
return new ProgressiveDownloadHelper(uri);
default:
throw new IllegalStateException("Unsupported type: " + type);
}
}
private final class StartDownloadDialogHelper
implements DownloadHelper.Callback, DialogInterface.OnClickListener {
private final DownloadHelper downloadHelper;
private final String name;
private final AlertDialog.Builder builder;
private final View dialogView;
private final List<TrackKey> trackKeys;
private final ArrayAdapter<String> trackTitles;
private final ListView representationList;
private int taskId;
public StartDownloadDialogHelper(
Activity activity, DownloadHelper downloadHelper, String name) {
this.downloadHelper = downloadHelper;
this.name = name;
builder =
new AlertDialog.Builder(activity)
.setTitle(R.string.exo_download_description)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null);
// Inflate with the builder's context to ensure the correct style is used.
LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
dialogView = dialogInflater.inflate(R.layout.start_download_dialog, null);
trackKeys = new ArrayList<>();
trackTitles =
new ArrayAdapter<>(
builder.getContext(), android.R.layout.simple_list_item_multiple_choice);
representationList = dialogView.findViewById(R.id.representation_list);
representationList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
representationList.setAdapter(trackTitles);
}
public void prepare() {
downloadHelper.prepare(this);
}
#Override
public void onPrepared(DownloadHelper helper) {
for (int i = 0; i < downloadHelper.getPeriodCount(); i++) {
TrackGroupArray trackGroups = downloadHelper.getTrackGroups(i);
for (int j = 0; j < trackGroups.length; j++) {
TrackGroup trackGroup = trackGroups.get(j);
for (int k = 0; k < trackGroup.length; k++) {
trackKeys.add(new TrackKey(i, j, k));
trackTitles.add(trackNameProvider.getTrackName(trackGroup.getFormat(k)));
}
}
}
if (!trackKeys.isEmpty()) {
builder.setView(dialogView);
}
builder.create().show();
}
#Override
public void onPrepareError(DownloadHelper helper, IOException e) {
Toast.makeText(
context.getApplicationContext(), R.string.download_start_error, Toast.LENGTH_LONG)
.show();
Log.e(TAG, "Failed to start download", e);
}
#Override
public void onClick(DialogInterface dialog, int which) {
ArrayList<TrackKey> selectedTrackKeys = new ArrayList<>();
for (int i = 0; i < representationList.getChildCount(); i++) {
if (representationList.isItemChecked(i)) {
selectedTrackKeys.add(trackKeys.get(i));
}
}
if (!selectedTrackKeys.isEmpty() || trackKeys.isEmpty()) {
// We have selected keys, or we're dealing with single stream content.
DownloadAction downloadAction =
downloadHelper.getDownloadAction(Util.getUtf8Bytes(name), selectedTrackKeys);
taskId=MyApplication.getInstance().getDownloadManager().handleAction(downloadAction);
startDownload(downloadAction);
}
}
}
}
In my Fragment/Activity:
/* this method will be called when user click on download button of each item */
#Override
public void onDownloadClick(LectureList lecture) {
Log.e(TAG,"onClickDownload");
downloadTracker.toggleDownload(this,lecture.getTitle_lecture(),
Uri.parse(lecture.getUrlPath()),lecture.getExtension());
}
And here is my broadcast receiver:
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e(TAG,"onRecive download");
if(intent.getAction().equals(MESSAGE_PROGRESS)){
int progress=intent.getLongExtra("progress",0);
}
}
};
In the getForegroundNotification() method, you will get list of TaskState objects, which has a members downloadPercentage and your download Uri taskState.action.uri which is unique for each download task. Store these variables into a map and broadcast the map.
override fun getForegroundNotification(taskStates: Array<TaskState>): Notification {
var totalPercentage = 0f
var downloadTaskCount = 0
var progressMap : HashMap<Uri, Int> = HashMap()
for (taskState in taskStates) {
if (taskState.state != TaskState.STATE_STARTED && taskState.state != TaskState.STATE_COMPLETED) {
continue
}
if (taskState.action.isRemoveAction) {
continue
}
if (taskState.downloadPercentage != C.PERCENTAGE_UNSET.toFloat()) {
totalPercentage += taskState.downloadPercentage
progressMap.put(taskState.action.uri, taskState.downloadPercentage.toInt())
}
downloadTaskCount++
}
var progress = 0
progress = (totalPercentage / downloadTaskCount).toInt()
broadcastIndividualProgress(progressMap)
return buildProgressNotification(progress)
}

waitingInMainSignalCatcherLoop,Thread*=0x72c22ee000,peer=0x12d00280,"Signal Catcher"]: reacting to signal 3

Good day everyone, I would like to ask, hat is the cause of that ANR?. In my project I have service which is binded in a activity. Now when I exit in that activity the app is hang for a moment. My thought is that the service is still running though I unbind it in onStop() of the activity.
Here is my service class
public class SpeechService extends Service {
public interface Listener {
/**
* Called when a new piece of text was recognized by the Speech API.
*
* #param text The text.
* #param isFinal {#code true} when the API finished processing audio.
*/
void onSpeechRecognized(String text, boolean isFinal);
}
private static final String TAG = "SpeechService";
private static final String PREFS = "SpeechService";
private static final String PREF_ACCESS_TOKEN_VALUE = "access_token_value";
private static final String PREF_ACCESS_TOKEN_EXPIRATION_TIME = "access_token_expiration_time";
/** We reuse an access token if its expiration time is longer than this. */
private static final int ACCESS_TOKEN_EXPIRATION_TOLERANCE = 30 * 60 * 1000; // thirty minutes
/** We refresh the current access token before it expires. */
private static final int ACCESS_TOKEN_FETCH_MARGIN = 60 * 1000; // one minute
public static final List<String> SCOPE =
Collections.singletonList("https://www.googleapis.com/auth/cloud-platform");
private static final String HOSTNAME = "speech.googleapis.com";
private static final int PORT = 443;
private final SpeechBinder mBinder = new SpeechBinder();
private final ArrayList<Listener> mListeners = new ArrayList<>();
private volatile AccessTokenTask mAccessTokenTask;
private SpeechGrpc.SpeechStub mApi;
private static Handler mHandler;
private final StreamObserver<StreamingRecognizeResponse> mResponseObserver
= new StreamObserver<StreamingRecognizeResponse>() {
#Override
public void onNext(StreamingRecognizeResponse response) {
String text = null;
boolean isFinal = false;
if (response.getResultsCount() > 0) {
final StreamingRecognitionResult result = response.getResults(0);
isFinal = result.getIsFinal();
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, isFinal);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private final StreamObserver<RecognizeResponse> mFileResponseObserver
= new StreamObserver<RecognizeResponse>() {
#Override
public void onNext(RecognizeResponse response) {
String text = null;
if (response.getResultsCount() > 0) {
final SpeechRecognitionResult result = response.getResults(0);
if (result.getAlternativesCount() > 0) {
final SpeechRecognitionAlternative alternative = result.getAlternatives(0);
text = alternative.getTranscript();
}
}
if (text != null) {
for (Listener listener : mListeners) {
listener.onSpeechRecognized(text, true);
}
}
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "Error calling the API.", t);
}
#Override
public void onCompleted() {
Log.i(TAG, "API completed.");
}
};
private StreamObserver<StreamingRecognizeRequest> mRequestObserver;
public static SpeechService from(IBinder binder) {
return ((SpeechBinder) binder).getService();
}
#Override
public void onCreate() {
super.onCreate();
mHandler = new Handler();
fetchAccessToken();
}
#Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mFetchAccessTokenRunnable);
mHandler = null;
// Release the gRPC channel.
if (mApi != null) {
final ManagedChannel channel = (ManagedChannel) mApi.getChannel();
if (channel != null && !channel.isShutdown()) {
try {
channel.shutdown().awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Log.e(TAG, "Error shutting down the gRPC channel.", e);
}
}
mApi = null;
}
}
private void fetchAccessToken() {
if (mAccessTokenTask != null) {
return;
}
mAccessTokenTask = new AccessTokenTask();
mAccessTokenTask.execute();
}
private String getDefaultLanguageCode() {
final Locale locale = Locale.getDefault();
final StringBuilder language = new StringBuilder(locale.getLanguage());
final String country = locale.getCountry();
if (!TextUtils.isEmpty(country)) {
language.append("-");
language.append(country);
}
return language.toString();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void addListener(#NonNull Listener listener) {
mListeners.add(listener);
}
public void removeListener(#NonNull Listener listener) {
mListeners.remove(listener);
}
/**
* Starts recognizing speech audio.
*
* #param sampleRate The sample rate of the audio.
*/
public void startRecognizing(int sampleRate) {
if (mApi == null) {
Log.w(TAG, "API not ready. Ignoring the request.");
return;
}
// Configure the API
mRequestObserver = mApi.streamingRecognize(mResponseObserver);
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setStreamingConfig(StreamingRecognitionConfig.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setLanguageCode(getDefaultLanguageCode())
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setSampleRateHertz(sampleRate)
.build())
.setInterimResults(true)
.setSingleUtterance(true)
.build())
.build());
}
/**
* Recognizes the speech audio. This method should be called every time a chunk of byte buffer
* is ready.
*
* #param data The audio data.
* #param size The number of elements that are actually relevant in the {#code data}.
*/
public void recognize(byte[] data, int size) {
if (mRequestObserver == null) {
return;
}
// Call the streaming recognition API
mRequestObserver.onNext(StreamingRecognizeRequest.newBuilder()
.setAudioContent(ByteString.copyFrom(data, 0, size))
.build());
}
/**
* Finishes recognizing speech audio.
*/
public void finishRecognizing() {
if (mRequestObserver == null) {
return;
}
mRequestObserver.onCompleted();
mRequestObserver = null;
}
/**
* Recognize all data from the specified {#link InputStream}.
*
* #param stream The audio data.
*/
public void recognizeInputStream(InputStream stream) {
try {
mApi.recognize(
RecognizeRequest.newBuilder()
.setConfig(RecognitionConfig.newBuilder()
.setEncoding(RecognitionConfig.AudioEncoding.LINEAR16)
.setLanguageCode("en-US")
.setSampleRateHertz(16000)
.build())
.setAudio(RecognitionAudio.newBuilder()
.setContent(ByteString.readFrom(stream))
.build())
.build(),
mFileResponseObserver);
} catch (IOException e) {
Log.e(TAG, "Error loading the input", e);
}
}
private class SpeechBinder extends Binder {
SpeechService getService() {
return SpeechService.this;
}
}
private final Runnable mFetchAccessTokenRunnable = new Runnable() {
#Override
public void run() {
fetchAccessToken();
}
};
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
#Override
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs =
getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
// Check if the current token is still valid for a while
if (tokenValue != null && expirationTime > 0) {
if (expirationTime
> System.currentTimeMillis() + ACCESS_TOKEN_EXPIRATION_TOLERANCE) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
}
// ***** WARNING *****
// In this sample, we load the credential from a JSON file stored in a raw resource
// folder of this client app. You should never do this in your app. Instead, store
// the file in your server and obtain an access token from there.
// *******************
final InputStream stream = getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
prefs.edit()
.putString(PREF_ACCESS_TOKEN_VALUE, token.getTokenValue())
.putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME,
token.getExpirationTime().getTime())
.apply();
return token;
} catch (IOException e) {
Log.e(TAG, "Failed to obtain access token.", e);
}
return null;
}
#Override
protected void onPostExecute(AccessToken accessToken) {
mAccessTokenTask = null;
final ManagedChannel channel = new OkHttpChannelProvider()
.builderForAddress(HOSTNAME, PORT)
.nameResolverFactory(new DnsNameResolverProvider())
.intercept(new GoogleCredentialsInterceptor(new GoogleCredentials(accessToken)
.createScoped(SCOPE)))
.build();
mApi = SpeechGrpc.newStub(channel);
// Schedule access token refresh before it expires
if (mHandler != null) {
mHandler.postDelayed(mFetchAccessTokenRunnable,
Math.max(accessToken.getExpirationTime().getTime()
- System.currentTimeMillis()
- ACCESS_TOKEN_FETCH_MARGIN, ACCESS_TOKEN_EXPIRATION_TOLERANCE));
}
}
}
/**
* Authenticates the gRPC channel using the specified {#link GoogleCredentials}.
*/
private static class GoogleCredentialsInterceptor implements ClientInterceptor {
private final Credentials mCredentials;
private Metadata mCached;
private Map<String, List<String>> mLastMetadata;
GoogleCredentialsInterceptor(Credentials credentials) {
mCredentials = credentials;
}
#Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
final MethodDescriptor<ReqT, RespT> method, CallOptions callOptions,
final Channel next) {
return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
#Override
protected void checkedStart(Listener<RespT> responseListener, Metadata headers)
throws StatusException {
Metadata cachedSaved;
URI uri = serviceUri(next, method);
synchronized (this) {
Map<String, List<String>> latestMetadata = getRequestMetadata(uri);
if (mLastMetadata == null || mLastMetadata != latestMetadata) {
mLastMetadata = latestMetadata;
mCached = toHeaders(mLastMetadata);
}
cachedSaved = mCached;
}
headers.merge(cachedSaved);
delegate().start(responseListener, headers);
}
};
}
/**
* Generate a JWT-specific service URI. The URI is simply an identifier with enough
* information for a service to know that the JWT was intended for it. The URI will
* commonly be verified with a simple string equality check.
*/
private URI serviceUri(Channel channel, MethodDescriptor<?, ?> method)
throws StatusException {
String authority = channel.authority();
if (authority == null) {
throw Status.UNAUTHENTICATED
.withDescription("Channel has no authority")
.asException();
}
// Always use HTTPS, by definition.
final String scheme = "https";
final int defaultPort = 443;
String path = "/" + MethodDescriptor.extractFullServiceName(method.getFullMethodName());
URI uri;
try {
uri = new URI(scheme, authority, path, null, null);
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI for auth")
.withCause(e).asException();
}
// The default port must not be present. Alternative ports should be present.
if (uri.getPort() == defaultPort) {
uri = removePort(uri);
}
return uri;
}
private URI removePort(URI uri) throws StatusException {
try {
return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), -1 /* port */,
uri.getPath(), uri.getQuery(), uri.getFragment());
} catch (URISyntaxException e) {
throw Status.UNAUTHENTICATED
.withDescription("Unable to construct service URI after removing port")
.withCause(e).asException();
}
}
private Map<String, List<String>> getRequestMetadata(URI uri) throws StatusException {
try {
return mCredentials.getRequestMetadata(uri);
} catch (IOException e) {
throw Status.UNAUTHENTICATED.withCause(e).asException();
}
}
private static Metadata toHeaders(Map<String, List<String>> metadata) {
Metadata headers = new Metadata();
if (metadata != null) {
for (String key : metadata.keySet()) {
Metadata.Key<String> headerKey = Metadata.Key.of(
key, Metadata.ASCII_STRING_MARSHALLER);
for (String value : metadata.get(key)) {
headers.put(headerKey, value);
}
}
}
return headers;
}
}
}
and here is my activity class
public class MainActivity extends AppCompatActivity implements MessageDialogFragment.Listener {
private static final String FRAGMENT_MESSAGE_DIALOG = "message_dialog";
private static final String STATE_RESULTS = "results";
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 1;
private SpeechService mSpeechService;
private VoiceRecorder mVoiceRecorder;
private final VoiceRecorder.Callback mVoiceCallback = new VoiceRecorder.Callback() {
#Override
public void onVoiceStart() {
showStatus(true);
if (mSpeechService != null) {
mSpeechService.startRecognizing(mVoiceRecorder.getSampleRate());
}
}
#Override
public void onVoice(byte[] data, int size) {
if (mSpeechService != null) {
mSpeechService.recognize(data, size);
}
}
#Override
public void onVoiceEnd() {
showStatus(false);
if (mSpeechService != null) {
mSpeechService.finishRecognizing();
}
}
};
// Resource caches
private int mColorHearing;
private int mColorNotHearing;
// View references
private TextView mStatus;
private TextView mText, mResult;
private Button editButton, clearButton;
private SharedPreferences settings;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
mSpeechService = SpeechService.from(binder);
mSpeechService.addListener(mSpeechServiceListener);
mStatus.setVisibility(View.VISIBLE);
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mSpeechService = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
final Resources resources = getResources();
final Resources.Theme theme = getTheme();
mColorHearing = ResourcesCompat.getColor(resources, R.color.status_hearing, theme);
mColorNotHearing = ResourcesCompat.getColor(resources, R.color.status_not_hearing, theme);
mStatus = (TextView) findViewById(R.id.status);
mText = (TextView) findViewById(R.id.text);
mResult = (TextView) findViewById(R.id.resultText);
editButton = (Button)findViewById(R.id.button1);
clearButton = (Button)findViewById(R.id.button2);
settings = getSharedPreferences("MyPreference", Context.MODE_PRIVATE);
clearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
mResult.setText("");
}
});
editButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Sounds sounds = new Sounds(getApplicationContext());
if(settings.getBoolean("muteAble", false ) == true){
sounds.playSound();
}
Intent editIntent = new Intent(MainActivity.this, EditorActivity.class);
String forEditText = mResult.getText().toString();
editIntent.putExtra("forEdit", forEditText);
startActivity(editIntent);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
this.finish();
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onStart() {
super.onStart();
// Prepare Cloud Speech API
bindService(new Intent(this, SpeechService.class), mServiceConnection, BIND_AUTO_CREATE);
// Start listening to voices
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
showPermissionMessageDialog();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
}
#Override
protected void onStop() {
// Stop listening to voice
stopVoiceRecorder();
// Stop Cloud Speech API
mSpeechService.removeListener(mSpeechServiceListener);
unbindService(mServiceConnection);
mSpeechService = null;
super.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
if (permissions.length == 1 && grantResults.length == 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startVoiceRecorder();
} else {
showPermissionMessageDialog();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void startVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
}
mVoiceRecorder = new VoiceRecorder(mVoiceCallback);
mVoiceRecorder.start();
}
private void stopVoiceRecorder() {
if (mVoiceRecorder != null) {
mVoiceRecorder.stop();
mVoiceRecorder = null;
}
}
private void showPermissionMessageDialog() {
MessageDialogFragment
.newInstance(getString(R.string.permission_message))
.show(getSupportFragmentManager(), FRAGMENT_MESSAGE_DIALOG);
}
private void showStatus(final boolean hearingVoice) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mStatus.setTextColor(hearingVoice ? mColorHearing : mColorNotHearing);
}
});
}
#Override
public void onMessageDialogDismissed() {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO},
REQUEST_RECORD_AUDIO_PERMISSION);
}
private final SpeechService.Listener mSpeechServiceListener =
new SpeechService.Listener() {
#Override
public void onSpeechRecognized(final String text, final boolean isFinal) {
if (isFinal) {
mVoiceRecorder.dismiss();
}
if (mText != null && !TextUtils.isEmpty(text)) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (isFinal) {
mText.setText(null);
mResult.append(" "+text.toString());
} else {
mText.setText(text);
}
}
});
}
}
};
}
Thank in advance for your help

Android ANR Multithreading

So I'm working on a project which needs to cut up a video into multiple frames, and save them as Bitmaps on the device.
I'm using FFmpegMediaMetadataRetriever.getFrameAtTime() to obtain the individual frames, which is working, but is slow. To speed it up a bit I'm trying to implement multiple worker threads which go off and grab the frames, finally responding back to UI via an anonymous function.
I have a class MyVideoProcessor which handles the video processing, and this is called from my EditVideoActivity.
The threads start, and start processing, but shortly afterwards the EditVideoActivity dies (ANR).
From what I can see, there is nothing running on UI (apart from at the very end (which I confirm only runs once)) so not sure why the UI thread is being held up by the worker threads.
EDIT:
So I've switched out FFmpegMediaMetadataRetriever for the standard MediaMetadataRetriever and everything works. BUT I need to use FFmpegMediaMetadataRetriever, as the OPTION_CLOSEST in MMR doesn't work as it should.
EditVideoActivity:
if (mBackgroundThread==null || !mBackgroundThread.isAlive()) {
mBackgroundThread = new Thread(mMyVideoProcessor);
mBackgroundThread.start();
}
MyVideoProcessor:
public class MyVideoProcessor implements Runnable {
private static final String TAG = MyVideoProcessor.class.getSimpleName();
private MyVideo mMyVideo;
private final Context mContext;
public static final int FRAME_CUT_DURATION = 200;
private int mStartFrom = 0;
private int mCurrentDuration = 0;
private int mVideoDuration = 0;
private ArrayList<OnFrameUpdateListener> listeners = new ArrayList<>();
private ExecutorService mProcessors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
public MyVideoProcessor(Context context, MyVideo myVideo) {
mContext = context;
mMyVideo = myVideo;
}
public void setOnFrameUpdateListener(OnFrameUpdateListener listener) {
listeners.add(listener);
}
public int getCurrentDuration() {
return mCurrentDuration;
}
public void setStartFrom(int startFrom) {
mStartFrom = startFrom;
}
#Override
public void run() {
if (!mMyVideo.getProcessed()) {
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
retriever.setDataSource(mContext.getExternalFilesDir(null) + File.separator + mMyVideo.getVideo());
String time = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
retriever.release();
mVideoDuration = Integer.parseInt(time);
int i = 0;
if (mStartFrom > 0) {
Log.d(TAG,"Attempting restore");
i = mStartFrom+1;
}
for ( i=i;i<mVideoDuration;i+=FRAME_CUT_DURATION) {
mProcessors.execute(new ExtractImageExecutor(i));
}
}
}
public class ExtractImageExecutor implements Runnable {
private int mTime;
public ExtractImageExecutor(int time) {
mTime = time;
}
#Override
public void run() {
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
retriever.setDataSource(mContext.getExternalFilesDir(null) + File.separator + mMyVideo.getVideo());
mCurrentDuration = mTime;
long startTime = System.currentTimeMillis();
Bitmap bitmap = retriever.getFrameAtTime(mTime*1000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
long endTime = System.currentTimeMillis();
Log.d(TAG, "Took: " + ((endTime - startTime) / 1000f));
if (bitmap != null) {
try {
int thisFrame = 0;
if (mTime>0) {
thisFrame = mTime/FRAME_CUT_DURATION;
}
//noinspection StringBufferReplaceableByString
StringBuilder frameFilename = new StringBuilder();
frameFilename.append("VIDEO_");
frameFilename.append(thisFrame).append("_");
frameFilename.append(new SimpleDateFormat("yyyyMMddHHmm", Locale.UK).format(new Date()));
frameFilename.append(".jpg");
File frameFile = new File(mContext.getExternalFilesDir(null), frameFilename.toString());
FileOutputStream fos = new FileOutputStream(frameFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
mMyVideo.addFrame(thisFrame, frameFile);
/*for (OnFrameUpdateListener listener : listeners) {
listener.onFrameUpdate(mMyVideo);
}*/
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
retriever.release();
if ((mTime+FRAME_CUT_DURATION) > mVideoDuration) {
mMyVideo.setProcessed(true);
for (OnFrameUpdateListener listener : listeners) {
listener.onFrameUpdate(mMyVideo);
}
}
}
}
}
EditVideoActivity:
public class EditVideoActivity extends Activity {
private static final String TAG = EditVideoActivity.class.getSimpleName();
private ImageView mImageView;
private MyVideo mMyVideo;
private MyVideoProcessor mMyVideoProcessor;
private Thread mBackgroundThread;
private int mCurrentDuration = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_edit_video);
String videoFilename = getIntent().getStringExtra("videoFilename");
if (videoFilename != null) {
mMyVideo = new MyVideo(MyVideo.TYPE_EXTERIOR,"TEST",new File(videoFilename));
mMyVideoProcessor = new MyVideoProcessor(this,mMyVideo);
} else {
Log.d(TAG, "There was a problem with the video file");
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
Log.d(TAG,"Saving Instance State");
outState.putParcelable("video", mMyVideo);
outState.putInt("currentDuration", mMyVideoProcessor.getCurrentDuration());
super.onSaveInstanceState(outState);
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
Log.d(TAG,"Restoring Instance State");
super.onRestoreInstanceState(savedInstanceState);
mMyVideo = (MyVideo) savedInstanceState.getParcelable("video");
mCurrentDuration = savedInstanceState.getInt("currentDuration");
}
#Override
protected void onResume() {
super.onResume();
mMyVideoProcessor = new MyVideoProcessor(this,mMyVideo);
final TextView totalFrames = (TextView) findViewById(R.id.totalFrames);
mImageView = (ImageView) findViewById(R.id.imageView2);
final SeekBar seekBar = (SeekBar) findViewById(R.id.seekBar);
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.animate();
seekBar.setEnabled(false);
OnFrameUpdateListener onFrameUpdateListener = new OnFrameUpdateListener() {
#Override
public void onFrameUpdate(final MyVideo myVideo) {
if (myVideo.getProcessed()) {
File lastFrame = myVideo.getLastFrame();
totalFrames.setText(myVideo.getTotalFrames()+"");
mImageView.setImageBitmap(BitmapFactory.decodeFile(lastFrame.getAbsolutePath()));
seekBar.setEnabled(true);
progressBar.setVisibility(View.GONE);
}
}
};
mMyVideoProcessor.setOnFrameUpdateListener(onFrameUpdateListener);
if (mBackgroundThread==null || !mBackgroundThread.isAlive()) {
mBackgroundThread = new Thread(mMyVideoProcessor);
mBackgroundThread.start();
}
}
}

How can resolve: The content of the adapter has changed but ListView did not receive a notification

I have this exception on my APP... I don't know why happen it.
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(2131492879), class android.widget.ListView with Adapter class com.agencialanave.AdaptadorListaApps
I have tried many options but I have not managed to fix it.
Class: Apps.java
public class Apps
{
public Bitmap Colorbanda;
public Bitmap Logo;
public Bitmap LogoBasura;
public String NombreAPP;
public float MemoriaUsada;
public String NombrePaquete;
public File Apk;
public Apps(Bitmap colorbanda, Bitmap logo,String nombreAPP, float memoriaUsada, Bitmap logoBasura, String nombrePaquete, File apk)
{
super();
Colorbanda = colorbanda;
Logo = logo;
LogoBasura = logoBasura;
NombreAPP = nombreAPP;
MemoriaUsada = memoriaUsada;
NombrePaquete = nombrePaquete;
Apk = apk;
}
public Apps(Bitmap colorbanda, Bitmap logo,String nombreAPP, float memoriaUsada, Bitmap logoBasura, String nombrePaquete)
{
super();
Colorbanda = colorbanda;
Logo = logo;
LogoBasura = logoBasura;
NombreAPP = nombreAPP;
MemoriaUsada = memoriaUsada;
NombrePaquete = nombrePaquete;
}
public Bitmap getColorbanda() {
return Colorbanda;
}
public void setColorbanda(Bitmap colorbanda) {
Colorbanda = colorbanda;
}
public Bitmap getLogo() {
return Logo;
}
public void setLogo(Bitmap logo) {
Logo = logo;
}
public Bitmap getLogoBasura() {
return LogoBasura;
}
public void setLogoBasura(Bitmap logoBasura) {
LogoBasura = logoBasura;
}
public String getNombreAPP() {
return NombreAPP;
}
public void setNombreAPP(String nombreAPP) {
NombreAPP = nombreAPP;
}
public float getMemoriaUsada() {
return MemoriaUsada;
}
public void setMemoriaUsada(float memoriaUsada) {
MemoriaUsada = memoriaUsada;
}
public String getNombrePaquete() {
return NombrePaquete;
}
public void setNombrePaquete(String nombrePaquete) {
NombrePaquete = nombrePaquete;
}
public File getApk() {
return Apk;
}
public void setApk(File apk) {
Apk = apk;
}
}
Class: AdaptadorListaApps.java
public class AdaptadorListaApps extends ArrayAdapter<Apps>
{
private static Activity Context;
ArrayList<Apps> listaApps;
public AdaptadorListaApps(Activity context, ArrayList<Apps> lista)
{
super(context, R.layout.layout_list, lista);
Context = context;
listaApps = lista;
}
class ViewHolder
{
ImageView fotoBandaColor,fotoLogoApp,fotoDelete;
TextView nombreApp, memoriaUsada;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View item =convertView;
ViewHolder holder;
if (item == null)
{
LayoutInflater inflater = Context.getLayoutInflater();
item = inflater.inflate(R.layout.layout_list, null);
holder = new ViewHolder();
holder.fotoBandaColor = (ImageView)item.findViewById(R.id.bandaColor);
holder.fotoLogoApp = (ImageView)item.findViewById(R.id.logoApp);
holder.fotoDelete = (ImageView)item.findViewById(R.id.borrarApp);
holder.nombreApp = (TextView)item.findViewById(R.id.nombreApp);
holder.memoriaUsada = (TextView)item.findViewById(R.id.memoriaUsada);
item.setTag(holder);
}
else
{
holder=(ViewHolder) item.getTag();
}
holder.fotoBandaColor.setImageBitmap(listaApps.get(position).getColorbanda());
holder.fotoLogoApp.setImageBitmap(listaApps.get(position).getLogo());
holder.fotoDelete.setImageBitmap(listaApps.get(position).getLogoBasura());
holder.memoriaUsada.setText(TamaƱoAppEnRam(listaApps.get(position).getMemoriaUsada()) + " MB ( " + PorcentageMemoria(listaApps.get(position).getMemoriaUsada())+"% )");
if(listaApps.get(position).getMemoriaUsada() < 4)
{
holder.memoriaUsada.setTextColor(Color.parseColor("#56E000"));
}
else if(listaApps.get(position).getMemoriaUsada() > 7)
{
holder.memoriaUsada.setTextColor(Color.RED);
}
else
{
holder.memoriaUsada.setTextColor(Color.parseColor("#FF8000"));
}
holder.nombreApp.setText(listaApps.get(position).getNombreAPP());
return item;
}
}
Code where update listview
private class GetRunningApps extends AsyncTask<String, ArrayList<Apps>, String>
{
#Override
protected String doInBackground(String... params) throws IllegalStateException
{
listaapps.clear();
listaapps = new ArrayList<Apps>();
cont = 0;
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningTasks = activityManager.getRunningAppProcesses();
PackageManager pm = context.getPackageManager();
Drawable icon;
Bitmap logo;
float memoria = 0;
String nombrePaquete;
MB = 0;
int pids[] = new int[1];
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
for (RunningAppProcessInfo appInfo : runningTasks)
{
try
{
if(appInfo.importance == RunningAppProcessInfo.IMPORTANCE_SERVICE || appInfo.importance == RunningAppProcessInfo.IMPORTANCE_BACKGROUND)
{
icon = pm.getApplicationIcon(appInfo.processName);
logo = ((BitmapDrawable) icon).getBitmap();
CharSequence c = pm.getApplicationLabel
(
pm.getApplicationInfo(appInfo.processName,PackageManager.GET_META_DATA)
);
pids[0] = appInfo.pid;
nombrePaquete = appInfo.processName;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
memoria = (float)pidMemoryInfo.getTotalPss()/1024;
if(pidMemoryInfo.getTotalPss()/1024 <= 3)
{
listaapps.add(new Apps(bandaVerde, logo , c.toString() , memoria ,logoDelete, nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
else if((pidMemoryInfo.getTotalPss()/1024 >= 7))
{
listaapps.add(new Apps(bandaRoja, logo , c.toString() , memoria ,logoDelete,nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
else if((pidMemoryInfo.getTotalPss()/1024 > 3 && pidMemoryInfo.getTotalPss()/1024 < 7))
{
listaapps.add(new Apps(bandaNaranja, logo , c.toString() , memoria ,logoDelete,nombrePaquete, new File(getActivity().getPackageManager().getApplicationInfo(nombrePaquete, PackageManager.GET_META_DATA).publicSourceDir)));
}
}
cont++;
MB += memoria;
if(cont % 2 == 0)
{
try
{
publishProgress();
}
catch(IllegalStateException e){}
}
}
}
catch (Exception e) {}
}
cont = 0;
return null;
}
#Override
protected void onProgressUpdate(ArrayList<Apps>... values)
{
try
{
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
listaAplicaciones.setAdapter(adaptadorLista);
adaptadorLista.notifyDataSetChanged();
}
catch(IllegalStateException e){}
}
#Override
protected void onPostExecute(String result)
{
adaptadorLista = new AdaptadorListaApps(activity,listaapps);
adaptadorLista.sort(new OrderList());
listaAplicaciones.setAdapter(adaptadorLista);
}
}
Please, help me... Thanks
You should never change the properties of a view or any of its underlying datasource on a background thread.
Do not manipulate the variable listaaps in your onBackground. Only change it in your onPostExecute or onProgressUpdate.
Do not manipulate the variable adaptorLista in your onBackground. Only change it in your onPostExecute or onProgressUpdate.

Background Service Hangs UI upto the time web service finish its execution?

I have created a webservice class lokks like below, in with in the "onCreate" method of the service i Have called my webservice which takes around 45 seconds to complete its execution for that time my UI gets black that means it Hangs upto the execution of the web service,
below is the code of my service,
public class productService extends Service
{
private static Context _pctx;
static Vector _productsAll = null;
public static void getInstance(Context context) throws Exception
{
if (_pctx == null)
{
_pctx = context;
}
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate()
{
try
{
LoadAllProducts();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
return START_REDELIVER_INTENT; // 21 sec
}
#Override
public void onDestroy()
{
_productsAll= null;
}
private void LoadAllProducts() throws Exception
{
_productsAll = new Vector();
Exception e = null;
WebResponse myResponse = DataService.GetData("$PR$" , _pctx);
if (Helper.getBoolValueFromString(myResponse.Success))
{
saveMDBData(myResponse.Response);
}
else
{
e = new Exception(myResponse.Response.toString());
}
//cats = null;
if (e != null) {
throw e;
}
}
public static void saveMDBData(StringBuffer pMDBData)
{
Vector Rows;
Vector Cols;
int iRow = 0;
if (pMDBData != null)
{
if (!pMDBData.toString().trim().equals(""))
{
Rows = Helper.getRowsNew(pMDBData);
if (Rows != null)
{
for (iRow = 0; iRow < Rows.size(); iRow++)
{
if (!((String) Rows.elementAt(iRow)).trim().equals(""))
{
Cols = Helper.SplitMultiCharDelimiters((String) Rows.elementAt(iRow), Helper.FIELDDELIMITERS);
assignMDBData(Cols);
}
}
}
}
}
Rows = null;
Cols=null;
}
private static void assignMDBData(Vector pCols)
{
Product myProduct = null;
if (pCols != null)
{
//Create new setting instance
//myProduct = new Product();
myProduct = new Product();
//assign values
myProduct.Id = Helper.getIntValue((String)pCols.elementAt(0));
myProduct.PartNumber = (String)pCols.elementAt(1);
myProduct.Description = (String)pCols.elementAt(2);
myProduct.IdCategory = Helper.getIntValue((String)pCols.elementAt(3));
myProduct.Ideal = Helper.getIntValue((String)pCols.elementAt(4));
myProduct.Taxable = Helper.getBoolValueFromString((String)pCols.elementAt(5));
myProduct.Discountable = Helper.getBoolValueFromString((String)pCols.elementAt(6));
myProduct.LotSize = Helper.getIntValue((String)pCols.elementAt(7));
myProduct.RetailPrice = Helper.getDoubleValue((String)pCols.elementAt(8));
myProduct.ListPrice = Helper.getDoubleValue((String)pCols.elementAt(9));
myProduct.TotalOnHand = Helper.getIntValue((String)pCols.elementAt(10));
myProduct.TotalOnOrder = Helper.getIntValue((String)pCols.elementAt(11));
myProduct.IsPrepack = Helper.getBoolValueFromString((String)pCols.elementAt(12));
//myProduct.Breakdown = (String)pCols.elementAt(13);
myProduct.NoInventory = Helper.getBoolValueFromString((String)pCols.elementAt(13));
myProduct.IsCollection = Helper.getBoolValueFromString((String)pCols.elementAt(14));
myProduct.Followup = Helper.getIntValue((String)pCols.elementAt(15));
myProduct.PctDiscount = Helper.getDoubleValue((String)pCols.elementAt(16));
myProduct.IdGroup = Helper.getIntValue((String)pCols.elementAt(17));
myProduct.Points = Helper.getIntValue((String)pCols.elementAt(18));
myProduct.IsVitamin = Helper.getBoolValueFromString((String)pCols.elementAt(19));
myProduct.PusChange = Helper.getIntValue((String)pCols.elementAt(20));
myProduct.MovedToCloseout = Helper.getDateDataSync((String)pCols.elementAt(21));
myProduct.OnHandDelta = Helper.getIntValue((String)pCols.elementAt(24));
//save processed setting to persistent collection
_productsAll.addElement(myProduct);
//release saved setting in)stance
myProduct = null;
}
}
}
Anyone please help me to sort out the probelm,
I am Stuck Here,
Thanks in Advance!
For Background Services use the AsyncTask which creates background threads so doesn't effect your main UI.
Here is the Code:
public class DownloadData extends AsyncTask<String, String, String> {
#Override
public void onPreExecute() {
// Do Some Task before background thread runs
}
#Override
protected String doInBackground(String... arg0) {
// To Background Task Here
return null;
}
#Override
protected void onProgressUpdate(String... progress) {
// publish progress here
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Do some Task after Execution
}
}
For more details: See this one
http://developer.android.com/reference/android/os/AsyncTask.html

Categories

Resources