douzhui1972 2016-04-01 14:32
浏览 47
已采纳

使用gcm更新ListView中的ImageView

So here is my problem, what I'm trying to do is the following:

I have a simple ListView class that gets the item info (name of the item) from a MySql DB via PHP script and that works fine.

The other part of the ListView item is a ImageView. It represents 3 states the item can be in. A picture of a green "traffic light" means 'its OK', a red one, its 'not OK' and a grey one means 'service not available'. The state change trigger comes from an other app (via gcm) and the message contains a value of -1, 0 or 1 which I want to use to trigger the ImageView changes.

Here is my onCreate method for my Activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_channel_list);

    mRegistrationProgressBar = (ProgressBar) findViewById(R.id.registrationProgressBar);
    mRegistrationBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
            SharedPreferences sharedPreferences =
                    PreferenceManager.getDefaultSharedPreferences(context);
            boolean sentToken = sharedPreferences
                    .getBoolean(SENT_TOKEN_TO_SERVER, false);
            if (sentToken) {
                Log.i(TAG, getString(R.string.gcm_send_message));
            } else {
                Log.i(TAG, getString(R.string.token_error_message));
            }

        }
    };
    // Registering broadcast receiver
    registerReceiver();

    if (checkPlayServices()) {
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }



    /*----------------------------------------------------------------------------------------*/
    /*---------------------------------AsyncTask that makes the ListView ---------------------*/
    /*----------------------------------------------------------------------------------------*/

    PostResponseAsyncTask taskRead = new PostResponseAsyncTask(ChannelList.this, this);
    taskRead.execute(SERVER_ADDRESS + "Script.php");

    BindDictionary<Channel> dict = new BindDictionary<Channel>();
    dict.addStringField(R.id.tvName, new StringExtractor<Channel>() {
        @Override
        public String getStringValue(Channel channel, int position) {
            return channel.channel_name;
        }
    });

    FunDapter<Channel> adapter = new FunDapter<>(
            ChannelList.this, channelList, R.layout.layout_list, dict);

    lvChannel = (ListView) findViewById(R.id.lvChannels);
    lvChannel.setAdapter(adapter);

    /*----------------------------------------------------------------------------------------*/
    /*----------------------------------------------------------------------------------------*/
}

Then I have the GcmListenerService class:

public class MyGcmListenerService extends GcmListenerService {

private static final String TAG = "MyGcmListenerService";


/**
 * Called when message is received.
 *
 * @param from SenderID of the sender.
 * @param data Data bundle containing message data as key/value pairs.
 *             For Set of keys use data.keySet().
 */
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
    String message = data.getString("message");
    String commercial = data.getString("commercial");
    Log.d(TAG, "From: " + from);
    Log.d(TAG, "Message: " + message);
    Log.d(TAG, "Commercial: " + commercial);

    if (from.startsWith("/topics/")) {
        // message received from some topic.
    } else {
        // normal downstream message.
    }

    // [START_EXCLUDE]
    /**
     * Production applications would usually process the message here.
     * Eg: - Syncing with server.
     *     - Store message in local database.
     *     - Update UI.
     */

    /**
     * In some cases it may be useful to show a notification indicating to the user
     * that a message was received.
     */
    sendNotification(message);
    // [END_EXCLUDE]
}
// [END receive_message]

/**
 * Create and show a simple notification containing the received GCM message.
 *
 * @param message GCM message received.
 */

private void sendNotification(String message) {

    Intent intent = new Intent(this, ChannelList.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , intent,  // 0 => Request code
            PendingIntent.FLAG_ONE_SHOT);



    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("GCM Message")
            .setContentText(message)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 , notificationBuilder.build()); // 0 => ID of notification
}
}

Then I have the RegistrationIntentService class:

