Ja, das macht ja alles Sinn. Mir ist nur immer noch nicht klar, warum die results von dem ersten Tab auf dem dritten Tab angezeigt werden. Und umgekehrt. Wie wäre dann der richtige Weg um die Daten dort zu reichen?
Beiträge von winterrmute
-
-
Moin,
ich habe in dem ViewPager2 mit TabLayout einen Recyclerview. Um in den die Daten einzuspeisen benutze ich einen Adapter (ViewPagerAdapter). Sobald die Daten in dem RecyclerView drin sind, ist die Interaktion mit den Daten kein Problem. Problematisch wird aber die erste Ebene, der richtige Umgang mit dem ViewPagerAdapter. Wenn ich in der tabbed Ansicht bin und den Tab wechsel, wird sofort der Adapter für die restlichen Tabs erzeugt und die Daten werden nur auf dem letzten Tab aktualisiert.
Hier ist meine Activity, die den ViewPagerAdapter implementiert;
Java
Alles anzeigenpublic class AudioFilePanel extends AppCompatActivity { public static final int FILE_BROWSER_REQUEST_CODE = 1; private String currentTab; private ViewPagerAdapter adapter; private ViewPager2 viewPager; private Map<String, List<FileElement>> content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_audio_file_panel); viewPager = findViewById(R.id.view_pager2); TabLayout tabLayout = findViewById(R.id.tabs); Button addFilesByTag = findViewById(R.id.add_files_with_tag); if (null == currentTab) { currentTab = "music"; } content = listByTag(); adapter = new ViewPagerAdapter(getApplicationContext(), new ArrayList<>(content.values()), currentTab); viewPager.setAdapter(adapter); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(content.keySet().toArray()[position].toString())).attach(); tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { currentTab = tab.getText().toString(); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); addFilesByTag.setOnClickListener(l -> { Intent fileBrowser = new Intent(AudioFilePanel.this, FileBrowser.class); startActivityForResult(fileBrowser, 1); }); } private void updateViweData() { content = listByTag(); adapter = new ViewPagerAdapter(getApplicationContext(), new ArrayList<>(content.values()), currentTab); viewPager.setAdapter(adapter); } private Map<String, List<FileElement>> listByTag() { Map<String, List<FileElement>> result = new HashMap<>(); DirectoryDao dao = new DirectoryDao(getApplicationContext()); String[] categories = {"music", "ambience", "effect"}; for (String category : categories) { List<FileElement> directories = dao.getDirectoriesForCategory(category).stream().map(f -> new FileElement( new File(f.getPath()).getName(), f.getPath(), true)).collect(Collectors.toList()); result.put(category, directories); } return result; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == FILE_BROWSER_REQUEST_CODE) { String path = data.getStringExtra("path"); storeDirectory(path, data.getBooleanExtra("includeSubdirs", true), currentTab); updateViweData(); } } private void storeDirectory(String path, boolean recursive, String tag) { Directory directory = new Directory(); directory.setPath(path); directory.setTag(tag); directory.setRecursive(recursive); DirectoryDao dao = new DirectoryDao(getApplicationContext()); directory.setId(dao.insert(directory)); } }
Das ist der ViewPagerAdapter:
Beim debuggen habe ich rausgefunden, dass beim ersten Tabwechsel (danach nicht mehr) direkt der onBindViewHolder ausgeführt wird.Code
Alles anzeigenpublic class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewHolder> { private static final String PREVIOUS_DIRECTORY = "previous directory"; private List<List<FileElement>> filesListsByCategory; private LayoutInflater mInflater; private Context ctx; private ItemListAdapter adapter; private String rootPath; private List<FileElement> rootElements; private String tag; public ViewPagerAdapter(Context context, List<List<FileElement>> data, String tag) { this.mInflater = LayoutInflater.from(context); this.filesListsByCategory = data; this.ctx = context; this.tag = tag; rootElements = new ArrayList<>(filesListsByCategory.get(0)); } @NotNull @Override public ViewHolder onCreateViewHolder(@NotNull ViewGroup parent, int viewType) { return new ViewHolder(mInflater.inflate(R.layout.item_viewpager, parent, false)); } @Override public void onBindViewHolder(ViewHolder holder, int position) { FileBrowserService fbs = new FileBrowserService(); List<FileElement> categoryFiles = new ArrayList<>(filesListsByCategory.get(position)); adapter = new ItemListAdapter(categoryFiles, item -> handleClickOnElement(fbs, item)); holder.myView.setAdapter(adapter); } private void handleClickOnElement(FileBrowserService fbs, FileElement item) { if (new File(item.getPath()).isDirectory()) { List<FileElement> newContent; String newPath; if (item.isRoot()) { rootPath = item.getPath(); } if (PREVIOUS_DIRECTORY.equals(item.getName())) { newPath = item.getPath().substring(0, item.getPath().lastIndexOf('/')); } else { newPath = item.getPath(); } FileElement goToParent = new FileElement(PREVIOUS_DIRECTORY, newPath, false); if (item.getPath().equals(rootPath) && !item.isRoot()) { newContent = rootElements; } else { newContent = fbs.getFiles(newPath); newContent.add(0, goToParent); } updateListElements(newContent); } else { //TODO: play track } } private void updateListElements(List<FileElement> newContent) { adapter.updateData(null, "clearData"); adapter.updateData(newContent, "updateData"); } @Override public int getItemCount() { return filesListsByCategory.size(); } class ViewHolder extends RecyclerView.ViewHolder { RecyclerView myView; RelativeLayout relativeLayout; ViewHolder(View itemView) { super(itemView); myView = itemView.findViewById(R.id.my_list); myView.setLayoutManager(new LinearLayoutManager(ctx)); relativeLayout = itemView.findViewById(R.id.container); } } }
Das Endeffekt sieht so aus:Hat jemand eine Idee wie man den ViewPagerAdapter anbinden muss oder was ich falsch mache?
(Es ist für mich sehr wichtig die Antworten zu erklären, denn ich möchte eine Lösung, aber ich möchte es auch verstehen)
-
Warum zweimal Intent ?
startService(new Intent(new Intent(PlayerClient.this, MediaPlayerService.class)));
War ein copy-paste Fehler.
Ich habe das ganze etwas nachgebessert, es gibt jetzt onStartCommand. Ich zeige es vielleicht einamal:
Das ist mein Client (die Activity)
Code
Alles anzeigen/** * MediaPlayer client. Communicates with the MediaPlayerService */ public class MediaPlayer extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.player_client); Button play = findViewById(R.id.play); Button pause = findViewById(R.id.pause); play.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(MediaPlayer.this, MediaPlayerService.class)); } }); pause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(MediaPlayer.this, MediaPlayerService.class)); } }); } }
Das ist mein Service:
Code
Alles anzeigen/** * Handles client requests and the media player service. */ public class MediaPlayerService extends Service { MediaPlayer mp = new MediaPlayer(); @Override public int onStartCommand(Intent intent, int flags, int startId) { mp.create(this, Settings.System.DEFAULT_RINGTONE_URI); mp.setLooping(true); mp.start(); return Service.START_STICKY; } @Override public void onDestroy(){ super.onDestroy(); mp.stop(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
Wenn der Button "Play" gedruckt wird, kommt folgender Error:
E/MediaPlayerNative: start called in state 1, mPlayer(0x0)
error (-38, 0)
E/MediaPlayer: Error (-38,0) -
Moin,
ich bin gerade dabei einen Audioplayer zu coden und bin auf einige offene Fragen gestoßen... Habe etwas rumgegoogelt, aber alles was ich gefunden habe, hat mich nicht zufireden gestellt. Die eine oder andere Lösung hätte vielleicht mein Problem gelöst, aber das hilft mir nicht wirklich, wenn ich das nicht nachvollziehen kann.
Ich habe mich dazu entschieden den Audioplayer als Service umzusetzen, da ich einen Soundboard, bzw. background Soundmixer programmieren möchte und denke, dass ich mit einem Service besser darstehe, als mit einer AudioPlayer Activity. Nun habe ich eine Activity erstellt, die den Service zwar aufruft, aber die Dateien werden nicht abgespielt, kann das noch nicht so richtig nachvollziehen warum. Ich zeige euch mal vielleicht den Code und ihr hilft mir das Problem zu lokalisieren
Das ist der Inhalt der onCreate() Methode in meiner Activity. Hier sollte der Service gestartet werden.
Code
Alles anzeigenButton play = findViewById(R.id.play); Button pause = findViewById(R.id.pause); play.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startService(new Intent(new Intent(PlayerClient.this, MediaPlayerService.class))); } }); pause.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { stopService(new Intent(new Intent(PlayerClient.this, MediaPlayerService.class))); } });
Das hier ist der MediaPlayerService
Code
Alles anzeigenMediaPlayer mediaPlayer; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate(){ System.out.println("started"); mediaPlayer = new MediaPlayer(); mediaPlayer.create(getApplicationContext(), R.raw.song); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { mp.start(); } }); } @Override public void onDestroy() { System.out.println("stopped"); super.onDestroy(); if (mediaPlayer != null) mediaPlayer.release(); }
Die Datei "song.mp3" in res/raw habe ich hinterlegt. Die system.outs erscheinen in der console. Das Service in AndroidManifest.xml ist da. Wo ist also das Problem?