Android Widget相同窗口小部件的多个实例发生冲突

时间:2018-10-26 16:43:43

标签: java android widget sharedpreferences android-widget

我遇到的问题是,当我创建同一窗口小部件的两个实例时,它们会发生冲突。

当我刷新时,所以当我打电话时

if (WIDGET_LIST_REFRESH.equals (intent.getAction ())) {

仅更新最后一个小部件。

我认为的问题还在于,WidgetConfigureActivity.loadTitlePref在创建窗口小部件的第二个实例时会更改第一个窗口小部件中的值。

ListWidgetProvider:

    import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.util.Log;
    import android.widget.RemoteViews;
    import android.widget.Toast;

    import com.widgettwitter.AppIntent;
    import com.widgettwitter.R;

    /**
     * Implementation of App Widget functionality.
     * App Widget Configuration implemented in {@link WidgetConfigureActivity WidgetConfigureActivity}
     */
    public class ListWidgetProvider extends AppWidgetProvider {
        public static final int OPEN_CLICK_TYPE = 1;
        private static final String TAG = ListWidgetProvider.class.getName();
        private static final String WIDGET_APP_CONFIG = "com.widgettwitter.WIDGET_CONFIG";

        public static String WIDGET_TWITTER_NEW = "com.widgettwitter.WIDGET_NEW";
        public static String WIDGET_LIST_REFRESH = "com.widgettwitter.WIDGET_REFRESH";
        private static String WIDGET_LIST_CLEAR = "com.widgettwitter.WIDGET_CLEAR";
        static Context contextApp;
        static int appWidgetIdApp;

        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
            Log.v("Class:" + TAG, "onUpdate:" + appWidgetIds.length);
            for (int appWidgetId : appWidgetIds)
                updateAppWidget(context, appWidgetManager, appWidgetId);
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }

        static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
            contextApp = context;
            appWidgetIdApp = appWidgetId;

            CharSequence widgetText = WidgetConfigureActivity.loadTitlePref(context, appWidgetId);
            Log.v("Class:" + TAG, "updateAppWidget:" + String.valueOf(widgetText));

            RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget);
            remoteView.setTextViewText(R.id.hashtag, widgetText);

            Intent intent = new Intent(context, ListWidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));//problem
            remoteView.setRemoteAdapter(R.id.widgetListViewTweets, intent);
            remoteView.setEmptyView(R.id.widgetListViewTweets, R.id.empty_view_tweets);

            final Intent newIntent = new Intent(context, ListWidgetProvider.class);
            newIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            newIntent.setAction(ListWidgetProvider.WIDGET_TWITTER_NEW);
            PendingIntent newPendingIntent = PendingIntent.getBroadcast(context, appWidgetId, newIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.add, newPendingIntent);

            final Intent configIntent = new Intent(context, ListWidgetProvider.class);
            configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            configIntent.setAction(ListWidgetProvider.WIDGET_APP_CONFIG);
            PendingIntent configPendingIntent = PendingIntent.getBroadcast(context, appWidgetId, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.hashtag, configPendingIntent);

            final Intent refreshIntent = new Intent(context, ListWidgetProvider.class);
            refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            refreshIntent.setAction(ListWidgetProvider.WIDGET_LIST_REFRESH);
            PendingIntent refreshPendingIntent = PendingIntent.getBroadcast(context, appWidgetId, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.refresh, refreshPendingIntent);

            final Intent clearIntent = new Intent(context, ListWidgetProvider.class);
            clearIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            clearIntent.setAction(ListWidgetProvider.WIDGET_LIST_CLEAR);
            PendingIntent clearPendingIntent = PendingIntent.getBroadcast(context, appWidgetId, clearIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setOnClickPendingIntent(R.id.clear, clearPendingIntent);

            final Intent onClickIntent = new Intent(context, ListWidgetProvider.class);
            onClickIntent.setAction(AppIntent.ACTION_CLICK_LIST_WIDGET);
            onClickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            onClickIntent.setData(Uri.parse(onClickIntent.toUri(Intent.URI_INTENT_SCHEME)));
            final PendingIntent onClickPendingIntent = PendingIntent.getBroadcast(context, appWidgetId, onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            remoteView.setPendingIntentTemplate(R.id.widgetListViewTweets, onClickPendingIntent);

            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetListViewTweets);
            appWidgetManager.updateAppWidget(appWidgetId, remoteView);
        }

        @Override
        public void onDeleted(Context context, int[] appWidgetIds) {
            for (int appWidgetId : appWidgetIds)
                WidgetConfigureActivity.deleteTitlePref(context, appWidgetId);
        }

        @Override
        public void onEnabled(Context context) {
        }

        @Override
        public void onDisabled(Context context) {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            super.onReceive(context, intent);

            String widgetText = WidgetConfigureActivity.loadTitlePref(context, appWidgetIdApp);
            Log.v("Class:" + TAG, "onReceive:" + intent.getAction() + " widgetText:" + widgetText);

            if (WIDGET_LIST_REFRESH.equals(intent.getAction())) {
                Toast.makeText(contextApp, "Refresh:" + widgetText, Toast.LENGTH_SHORT).show();
                ListWidgetViewsFactory.onRefresh();
            } else if (WIDGET_APP_CONFIG.equals(intent.getAction())) {
                Intent appIntent = new Intent(context, WidgetConfigureActivity.class);
                appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(appIntent);
            } else if (WIDGET_LIST_CLEAR.equals(intent.getAction())) {
                ListWidgetViewsFactory.onClear();
            } else if (WIDGET_TWITTER_NEW.equals(intent.getAction())) {
                String text = widgetText.replaceAll("#", "");
                Intent appIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/intent/tweet?text=%23" + text + " "));
                context.startActivity(appIntent);
            } else if (AppIntent.ACTION_CLICK_LIST_WIDGET.equals(intent.getAction())) {
                switch (intent.getIntExtra(AppIntent.EXTRA_CLICK_TYPE, -1)) {
                    case OPEN_CLICK_TYPE:
                        String id = intent.getStringExtra(AppIntent.EXTRA_ID);
                        String user = intent.getStringExtra(AppIntent.EXTRA_USERNAME);
                        user = user.replaceAll("@", "");

                        Log.v("Class:" + TAG, "ID:" + id + ",User:" + user);
                        Intent webIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/" + user + "/status/" + id));
                        context.startActivity(webIntent);
                        break;
                }
            }
        }

    }

