如何更新BroadcastReceiver中的UI

时间:2013-02-01 09:41:02

标签: android broadcastreceiver

我创建了一个应用程序,我在我的主要课程(Main Activity)中注册了一个广播接收器,每当我在BroadcastReceiver收到某些内容时,我想要更新UI,例如我想显示一个警告框或设置我的MainActivity的一些文本视图。我收到了接收器中的所有值但无法设置它们,有人可以帮助我,以便我可以在BroadcastReceiver更新我的UI。

我的BroadcastReceiver类是MainActivity的内部类,如下所示: -

public class MainActivity extends Activity {

   ..........

public static class NissanTabBroadcast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            SharedPreferences shrd = context.getSharedPreferences("NissanGallery", context.MODE_WORLD_READABLE);
            type = shrd.getString("type", "null");
            badges = shrd.getString("badge_count", "null");

            //badge_tips_text.setText(badges);
            /*Editor edit =  shrd.edit();
            edit.remove("type");*/

            Toast.makeText(context, "" + type + "\n" + badge_tips_text.getText().toString(), Toast.LENGTH_LONG).show();
        }
    }
}

任何帮助都会很明显

由于

12 个答案:

答案 0 :(得分:31)

我建议你使用Handler。

  1. 在活动中初始化处理程序,例如:handler = new Handler()
  2. 在构造函数中为BroadcastReceiver提供处理程序,方式与上面NissanTabBroadcast相同
  3. 使用post()方法中的Handler实例的onReceive()方法提交更新UI的Runnable
  4. 这是我能想象到的最干净的解决方案。

    public class MainActivity extends Activity {
    
        private MyReceiver receiver;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            receiver = new MyReceiver(new Handler()); // Create the receiver
            registerReceiver(receiver, new IntentFilter("some.action")); // Register receiver
    
            sendBroadcast(new Intent("some.action")); // Send an example Intent
        }
    
        public static class MyReceiver extends BroadcastReceiver {
    
            private final Handler handler; // Handler used to execute code on the UI thread
    
            public MyReceiver(Handler handler) {
                this.handler = handler;
            }
    
            @Override
            public void onReceive(final Context context, Intent intent) {
                // Post the UI updating code to our Handler
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(context, "Toast from broadcast receiver", Toast.LENGTH_SHORT).show();
                    }
                });
            }
        }
    }
    

答案 1 :(得分:8)

我的情况是更新MainActivity托管的一个片段中的文本字段。我找到的最简单的解决方案是: -

在我的MainActivity类中检索了MainActivtiy的运行实例。这是我的MAinActivity

private static MainActivity mainActivityRunningInstance;
    public static MainActivity  getInstace(){
        return mainActivityRunningInstance;
    }
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mainActivityRunningInstance =this;
----------
}

现在在广播接收器的onRecieve方法中,获取该实例并调用更新方法

 @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().matches(Intents.PROVIDER_CHANGED_ACTION)) {
                String textValue="the text field value";
// the null check is for, if the activity is not running or in paused state, in my case the update was required onlyif the main activity is active or paused
            if(MainActivity.getInstace()!=null)
                MainActivity.getInstace().updateUI(textValue);
}

现在我们需要在UIThread中运行更新的部分,MainActivity的updateUI方法将调用片段更新方法。

  public void updateUI(final String str) {
        MainActivity.this.runOnUiThread(new Runnable() {
            public void run() {
     //use findFragmentById for fragments defined in XML ((SimpleFragment)getSupportFragmentManager().findFragmentByTag(fragmentTag)).updateUI(str);
            }
        });
    }

,最后一步是更新片段的文本字段

public void updateUI(String str){
        tv_content.setText(str);
    }

和宾果,完成了。我提到this链接来解决我的问题。希望它能帮到别人。

答案 2 :(得分:6)

使用runOnUiThread

 MainActivity.this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // show alert

        }
    });

答案 3 :(得分:1)

我正在使用完全不同的方法。通过将处理器的实例放入intent中来传播接收器的实例。然后在广播接收器中使用该处理程序向您的活动类发送消息,该类更新了onHandleMessage方法中的UI你的自定义处理程序类。

