Reputation: 1881
I'm playing around with ICS and Widgets and have stumbled across a problem I can't really seem to debug correctly.
The application has a main activity (WidgetActivity), a widget configure (WidgetConfigure) and a provider (WidgetProvider). The widget's layout (code below) has a parent LinearLayout and two child LinearLayouts. Both of those children are set to invisible. In my provider's onUpdate
I instantiate a RemoteViews object of that widget, and attempt to set the first LinearLayout to visible.
The widget displays, when placed on the home screen, but the two children don't (expected). When the onUpdate
is called, the child is not set to visible. What I do get, in adb, is a bunch of warnings from StrictMode about the widget not being able to write its state to disk. There's a policy violation for read and write. Since I'm not actually doing any read and writes anywhere, I assume this is an OS call.
My question - would this StrictMode be causing my views not to change visibility? I understand, on a rough, high level, that StrictMode allows me to identify where I have slow code in my UI Thread. But I don't just want to blindly override or ser new StrictMode settings without understanding what's going.
As the adb shows, my onReceive is getting called (and if you wait 180000ms, again), but my child view is not set to visible. And I'm not sure why.
Here's the code. Widget layout xml, provider, adb trace:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFF"
android:orientation="vertical" >
<include layout="@layout/widget_next_season" />
<include layout="@layout/widget_upcoming_game" />
</LinearLayout>
public class WidgetProvider extends AppWidgetProvider {
private static String TAG = "### WidgetProvider";
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
Log.d(TAG, "onUpdate");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Log.d(TAG, "Got Views");
views.setViewVisibility(R.id.layout_one, View.VISIBLE);
Log.d(TAG, "Should've set visibility");
}
}
D/### WidgetProvider( 522): onUpdate D/### WidgetProvider( 522): Got Views D/### WidgetProvider( 522): Should've set visibility I/ActivityManager( 84): Start proc com.android.quicksearchbox for broadcast com.android.quicksearchbox/.CorporaUpdateReceiver: pid=536 uid=10011 gids={3003} D/dalvikvm( 34): GC_EXPLICIT freed 37K, 4% free 9901K/10243K, paused 4ms+6ms D/dalvikvm( 84): GC_CONCURRENT freed 496K, 5% free 12726K/13383K, paused 11ms+43ms D/StrictMode( 84): StrictMode policy violation; ~duration=2436 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=151 violation=2 D/StrictMode( 84): at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1074) D/StrictMode( 84): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:94) D/StrictMode( 84): at libcore.io.IoBridge.open(IoBridge.java:390) D/StrictMode( 84): at java.io.FileOutputStream.(FileOutputStream.java:88) D/StrictMode( 84): at com.android.server.AppWidgetService.writeStateToFileLocked(AppWidgetService.java:1220) D/StrictMode( 84): at com.android.server.AppWidgetService.saveStateLocked(AppWidgetService.java:1204) D/StrictMode( 84): at com.android.server.AppWidgetService$2.onReceive(AppWidgetService.java:1503) D/StrictMode( 84): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:728) D/StrictMode( 84): at android.os.Handler.handleCallback(Handler.java:605) D/StrictMode( 84): at android.os.Handler.dispatchMessage(Handler.java:92) D/StrictMode( 84): at android.os.Looper.loop(Looper.java:137) D/StrictMode( 84): at com.android.server.ServerThread.run(SystemServer.java:744) D/StrictMode( 84): StrictMode policy violation; ~duration=2301 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=151 violation=1 D/StrictMode( 84): at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1048) D/StrictMode( 84): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:178) D/StrictMode( 84): at libcore.io.IoBridge.write(IoBridge.java:447) D/StrictMode( 84): at java.io.FileOutputStream.write(FileOutputStream.java:187) D/StrictMode( 84): at com.android.internal.util.FastXmlSerializer.flushBytes(FastXmlSerializer.java:212) D/StrictMode( 84): at com.android.internal.util.FastXmlSerializer.flush(FastXmlSerializer.java:233) D/StrictMode( 84): at com.android.internal.util.FastXmlSerializer.endDocument(FastXmlSerializer.java:183) D/StrictMode( 84): at com.android.server.AppWidgetService.writeStateToFileLocked(AppWidgetService.java:1266) D/StrictMode( 84): at com.android.server.AppWidgetService.saveStateLocked(AppWidgetService.java:1204) D/StrictMode( 84): at com.android.server.AppWidgetService$2.onReceive(AppWidgetService.java:1503) D/StrictMode( 84): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:728) D/StrictMode( 84): at android.os.Handler.handleCallback(Handler.java:605) D/StrictMode( 84): at android.os.Handler.dispatchMessage(Handler.java:92) D/StrictMode( 84): at android.os.Looper.loop(Looper.java:137) D/StrictMode( 84): at com.android.server.ServerThread.run(SystemServer.java:744)
Upvotes: 3
Views: 2542
Reputation: 1020
To add on to what jlindenbaum contributed, rather than managing the thread policy yourself, here's a nice helper class that will ensure you won't forget to reset your thread policy.
public class ThreadPolicyManager {
// ========== Singleton ==========
private static ThreadPolicyManager sInstance;
public static ThreadPolicyManager getInstance()
{
if(sInstance == null)
{
sInstance = new ThreadPolicyManager();
}
return sInstance;
}
private ThreadPolicyManager(){}
// ========== Class ==========
private StrictMode.ThreadPolicy mPreviousThreadPolicy;
/**
* Prevent exceptions from doing disk and network operations in a service
*/
private void setPermissiveThreadPolicy() {
mPreviousThreadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(mPreviousThreadPolicy).permitNetwork().permitDiskReads().permitDiskWrites().build());
}
/**
* Reset thread policy to previously known state for consistency
*/
private void resetThreadPolicy() {
if (mPreviousThreadPolicy != null) {
StrictMode.setThreadPolicy(mPreviousThreadPolicy);
}
}
/**
* This will temporarily set the thread policy to permissive,
* execute the unit of work, and then reset the thread policy
*/
public void executePermissiveUnit(PermissiveUnit unit)
{
setPermissiveThreadPolicy();
unit.executeUnitOfWork();
resetThreadPolicy();
}
// ========= PermissiveUnit ========
/**
* This is a functor to allow a unit of work to be executed
* permissively
*/
public static abstract class PermissiveUnit{
public abstract void executeUnitOfWork();
}
}
And to use it:
ThreadPolicyManager.getInstance().executePermissiveUnit(new ThreadPolicyManager.PermissiveUnit(){
@Override
public void executeUnitOfWork() {
//TODO whatever needs to be executed
}
});
Upvotes: 1
Reputation: 1881
The reason was, in fact, the StrictMode. I have worked around this problem by ensuring my network code is in a Service
, not in the onUpdate
of the widget. Despite that Android still complains about violating the StrictMode for network and disc access.
To work around this I modify the StrictMode policy, and reset it when I'm done. I simply call these functions around the network code.
/**
* Prevent exceptions from doing disk and network operations in a service
*/
protected static void setPermissiveThreadPolicy() {
// set StrictMode to allow network/disk in service
oldThreadPolicy = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(oldThreadPolicy).permitNetwork().permitDiskReads().permitDiskWrites().build());
}
/**
* Reset thread policy to previously known state for consistency
*/
protected static void resetThreadPolicy() {
if (oldThreadPolicy != null) {
// reset to old policy
StrictMode.setThreadPolicy(oldThreadPolicy);
}
}
Upvotes: 4