制作一个在点击时播放特定声音的 Android 小部件

问题描述

我正在编写一个音板应用程序,让用户可以在他们的主屏幕上放置一些小部件。它由一个由 Sound 类的 RecyclerView 扩充的 Widget ConfigureActivity 组成:

public class Sound {
    private String name;
    private int sound_id;

    public Sound(String name,int sound_id) {
        this.name= name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public int getId() {
        return id;
    }
}

用户从 ConfigureActivity RecyclerView 中选择一个元素时,会创建一个小部件。但是,我发现当用户点击它时无法播放声音。

我的适配器如下所示:

public class AdapterDatosWidget extends RecyclerView.Adapter<AdapterDatosWidget.ViewHolderDatosWidget> {
    private final ArrayList<Sonido> sonidos;
    private AssignHandler handler;

    public AdapterDatosWidget(ArrayList<Sound> sonidos,AssignHandler assignHandler) {
        this.sonidos = sonidos;
        handler = assignHandler;
    }

    @NonNull
    @Override
    public ViewHolderDatosWidget onCreateViewHolder(@NonNull ViewGroup parent,int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_widget,null,false);
        return new AdapterDatosWidget.ViewHolderDatosWidget(view,handler);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolderDatosWidget holder,int position) {
        holder.asignarDatos(sonidos.get(position));
    }

    @Override
    public int getItemCount() {
        return sonidos.size();
    }

    public static class ViewHolderDatosWidget extends RecyclerView.ViewHolder {
        Sound s;
        TextView name;
        AssignHandler handler;

        public ViewHolderDatosWidget(@NonNull View itemView,AssignHandler handler) {
            super(itemView);
            name = itemView.findViewById(R.id.sound_name);
            this.handler = handler;
        }

        public void asignarDatos(Sound sonido) {
            s = sonido;
            name.setText(sonido.getNombre());
            name.setonClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    handler.assign(getAbsoluteAdapterPosition());
                }
            });
        }
    }

    public interface AssignHandler {
        void assign(int position);
    }
}

Configure Activity 正确识别出被按下的声音,如下所示:

public class SoundWidgetConfigureActivity extends Activity implements AdapterDatosWidget.AssignHandler {

    int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
    RecyclerView recyclerView;
    private static final String PREFS_NAME = "com.xvlaze.soundboard.soundWidget";
    private static final String PREF_PREFIX_KEY = "appwidget_";

    public SoundWidgetConfigureActivity() {
        super();
    }

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

        // Set the result to CANCELED.  This will cause the widget host to cancel
        // out of the widget placement if the user presses the back button.
        setResult(RESULT_CANCELED);

        setContentView(R.layout.sound_widget_configure);
        recyclerView = findViewById(R.id.recycler);
        recyclerView.setLayoutManager(new linearlayoutmanager(this));
        AdapterDatosWidget ad = new AdapterDatosWidget(sonidos,this);
        recyclerView.setAdapter(ad);
        findViewById(R.id.add_button).setonClickListener(mOnClickListener);

        // Find the widget id from the intent.
        Intent intent = getIntent();
        Bundle extras = intent.getExtras();
        if (extras != null) {
            mAppWidgetId = extras.getInt(
                    AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID);
        }

        // If this activity was started with an intent without an app widget ID,finish with an error.
        if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
            finish();
            return;
        }
    }

    View.OnClickListener mOnClickListener = new View.OnClickListener() {
        public void onClick(View v) {
            final Context context = SoundWidgetConfigureActivity.this;

            // It is the responsibility of the configuration activity to update the app widget
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            SoundWidget.updateAppWidget(context,appWidgetManager,mAppWidgetId);

            // Make sure we pass back the original appWidgetId
            Intent resultValue = new Intent();
            resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,mAppWidgetId);
            setResult(RESULT_OK,resultValue);
            finish();
        }
    };

    // Write the prefix to the SharedPreferences object for this widget
    static void saveTitlePref(Context context,int appWidgetId,String text) {
        SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME,0).edit();
        prefs.putString(PREF_PREFIX_KEY + appWidgetId,text);
        prefs.apply();
    }

    // Read the prefix from the SharedPreferences object for this widget.
    // If there is no preference saved,get the default from a resource
    static String loadTitlePref(Context context,int appWidgetId) {
        SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME,0);
        String titleValue = prefs.getString(PREF_PREFIX_KEY + appWidgetId,null);
        if (titleValue != null) {
            return titleValue;
        } else {
            return context.getString(R.string.appwidget_text);
        }
    }

    static void deleteTitlePref(Context context,int appWidgetId) {
        SharedPreferences.Editor prefs = context.getSharedPreferences(PREFS_NAME,0).edit();
        prefs.remove(PREF_PREFIX_KEY + appWidgetId);
        prefs.apply();
    }

    @Override
    public void assign(int position) {
        Toast.makeText(this,sonidos.get(position).getName(),Toast.LENGTH_SHORT).show();
        final Context context = SoundWidgetConfigureActivity.this;

        // When the button is clicked,store the string locally
        //String widgetText = mAppWidgetText.getText().toString();
        //saveTitlePref(context,mAppWidgetId,widgetText);

        // It is the responsibility of the configuration activity to update the app widget
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        NewAppWidget.updateAppWidget(context,mAppWidgetId);

        // Make sure we pass back the original appWidgetId
        Intent resultValue = new Intent();
        resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,mAppWidgetId);
        setResult(RESULT_OK,resultValue);
        finish();
    }
}

Widget 代码如下所示:

public class SoundWidget extends appwidgetprovider {

    @Override
    public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds) {
        RemoteViews img = new RemoteViews(context.getPackageName(),R.layout.sound_widget);
        Intent playIntent = new Intent(context,PlaySoundService.class);
        PendingIntent playPendingIntent = PendingIntent.getService(
                context,playIntent,0);

        img.setonClickPendingIntent(R.id.widget,playPendingIntent);


        // There may be multiple widgets active,so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context,appWidgetId);
        }
    }

    @Override
    public void onDeleted(Context context,int[] appWidgetIds) {
        // When the user deletes the widget,delete the preference associated with it.
        for (int appWidgetId : appWidgetIds) {
            SoundWidgetConfigureActivity.deleteTitlePref(context,appWidgetId);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    @Override
    public void ondisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    static void updateAppWidget(Context context,int appWidgetId) {

        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.sound_widget);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId,views);
    }
}

Service 的代码如下所示:

public class PlaySoundService extends Service {
    private static final String TAG = null;
    MediaPlayer player;
    public IBinder onBind(Intent arg0) {

        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        player = MediaPlayer.create(this,R.raw.soundid);
        //configure other settings
    }
    public int onStartCommand(Intent intent,int flags,int startId) {
        player.start();
        return Service.START_STICKY;
    }

    public void onStart(Intent intent,int startId) {
        // TO DO
    }
    public IBinder onUnBind(Intent arg0) {
        // TO DO Auto-generated method
        return null;
    }

    public void onStop() {

    }
    public void onPause() {

    }
    @Override
    public void onDestroy() {
        player.stop();
        player.release();
    }
}

如果您重现此示例(请使用一些示例 mp3 文件填充 res/raw 文件夹),请调用

Intent svc=new Intent(this,BackgroundSoundService.class);
startService(svc);

在 MainActivity 中,您会看到只要打开应用程序就会立即播放声音。我错过了什么吗?我简直不敢相信它那么复杂。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)