public class RegistrationIntentService extends IntentService {

private static final String TAG = "RegIntentService";
private static final String[] TOPICS = {"global"};
public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
public static final String REGISTRATION_COMPLETE = "registrationComplete";

public RegistrationIntentService() {
    super(TAG);
}

@Override
protected void onHandleIntent(Intent intent) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    try {
        // [START register_for_gcm]
        // Initially this call goes out to the network to retrieve the token, subsequent calls
        // are local.
        // R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
        // See https://developers.google.com/cloud-messaging/android/start for details on this file.
        // [START get_token]
        InstanceID instanceID = InstanceID.getInstance(this);
        String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
        // [END get_token]
        Log.i(TAG, "GCM Registration Token: " + token);

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(token);

        // Subscribe to topic channels
        subscribeTopics(token);

        // You should store a boolean that indicates whether the generated token has been
        // sent to your server. If the boolean is false, send the token to your server,
        // otherwise your server should have already received the token.
        sharedPreferences.edit().putBoolean(SENT_TOKEN_TO_SERVER, true).apply();
        // [END register_for_gcm]
    } catch (Exception e) {
        Log.d(TAG, "Failed to complete token refresh", e);
        // If an exception happens while fetching the new token or updating our registration data
        // on a third-party server, this ensures that we'll attempt the update at a later time.
        sharedPreferences.edit().putBoolean(SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(REGISTRATION_COMPLETE);
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}

/**
 * Persist registration to third-party servers.
 *
 * Modify this method to associate the user's GCM registration token with any server-side account
 * maintained by your application.
 *
 * @param token The new token.
 */
private void sendRegistrationToServer(String token) {
    // Add custom implementation, as needed.
}

/**
 * Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
 *
 * @param token GCM token
 * @throws IOException if unable to reach the GCM PubSub service
 */
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
    GcmPubSub pubSub = GcmPubSub.getInstance(this);
    for (String topic : TOPICS) {
        pubSub.subscribe(token, "/topics/" + topic, null);
    }
}
// [END subscribe_topics]

}

The InstanceIDListenerService:

public class MyInstanceIDListenerService extends InstanceIDListenerService {

private static final String TAG = "MyInstanceIDLS";

/**
 * Called if InstanceID token is updated. This may occur if the security of
 * the previous token had been compromised. This call is initiated by the
 * InstanceID provider.
 */
// [START refresh_token]
@Override
public void onTokenRefresh() {
    // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
    Intent intent = new Intent(this, RegistrationIntentService.class);
    startService(intent);
}
// [END refresh_token]
}

And the AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tumex.useralpha"
xmlns:tools="http://schemas.android.com/tools"
>

<uses-permission android:name="android.permission.INTERNET"/>
<!-- [START gcm_permission] -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- [END gcm_permission] -->

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:replace="@android:icon"
    >
    <activity android:name=".Login">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity android:name=".ChannelList"></activity>

    <!-- [START gcm_receiver] -->
    <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="gcm.play.android.samples.com.gcmquickstart" />
        </intent-filter>
    </receiver>
    <!-- [END gcm_receiver] -->

    <!-- [START gcm_listener] -->
    <service
        android:name="com.tumex.useralpha.MyGcmListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    <!-- [END gcm_listener] -->

    <!-- [START instanceId_listener] -->
    <service
        android:name="com.tumex.useralpha.MyInstanceIDListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>
    <!-- [END instanceId_listener] -->

    <service
       android:name="com.tumex.useralpha.RegistrationIntentService"
        android:exported="false">
    </service>

</application>

So how do I go about this, make a ImageView react to values received from gcm message? If I have forgotten anything that can be helpful in solving my problem please let me know. Thank you

  • 写回答

1条回答 默认 最新

  • dqd2800 2016-04-01 14:57
    关注

    I suppose you want to update ImageView in ListView only if Activity with this ListView is showing.
    In that case use LocalBroadcastManager:


    YourActivity.java

    private BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                //int for List, String for Dictionary
                String item_id_or_name = intent.getExtra("ITEM_ID_OR_NAME");
                int status_for_item = intent.getExtra("ITEM_STATUS");
                //find this item in you List or Dictionary
                //and set new Status for this item
                yourAdapter.notifyDataSetChanged();
            }
    };
    @Override
        public void onResume() {
            super.onResume();
            LocalBroadcastManager.getInstance(YourActivity.this).registerReceiver(receiver, 
                                              new IntentFilter("FILTER_NAME"));
        }
    @Override
        public void onPause() {
            LocalBroadcastManager.getInstance(YourActivity.this).unregisterReceiver(receiver);
            super.onPause();
        }
    

    YourGcmListenerService.java:

    @Override
    public void onMessageReceived(String from, Bundle data) {
        //...parse received data
        Intent updateStatus = new Intent("FILTER_NAME");
        updateStatus.putExtra("ITEM_ID_OR_NAME", id_or_name);
        updateStatus.putExtra("ITEM_STATUS", item_status);//-1, 0, 1
        LocalBroadcastManager.getInstance(this).sendBroadcast(updateStatus);
        //...
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题