0

I am trying to create my own android widget. I want it to contain a listview that gets data from an async task from an online database.

So far I have my res/xml.stat_widget.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="220dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/widget_stat_view">
</appwidget-provider>

and the layout widget_stat_view:

<?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:orientation="vertical" >


    <TextView
        android:id="@+id/statisticsTitle"
        android:gravity="center"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="Your Statistics"
        android:textSize="20sp"
        android:textStyle = "bold"
        android:padding="5dip"
        >
    </TextView>

    <View
        android:layout_width="1dp"
        android:layout_height="30dp">
    </View>

    <ListView
        android:id="@+id/yourStats"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:dividerHeight="0px"
        android:divider="@null"

        >
    </ListView>



</LinearLayout>

I am trying to code the widget provider now which calls the async task. I modeled my async task after the async tasks I use in my normal app activities. It is not set up yet to change data in the widget but I am having problems calling it from my provider:

package com.example.beerportfoliopro;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.RemoteViews;

import com.beerportfolio.beerportfoliopro.R;

/**
 * Created by Mike on 9/12/13.
 */
public class StatWidgetProvider extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                         int[] appWidgetIds) {

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
        String userName = prefs.getString("userName", null);
        String userID = prefs.getString("userID", null);
        String url = "myURL";



        new GetJSONStatWidget(this).execute(url);



    }
    public static void updateWidgetContent(Context context,
                                           AppWidgetManager appWidgetManager) {

        RemoteViews remoteView = new RemoteViews(context.getPackageName(),
                R.layout.widget_stat_view);
        remoteView.setTextViewText(R.id.title, strLatestTitle);
        Intent launchAppIntent = new Intent(context, TutListActivity.class);
        PendingIntent launchAppPendingIntent = PendingIntent.getActivity(context,
                0, launchAppIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        remoteView.setOnClickPendingIntent(R.id.full_widget, launchAppPendingIntent);
        ComponentName tutListWidget = new ComponentName(context,
                TutWidgetProvider.class);
        appWidgetManager.updateAppWidget(tutListWidget, remoteView);
    }
}

My first error I get on this line in the above code:

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);

The error is:

getDefaultSharedPreferences
                (android.content.Context)
        in PreferenceManager cannot be applied
                to
        (com.example.beerportfoliopro.StatWidgetProvider)

I also get an error with this on this line:

new GetJSONStatWidget(this).execute(url);
     

My async task code is this:

package com.example.beerportfoliopro;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.Inflater;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.RatingBar.OnRatingBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import com.beerportfolio.beerportfoliopro.R;

public class GetJSONStatWidget extends AsyncTask
        <String, Void, String> {

    Context c;
    String b;

    public GetJSONStatWidget(Context context)
    {
        c = context;
    }

    @Override
    protected String doInBackground(String... arg0) {
        // TODO Auto-generated method stub
        return readJSONFeed(arg0[0]);
    }

    protected void onPostExecute(String result){

        //decode json here
        try{

            JSONObject json = new JSONObject(result);

            String beerCount = json.getString("beerCount");
            String breweryCount = json.getString("breweryCount");
            String styleCount = json.getString("styleCount");
            String highABV = json.getString("highABV");
            String highIBU = json.getString("highIBU");


            //todo: everything below is for the listview

            //make array list for stats
            final List<BasicStat> basicStatList = new ArrayList<BasicStat>();

            //create object
            BasicStat stat1 = new BasicStat("Beer Count: ", beerCount);
            basicStatList.add(stat1);

            BasicStat stat2 = new BasicStat("Brewery Count: ", breweryCount);
            basicStatList.add(stat2);

            BasicStat stat3 = new BasicStat("Style Count: ", styleCount);
            basicStatList.add(stat3);

            BasicStat stat4 = new BasicStat("High ABV: ", highABV);
            basicStatList.add(stat4);

            BasicStat stat5 = new BasicStat("High IBU: ", highIBU);
            basicStatList.add(stat5);

            //acces listview
            ListView lv = (ListView) ((Activity) c).findViewById(R.id.yourStats);

            //add items to listview
            StatInfoAdapter adapter1 = new StatInfoAdapter(c ,R.layout.stat_list_item, basicStatList);
            lv.setAdapter(adapter1);




        }
        catch(Exception e){

        }

    }





    public String readJSONFeed(String URL) {
        StringBuilder stringBuilder = new StringBuilder();
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(URL);
        try {
            HttpResponse response = httpClient.execute(httpGet);
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                InputStream inputStream = entity.getContent();
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(inputStream));
                String line;
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                inputStream.close();
            } else {
                Log.d("JSON", "Failed to download file");
            }
        } catch (Exception e) {
            Log.d("readJSONFeed", e.getLocalizedMessage());
        }
        return stringBuilder.toString();
    }




}

1 Answer 1

1

For your first error, that's because AppWidgetProvider is NOT an Activity, therefore it is not a Context. If you look at the documentation, getDefaultSharedPreferences() requires a Context, but AppWidgetProvider is in fact a subclass of BroadcastReceiver.

You also should not execute AsyncTasks inside the AppWidgetProvider because of its being a BroadcastReceiver. Once the BroadcastReceiver has finished its tasks, the AsyncTask will fail to complete because the BroadcastReceiver component is lost. You should be using Services to do your "background" stuff. Have another line that looks like

PendingIntent notReallyBackground = PendingIntent.getService(...);

Source: CommonsWare's book "The Busy Coder's Guide to Android"

UPDATE: Sorry about that, PendingIntent is used for when you want something to happen later. In the line above, it means the AppWidgetHost will start the service once the RemoteViews you have bound it to is clicked for example.

You can start a new Service from the BroadcastReceiver immediately if you need to by calling startService(Intent).

You can see a great example for what you're trying to do here (look for UpdateService): http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html

And here's a good link for using ListViews on widgets (Using app widgets with collections): http://developer.android.com/guide/topics/appwidgets/index.html

I'm sure you've seen the latter already, but I just wanted to point out that it was introduced in Android 3.0, and that because RemoteViews are like Views with limited capabilities, you have to use a slightly different approach compared to using ListViews in an Activity. (setRemoteAdapter for example)

Sign up to request clarification or add additional context in comments.

1 Comment

So I was going about this the complete wrong way. I am not familiar with using the broadcast receiver and am not sure how to get and parse a json file from my server to display that info in the widget. I have been grabbing data from my server with async tasks, for my activities....

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.