create handler class like

   public class MyHandler extends Handler{

onHandlerMessage(Message msg){//do whatever you want here after broadcast get fired}
}

现在使用Myhandler handler=new MyHandler();在活动的全局级别范围内创建此处理程序对象。

现在通过putExtra将此处理程序置于您的意图中,然后通过sendBraodcast(intent)发送此意图。

广播接收器类中的

通过getExtras获取此处理程序对象并使用如下所示 在onReceive()方法

 handler.sendEmptyMessage();

答案 4 :(得分:1)

我使用Intent让Broadcast Receiver了解主Activity线程的Handler实例,并使用Message将消息传递给Main activity

我已经使用这种机制来检查广播接收器是否已经注册。有时,当您动态注册广播接收器并且不想两次播放时,或者如果广播接收器正在运行,则需要向用户显示。

主要活动:

public class Example extends Activity {

private BroadCastReceiver_example br_exemple;

final Messenger mMessenger = new Messenger(new IncomingHandler());

private boolean running = false;

static class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        running = false;    
        switch (msg.what) {
        case BroadCastReceiver_example.ALIVE:
    running = true;
            ....
            break;
        default:

            super.handleMessage(msg);
        }

    }
    }

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    IntentFilter filter = new IntentFilter();
        filter.addAction("pl.example.CHECK_RECEIVER");

        br_exemple = new BroadCastReceiver_example();
        getApplicationContext().registerReceiver(br_exemple , filter); //register the Receiver
    }

// call it whenever you want to check if Broadcast Receiver is running.

private void check_broadcastRunning() {    
        /**
        * checkBroadcastHandler - the handler will start runnable which will check if Broadcast Receiver is running
        */
        Handler checkBroadcastHandler = null;

        /**
        * checkBroadcastRunnable - the runnable which will check if Broadcast Receiver is running
        */
        Runnable checkBroadcastRunnable = null;

        Intent checkBroadCastState = new Intent();
        checkBroadCastState .setAction("pl.example.CHECK_RECEIVER");
        checkBroadCastState .putExtra("mainView", mMessenger);
        this.sendBroadcast(checkBroadCastState );
        Log.d(TAG,"check if broadcast is running");

        checkBroadcastHandler = new Handler();
        checkBroadcastRunnable = new Runnable(){    

            public void run(){
                if (running == true) {
                    Log.d(TAG,"broadcast is running");
                }
                else {
                    Log.d(TAG,"broadcast is not running");
                }
            }
        };
        checkBroadcastHandler.postDelayed(checkBroadcastRunnable,100);
        return;
    }

.............
}

广播接收器:

public class BroadCastReceiver_example extends BroadcastReceiver {


public static final int ALIVE = 1;
@Override
public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    Bundle extras = intent.getExtras();
    String action = intent.getAction();
    if (action.equals("pl.example.CHECK_RECEIVER")) {
        Log.d(TAG, "Received broadcast live checker");
        Messenger mainAppMessanger = (Messenger) extras.get("mainView");
        try {
            mainAppMessanger.send(Message.obtain(null, ALIVE));
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    .........

}

}

答案 5 :(得分:1)

在我的情况下,我想用传入的短信更新我的活动中的textview,我所做的是使用putextra添加所需信息,然后从广播接收器开始活动:

Intent intentone = new Intent(context.getApplicationContext(), enroll.class);
intentone.putExtra("pinbody",message);
intentone.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentone);    

然后在接收端,即在注册活动中,我使用以下内容提取了该信息并更新了我的文本视图:

Bundle extras = getIntent().getExtras();
String message = extras.getString("pinbody");

不确定它是否有帮助,但绝对会引导您达到您想要的效果。

干杯!

答案 6 :(得分:1)

使用getter和setter可以轻松解决这个问题。

按如下方式声明一个类。

public class DetailsGetters {
    private View view;
    public View getview() {
        return view;
    }

    public void setview(View view) {
        this.view = view;
    }
}

在主活动或片段活动上,创建DetailsGetters类的实例。

