Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging Widget causes ANR

I'm trying to debug an AppWidget but I incurred in a problem :D If not setting the breakpoint the widget works without ANR and the commands Log.v are executed flawlessly. Then I placed a breakpoint on the top of the method:

    public void onReceive(Context context, Intent intent) {
    Log.v(TAG, "onReceive 1"); // BP on this line
    super.onReceive(context, intent);
    String action = intent.getAction();

    // Checks on action and computations ...

    Log.v(TAG, "onReceive 2");
    updateWidget(context);
    Log.v(TAG, "onReceive 3");
}

The breakpoint stops the execution as expected but then the process dies. The problem is that the breakpoint ( I guess xD ) cause an ANR and the ActivityManager kills the process. That's the Log:

01-07 14:32:38.886: ERROR/ActivityManager(72): ANR in com.salvo.wifiwidget
01-07 14:32:38.886: INFO/Process(72): Sending signal. PID: 475 SIG: 9
......
......
01-07 14:32:38.906: INFO/ActivityManager(72): Process com.salvo.wifiwidget (pid   475) has died.

This cause the debug to stop. So the question is: there's a way to debug the widget without incurring in the ANR?? thanks in advance for the answers

like image 252
Salv0 Avatar asked Nov 06 '22 04:11

Salv0


1 Answers

You're right. According to this your Widget's BroadcastReceiver will be killed by the system if it takes longer than 10 seconds to process its onReceive method.

From the top of my head I can see two solutions:

  1. Separate logic from presentation and debug your logic in Activity, then incorporate it into widget.
  2. Resort to "old good" logging.

OR you can try following thing. I am not sure how it will work, but maybe it is worth to give this approach a try.

Use your own activity as host for widget's RemoteViews. I've done something like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <LinearLayout
            android:id="@+id/widget_view"
            android:layout_width="fill_parent"
            android:layout_height="200dp"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Inflate widget"
        android:onClick="onInflateClick"/>
    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Update widget"
            android:onClick="onUpdateClick"/>
</LinearLayout>

In this layout LinearLayout with id = widget_view will play widget host. Activity code itself looks like this:

package com.example;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RemoteViews;

public class MyActivity extends Activity {
    private LinearLayout widgetHolder;
    private View widgetView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        widgetHolder = (LinearLayout) findViewById(R.id.widget_view);
    }

    public void onInflateClick(View v) {
        RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget);
        views.setImageViewResource(R.id.image, R.drawable.img1);
        views.setTextViewText(R.id.text, "Widget created");
        widgetView = views.apply(this, null);
        widgetHolder.addView(widgetView);
    }

    public void onUpdateClick(View v) {
        onUpdateWidget(0);
    }

    public void onUpdateWidget(int widgetId) {
        RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget);
        views.setImageViewResource(R.id.image, R.drawable.img2);
        views.setTextViewText(R.id.text, "Widget updated");

        // Tell the AppWidgetManager to perform an update on the current app widget
        updateWidget(widgetId, views);
    }

    private void updateWidget(int widgetId, RemoteViews views) {
        views.reapply(this, widgetView);
        // appWidgetManager.updateAppWidget(appWidgetId, views);
    }
}

Put your widget update logic into updateWidget method (or just call proper onUpdate method of the widget's BroadcastReceiver with fake parameters) and you can debug it with a click of a button on your activity.

Again, I never tried it on real widget, I just come up with idea and tried to write code for it. Use it on your own risk :)

I put my quick and dirty project to github in case you want to try it. It is and Idea project, but it should be easy to import it into Eclipse.

like image 102
uaraven Avatar answered Nov 09 '22 06:11

uaraven