ListWidgetViewsFactory:

import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;

import com.widgettwitter.AppIntent;
import com.widgettwitter.R;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

class ListItem {
    public String id, ch, fullname, username, timestamp, text, photo;
}

public class ListWidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
    private static final String TAG = ListWidgetViewsFactory.class.getName();

    private static Context contextApp = null;
    private static int appWidgetIdApp;
    private static AppWidgetManager appWidgetManager = null;
    private static RemoteViews remoteViewWidget = null;

    public static ArrayList<ListItem> listItemList = new ArrayList<ListItem>();
    public static String ultimeTwitter = "";

    private static String url;
    static String widgetText;
    static Boolean tag = false;

    public ListWidgetViewsFactory(Context context, Intent intent) {
        contextApp = context;
        appWidgetIdApp = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
        widgetText = WidgetConfigureActivity.loadTitlePref(context, appWidgetIdApp);
        Log.v("Class:" + TAG, widgetText);

        String query = String.valueOf(widgetText);
        if (query.contains("#")) {
            widgetText = query.replaceAll("#", "");
            url = "https://twitter.com/search?f=tweets&q=%23" + widgetText + "&lang=it";
            tag = true;
        } else {
            url = "https://twitter.com/search?f=tweets&q=" + widgetText + "&lang=it";
            tag = false;
        }
        appWidgetManager = AppWidgetManager.getInstance(context);
        remoteViewWidget = new RemoteViews(context.getPackageName(), R.layout.widget);
    }

    @Override
    public void onCreate() {
        Log.v("Class:" + TAG, "onCreate:" + widgetText);
        remoteViewWidget.setTextViewText(R.id.hashtag, "Init");
        remoteViewWidget.setViewVisibility(R.id.progressBar, View.VISIBLE);
        appWidgetManager.updateAppWidget(appWidgetIdApp, remoteViewWidget);

        new Html().execute();
    }

    @Override
    public void onDataSetChanged() {
        Log.v("Class:" + TAG, "onDataSetChanged:");
    }

    public static void onClear(){
        listItemList.clear();
        ultimeTwitter = "";
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIdApp, R.id.widgetListViewTweets);
    }


    public static void onRefresh(){
        remoteViewWidget.setTextViewText(R.id.hashtag, "#Refresh");
        remoteViewWidget.setViewVisibility(R.id.progressBar, View.VISIBLE);
        appWidgetManager.updateAppWidget(appWidgetIdApp, remoteViewWidget);

        new Html().execute();
    }

    @Override
    public void onDestroy() {
        if (listItemList != null) listItemList.clear();
    }

    @Override
    public int getCount() {
        return listItemList.size();
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public RemoteViews getLoadingView() {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public RemoteViews getViewAt(int position) {
        Log.v("Class:" + TAG, "getViewAt:" + position);
        final RemoteViews remoteView = new RemoteViews(contextApp.getPackageName(), R.layout.list_row);
        ListItem listItem = listItemList.get(position);
        URL url = null;
        try {
            url = new URL(listItem.ch);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        Bitmap bmp = null;
        try {
            bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        bmp = getCroppedBitmap(bmp);
        remoteView.setImageViewBitmap(R.id.ch, bmp);
        remoteView.setTextViewText(R.id.name, listItem.fullname);
        remoteView.setTextViewText(R.id.username, listItem.username);
        remoteView.setTextViewText(R.id.timestamp, listItem.timestamp);
        remoteView.setTextViewText(R.id.text, listItem.text);

        /*if (listItem.photo != "") {
            try {
                url = new URL(listItem.photo);
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
            bmp = null;
            try {
                bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            remoteView.setViewVisibility(R.id.photo, View.VISIBLE);
            remoteView.setImageViewBitmap(R.id.photo, bmp);
        }*/

        final Intent openIntent = new Intent();
        openIntent.putExtra(AppIntent.EXTRA_CLICK_TYPE, ListWidgetProvider.OPEN_CLICK_TYPE);
        openIntent.putExtra(AppIntent.EXTRA_ID, listItem.id);
        openIntent.putExtra(AppIntent.EXTRA_USERNAME, listItem.username);
        remoteView.setOnClickFillInIntent(R.id.widgetItemContainer, openIntent);

        return remoteView;
    }

    public Bitmap getCroppedBitmap(Bitmap bitmap) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
                bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

        paint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(color);
        // canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
                bitmap.getWidth() / 2, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(bitmap, rect, rect, paint);
        //Bitmap _bmp = Bitmap.createScaledBitmap(output, 60, 60, false);
        //return _bmp;
        return output;
    }

    private static class Html extends AsyncTask<Void, Void, Void> {
        private JSONArray array = new JSONArray();

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(Void... params) {

            try {
                // Connect to the web site
                Document doc = Jsoup.connect(url).get();
                // Using Elements to get the Meta data
                Elements mElementDataSize = doc.select("div[class=content]");
                // Locate the content attribute
                int mElementSize = mElementDataSize.size();

                for (int i = 0; i < mElementSize; i++) {
                    JSONObject obj = new JSONObject();

                    Elements mElementId = doc.select("li[class=js-stream-item stream-item stream-item]").eq(i);
                    String mId = mElementId.attr("data-item-id");

                    Elements mElementAvatar = doc.select("img[class=avatar js-action-profile-avatar]").eq(i);
                    String mAvatar = mElementAvatar.attr("src");

                    Elements mElementFullName = doc.select("strong[class=fullname show-popup-with-id u-textTruncate]").eq(i);
                    String mFullName = mElementFullName.text();

                    Elements mElementUsername = doc.select("span[class=username u-dir u-textTruncate]").eq(i);
                    String mUsername = mElementUsername.text();

                    Elements mElementTimestamp = doc.select("span[class=_timestamp js-short-timestamp js-relative-timestamp]").eq(i);
                    String mTimestamp = mElementTimestamp.text();

                    Elements mElementText = doc.select("p[class=TweetTextSize  js-tweet-text tweet-text]").eq(i);
                    String mText = mElementText.text();

                    Elements mElementPhoto = doc.select("div[class=AdaptiveMedia-photoContainer js-adaptive-photo]").eq(i);
                    String mPhoto = mElementPhoto.attr("data-image-url");

                    try {
                        obj.put("id", mId);
                        obj.put("avatar", mAvatar);
                        obj.put("fullname", i + ") " + mFullName);
                        obj.put("username", mUsername);
                        obj.put("timestamp", mTimestamp);
                        obj.put("text", mText);
                        obj.put("photo", mPhoto);
                        array.put(obj);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            populateListItem(array);
        }

        private void populateListItem(JSONArray array) {
            int id = array.length() - 1;
            if (!ultimeTwitter.equals("")) {
                for (int i = array.length() - 1; i >= 0; i--) {
                    try {
                        JSONObject o = array.getJSONObject(i);
                        if (o.getString("id").equals(ultimeTwitter)) {
                            id = i - 1;
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }

            for (; id >= 0; id--) {
                ListItem listItem = new ListItem();
                try {
                    JSONObject o = array.getJSONObject(id);
                    Log.v("Class:" + TAG, "populateListItem" + String.valueOf(array.getJSONObject(id)));
                    ultimeTwitter = o.getString("id");
                    listItem.id = o.getString("id");
                    listItem.fullname = o.getString("fullname");
                    listItem.username = o.getString("username");
                    listItem.timestamp = "· " + o.getString("timestamp");
                    listItem.text = o.getString("text");
                    listItem.ch = o.getString("avatar");
                    listItem.photo = o.getString("photo");
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                listItemList.add(listItem);
            }

            String str = tag ? "#" : "";
            remoteViewWidget.setTextViewText(R.id.hashtag, str + String.valueOf(widgetText)+" ("+listItemList.size()+")");
            remoteViewWidget.setViewVisibility(R.id.progressBar, View.INVISIBLE);
            appWidgetManager.updateAppWidget(appWidgetIdApp, remoteViewWidget);
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIdApp, R.id.widgetListViewTweets);
            Log.v("Class:" + TAG, "TweetProvider:onPostExecute");
        }
    }

}

1 个答案:

答案 0 :(得分:1)

您要将应用程序窗口小部件ID保存在静态变量中,因此在快速创建两个窗口小部件之后,在ListWidgetProvider中,静态appWidgetId将具有最后一个窗口小部件的值,该用户将在Launcher上占据一席之地。问题在于静态变量在所有类实例中都具有相同的值。那么我们有什么:在执行两个asynctask之后,它将更新最后一个窗口小部件,因为第一个窗口小部件的asynctask仍在执行,并且如果第二个窗口小部件的asynctask仍在更新。要使其正常工作,请将其设置为非静态字段,然后通过 ListWidgetService ListWidgetViewsFactory 中传递应用小部件ID。是的,您需要删除所有使用该静态变量的静态方法,您可以通过 ListWidgetService 进行相同的操作,这些操作将触发 ListWidgetViewsFactory 并执行某些操作,例如 REFRESH 清除

当我检查您的代码时,您可以删除asynctask,并通过appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widgetListViewTweets)更新窗口小部件,并在 onDataSetChanged()中通过网络请求并填充窗口小部件。这个想法是 onDataSetChanged()在绑定线程(非主线程)上工作,因此可以安全地使用它。还要检查此回调图,实际上,如果您将当前线程记录在RemoteViewFactory回调中,则您会看到只有onCreate()在主线程上

enter image description here