DetailsGetters newdetailsinstance=new DetailsGetters();

退出观看电话newdetailsinstance.setview(view);

之前

在广播接收器上将视图设为newdetailsinstance.getview(view);

以下内容可用于从片段中获取视图并使用setText等更新Ui ..

要更新主要活动的UI,请传递Textview并更改DeailsGetters类并为Textview创建getter和setter。希望这对某人有帮助。

答案 7 :(得分:1)

如何在任何活动中重新使用BroadcastReceiver?

enter image description here
考虑以下情况,

  • 您想在不同的地方使用相同的BroadcastReceiver 活动
  • 您已经在单独的文件中编写了BroadcastReceiver,并希望访问Activity方法,UI元素等。

在这些情况下,使用接口是一个好主意。我将更详细地说明优势和用例。但是首先,让我们看看它是如何完成的。

1)创建一个界面

public interface MyBroadcastListener{

    public void doSomething(String value);

}

2)在BroadcastReceiver中初始化监听器

public class MyReceiver extends BroadcastReceiver {

    private MyBroadcastListener listener;

    public MyReceiver(MyBroadcastListener listener){
        this.listener = listener;
    }

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

        listener.doSomething("Some Result");

    }
}

3)在“活动”中实现界面并覆盖方法

 public MainActivity extends AppCompatActivity implements MyBroadcastListener{

      private BroadcastReceiver receiver;

      @Override
      public void onCreate(Bundle sis){

           // Related code 

           receiver = new MyReceiver(this);   // This is how you initialise receiver

          // Register receiver etc
      }


      public void updateUI(String msg) {
           TextView textView = (TextView) findViewById(R.id.textView);
           textView .setText(msg);
      }

      @Override
      public void doSomething(String result){
           updateUI(result);        // Calling method from Interface
      }

 }

优势和用例?

  

使用接口方法可使BroadcastReceiver独立于任何   活动。假设您将来想使用此BroadCastReceiver   与另一个活动,它从BroadcastReceiver获取结果   并启动一个DetailActivity。

     

请注意,这是完全   不同的任务,但您可以使用相同的BroadcastReceiver   BroadcastReceiver内部的任何代码更改。

该怎么做?
简单!在Activity中实现接口,然后重写该方法。就是这样!

public ListActivity extends AppCompatActivity implements MyBroadcastListener{

      // Your Activity code goes here

     public void startDetailActivity(String title) {
         Intent i = new Intent(ListActivity,this, DetailActivity.class);
         i.putExtra("Title", title);
         startActivity(i);
     }

      @Override
      public void doSomething(String result){
           startDetailActivity(String title);    // Calling method from Interface
      }

}

enter image description here

答案 8 :(得分:0)

我使用过Handler&它的post()方法。而不是runOnUiThread()。无需将Context转换为Activity。它是runOnUiThread()

的替代品
Handler handler = new Handler();
Runnable runnable = new Runnable() {
    private long startTime = System.currentTimeMillis();
    public void run() {
        while (gameState == GameState.Playing) {  
            try {
                Thread.sleep(1000);
            }    
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            handler.post(new Runnable(){
                public void run() {
                   tvTime.setText("" + ((System.currentTimeMillis() - this.startTime) / 1000));
            }
        });
        }
    }
};
new Thread(runnable).start();

答案 9 :(得分:0)

你应该将广播接收器作为内部类,这样它就可以访问所有字段来更新UI。

通过nick butcher查看此格子图案应用 Plaid- Nick Butcher(Github)

答案 10 :(得分:0)

获取当前日期时间和秒数,并通过广播接收器在用户界面中更新

    package com.keshav.broadcasttest;

    import java.util.Date;

    import android.app.Service;
    import android.content.Intent;
    import android.os.Handler;
    import android.os.IBinder;
    import android.util.Log;

    public class BroadcastService  extends Service {
       private static final String TAG = "BroadcastService";
       public static final String BROADCAST_ACTION = "com.keshav.broadcasttest.displayevent";
       private final Handler handler = new Handler();
       Intent intent;
       int counter = 0;

       @Override
       public void onCreate() {
          super.onCreate();

           intent = new Intent(BROADCAST_ACTION); 
       }

        @Override
        public void onStart(Intent intent, int startId) {
            handler.removeCallbacks(sendUpdatesToUI_Runnable);
            handler.postDelayed(sendUpdatesToUI_Runnable, 1000); // 1 second

        }

        private Runnable sendUpdatesToUI_Runnable = new Runnable() {
           public void run() {
              DisplayLoggingInfo();         
               handler.postDelayed(this, 10000); // 10 seconds
           }
        };    

        private void DisplayLoggingInfo() {
           Log.d(TAG, "entered DisplayLoggingInfo");

           intent.putExtra("time", new Date().toLocaleString());
           intent.putExtra("counter", String.valueOf(++counter));
           sendBroadcast(intent);
        }

       @Override
       public IBinder onBind(Intent intent) {
          return null;
       }

       @Override
       public void onDestroy() {     
            handler.removeCallbacks(sendUpdatesToUI_Runnable);
          super.onDestroy();
       }     
    }
    ============================================

    package com.keshav.broadcasttest;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

public class BroadcastTest extends Activity {
    private static final String TAG = "BroadcastTest";
    private Intent intent;

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

        intent = new Intent(this, BroadcastService.class);
    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updateUI(intent);       
        }
    };    

    @Override
    public void onResume() {
        super.onResume();       
        startService(intent);
        registerReceiver(broadcastReceiver, new IntentFilter(BroadcastService.BROADCAST_ACTION));
    }

    @Override
    public void onPause() {
        super.onPause();
        unregisterReceiver(broadcastReceiver);
        stopService(intent);        
    }   

    private void updateUI(Intent intent) {
        String counter = intent.getStringExtra("counter"); 
        String time = intent.getStringExtra("time");
        Log.d(TAG, counter);
        Log.d(TAG, time);

        TextView txtDateTime = (TextView) findViewById(R.id.txtDateTime);   
        TextView txtCounter = (TextView) findViewById(R.id.txtCounter);
        txtDateTime.setText(time);
        txtCounter.setText(counter);
    }
}
    =============================

    <?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"
        >
        <TableLayout android:id="@+id/tableGPS"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="7px"
            android:stretchColumns="1">
            <TableRow
                android:layout_margin="1dip">
                <TextView android:layout_gravity="right"
                    android:text="Time:"
                    android:layout_marginRight="7px"
                    android:layout_width="130px" />
                <TextView android:id="@+id/txtDateTime"
                    android:gravity="left"
                    android:layout_span="2" />
            </TableRow>
            <TableRow
                android:layout_margin="1px">
                <TextView android:layout_gravity="right"
                    android:text="Counter:"
                    android:layout_marginRight="7px"
                    android:layout_width="160px" />
                <TextView android:id="@+id/txtCounter"
                    android:gravity="left" />
            </TableRow>
        </TableLayout>
    </LinearLayout>

    ===========================================

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

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

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

            <service android:name=".BroadcastService" />
        </application>

    </manifest>

答案 11 :(得分:0)

BroadcastReceiver的onReceive()方法在主线程中运行,因此您可以在此方法中修改UI,因为onReceive()在主线程中运行,避免长时间运行 从这里开始操作。

来自官方文档:

由于接收者的onReceive(Context,Intent)方法在主线程上运行,因此它应该执行并快速返回。如果您需要执行长时间运行的工作,请小心生成线程或启动后台服务,因为在onReceive()返回之后,系统可能会杀死整个进程。有关更多信息,请参见对流程状态的影响。要执行长期运行的工作,我们建议:

在接收者的onReceive()方法中调用goAsync()并将BroadcastReceiver.PendingResult传递给后台线程。从onReceive()返回后,这可使广播保持活动状态。但是,即使采用这种方法,系统也希望您能够非常快地完成广播(不到10秒)。它的确使您可以将工作移至另一个线程,以避免使主线程出现故障。 使用JobScheduler计划作业。有关更多信息,请参阅智能作业计划。