简体   繁体   中英

force close an activity in kitkat & lollipop but work in jellybean?

this is an app that play music simultaneously on multiple Android device whith wifi connections

there is 2 sections, one is dj player mode (the device that play music) and the other one is speaker mode

dj play mode activity work good on android jelly bean (4.1,4.2,4.3) but on newer versions (4.4,5) force close occur

what is the problem?

the dj player activity

package com.example.musicsaround.dj;

import java.io.File;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ChannelListener;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import com.example.musicsaround.R;
import com.example.musicsaround.Timer;
import com.example.musicsaround.Utilities;
import com.example.musicsaround.dj.ServerDeviceListFragment.DJFragmentListener;

public class DJActivity extends Activity implements ChannelListener,
        DJFragmentListener
{
    public final static int DJ_MODE = 15;

    public static final String TAG = "DJ Mode Activity";
    private WifiP2pManager manager;
    private boolean channelRetried = false;
    private boolean isWifiP2pEnabled = false;
    private BroadcastReceiver receiver = null;
    ProgressDialog progressDialog = null;

    private Timer timer;

    private CountDownTimer keepAliveTimer;
    // Keep the Wifi Alive every 5 seconds
    private static final int KEEPALIVE_INTERVAL = 5000;

    // critical component for Wi-fi Direct connectivity
    private Channel channel;

    private final IntentFilter intentFilter = new IntentFilter();

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

        // need these intent filters to catch the Wi-fi direct events
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        intentFilter
                .addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        intentFilter
                .addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);

        manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        channel = manager.initialize(this, getMainLooper(), null);

        TextView txt_time = (TextView) this.findViewById(R.id.txt_dj_time);

        // start a timer with 25 ms precision
        this.timer = new Timer(Timer.DEFAULT_TIMER_PRECISION);
        // asynchronous call to start a timer
        this.timer.startTimer();

        keepAliveTimer = new CountDownTimer(KEEPALIVE_INTERVAL,
                KEEPALIVE_INTERVAL)
        {

            @Override
            public void onTick(long millisUntilFinished)
            {
            }

            @Override
            public void onFinish()
            {
                enableWifi();
                keepAliveTimer.start();
            }
        };
    }

    /** register the BroadcastReceiver with the intent values to be matched */
    @Override
    public void onResume()
    {
        super.onResume();
        receiver = new ServerWiFiDirectBR(manager, channel, this);
        registerReceiver(receiver, intentFilter);

        // ***Start discovering right away!
        discoverDevices();
        keepAliveTimer.start();
    }

    public void enableWifi()
    {
        WifiManager wifiManager = (WifiManager) this
                .getSystemService(this.WIFI_SERVICE);

        wifiManager.setWifiEnabled(true);
    }

    /**
     * UI to show the discovery process
     */
    public void onInitiateDiscovery()
    {
        if (progressDialog != null && progressDialog.isShowing())
        {
            progressDialog.dismiss();
        }

        progressDialog = ProgressDialog.show(this, "Press back to cancel",
                "finding peers", true, true,
                new DialogInterface.OnCancelListener()
                {
                    @Override
                    public void onCancel(DialogInterface dialog)
                    {
                        // stop discovery
                        manager.stopPeerDiscovery(channel,
                                new WifiP2pManager.ActionListener()
                                {
                                    @Override
                                    public void onFailure(int reason)
                                    {
                                        // Toast.makeText(DJActivity.this,
                                        // "Stopping Discovery Failed : " +
                                        // reason,
                                        // Toast.LENGTH_SHORT).show();
                                        Log.e(TAG,
                                                "Stopping Discovery Failed. Error Code is: "
                                                        + reason);
                                    }

                                    @Override
                                    public void onSuccess()
                                    {
                                        Log.d(TAG, "Discovery stopped.");
                                    }
                                });
                    }
                });
    }

    public void discoverDevices()
    {
        // TODO: need a better non-blocking UI to notify users we are
        // discovering
        // onInitiateDiscovery();

        // first turn on the wifi p2p
        enableWifi();

        channelRetried = false;

        manager.discoverPeers(channel, new WifiP2pManager.ActionListener()
        {
            @Override
            public void onSuccess()
            {
                // Toast.makeText(DJActivity.this,
                // "Discovery Initiated",
                // Toast.LENGTH_SHORT).show();

                Log.d(TAG, "Discovery Initiated.");
            }

            // if we failed, then stop the discovery and start again
            @Override
            public void onFailure(int reasonCode)
            {
                Log.e(TAG, "Discovery Failed. Error Code is: " + reasonCode);
                manager.stopPeerDiscovery(channel,
                        new WifiP2pManager.ActionListener()
                        {
                            @Override
                            public void onFailure(int reason)
                            {
                                // Toast.makeText(DJActivity.this,
                                // "Stopping Discovery Failed : " + reason,
                                // Toast.LENGTH_SHORT).show();
                                Log.e(TAG,
                                        "Stopping Discovery Failed. Error Code is: "
                                                + reason);
                            }

                            @Override
                            public void onSuccess()
                            {
                                manager.discoverPeers(channel,
                                        new WifiP2pManager.ActionListener()
                                        {
                                            @Override
                                            public void onSuccess()
                                            {
                                                // Toast.makeText(DJActivity.this,
                                                // "Discovery Initiated",
                                                // Toast.LENGTH_SHORT)
                                                // .show();

                                                Log.d(TAG,
                                                        "Discovery Initiated.");
                                            }

                                            @Override
                                            public void onFailure(int reasonCode)
                                            {
                                                Log.e(TAG,
                                                        "Discovery Failed. Error Code is: "
                                                                + reasonCode);
                                            }
                                        });
                            }
                        });
            }
        });
    }

    @Override
    public void onPause()
    {
        super.onPause();
        unregisterReceiver(receiver);

        keepAliveTimer.cancel();
    }

    @Override
    public void onDestroy()
    {
        disconnect();

        super.onDestroy();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.wifidirect_less, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch (item.getItemId())
        {
            case R.id.atn_direct_enable:
                if (manager != null && channel != null)
                {
                    // Since this is the system wireless settings activity, it's
                    // not going to send us a result. We will be notified by
                    // WiFiDeviceBroadcastReceiver instead.
                    Intent intent = new Intent();
                    // jump to wi-fi Direct settings
                    intent.setClassName("com.android.settings",
                            "com.android.settings.Settings$WifiP2pSettingsActivity");

                    startActivity(intent);
                }
                else
                {
                    Log.e(TAG, "channel or manager is null");
                }
                return true;

            case R.id.atn_direct_discover:
                discoverDevices();
                return true;

            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * Remove all peers and clear all fields. This is called on
     * BroadcastReceiver receiving a state change event. This is merely an UI
     * update.
     */
    public void resetDeviceList()
    {
        ServerDeviceListFragment fragmentList = (ServerDeviceListFragment) getFragmentManager()
                .findFragmentById(R.id.frag_djs_devices);

        if (fragmentList != null)
        {
            fragmentList.clearPeers();
        }
    }

    @Override
    public void onChannelDisconnected()
    {
        // we will try once more
        if (manager != null && !channelRetried)
        {
            Toast.makeText(this, "Wi-fi Direct Channel lost. Trying again...",
                    Toast.LENGTH_LONG).show();
            resetDeviceList();

            channelRetried = true;
            manager.initialize(this, getMainLooper(), this);
        }
        else
        {
            Toast.makeText(
                    this,
                    "Wi-fi Direct Channel is still lost. Try disabling / re-enabling Wi-fi Direct in the P2P Settings.",
                    Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void showDetails(WifiP2pDevice device)
    {
        // TODO: This is for debugging, showing the device details
        DJMusicFragment fragMusic = (DJMusicFragment) getFragmentManager()
                .findFragmentById(R.id.frag_dj_music);
    }

    @Override
    public void showInfo(WifiP2pInfo info)
    {
        DJMusicFragment fragMusic = (DJMusicFragment) getFragmentManager()
                .findFragmentById(R.id.frag_dj_music);

        if (info.isGroupOwner)
        {
            // fragMusic.setDebugText("I am the group owner.");
        }
        else
        {
            // fragMusic.setDebugText("I am not the group owner.");
        }
    }

    /*
     * Cancel an ongoing connection in progress. We won't actually use this
     * method all that much
     * 
     * (non-Javadoc)
     * 
     * @see
     * com.example.musicsaround.dj.ServerDeviceListFragment.DJFragmentListener
     * #cancelDisconnect()
     */
    @Override
    public void cancelDisconnect()
    {
        /*
         * A cancel abort request by user. Disconnect i.e. removeGroup if
         * already connected. Else, request WifiP2pManager to abort the ongoing
         * request
         */
        if (manager != null)
        {
            Log.d(TAG, "Someone requested a cancel connect!");

            final ServerDeviceListFragment fragment = (ServerDeviceListFragment) getFragmentManager()
                    .findFragmentById(R.id.frag_djs_devices);

            if (fragment.getDevice() == null
                    || fragment.getDevice().status == WifiP2pDevice.CONNECTED)
            {
                // we don't disconnect the whole group... it would be nice just
                // to disconnect that one guy
                // disconnect();
            }
            else if (fragment.getDevice().status == WifiP2pDevice.AVAILABLE
                    || fragment.getDevice().status == WifiP2pDevice.INVITED
                    || fragment.getDevice().status == WifiP2pDevice.CONNECTED)
            {
                manager.cancelConnect(channel, new ActionListener()
                {
                    @Override
                    public void onSuccess()
                    {
                        // Toast.makeText(DJActivity.this,
                        // "Aborting connection",
                        // Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFailure(int reasonCode)
                    {
                        // Toast.makeText(
                        // DJActivity.this,
                        // "Connect abort request failed. Reason Code: "
                        // + reasonCode, Toast.LENGTH_SHORT)
                        // .show();
                        Log.e(TAG,
                                "Could not abort connection, the reason is: "
                                        + reasonCode);
                    }
                });
            }
        }
    }

    /*
     * This is the main method to connect to a device through Wi-Fi Direct!
     * 
     * (non-Javadoc)
     * 
     * @see
     * com.example.musicsaround.dj.ServerDeviceListFragment.DJFragmentListener
     * #connect(android.net.wifi.p2p.WifiP2pConfig)
     */
    @Override
    public void connect(WifiP2pConfig config)
    {
        if (manager == null)
        {
            return;
        }

        // in DJ mode, we want to become the group owner
        WifiP2pConfig newConfig = config;
        newConfig.groupOwnerIntent = DJ_MODE;

        manager.connect(channel, newConfig, new ActionListener()
        {
            @Override
            public void onSuccess()
            {
                // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
            }

            @Override
            public void onFailure(int reason)
            {
                Toast.makeText(DJActivity.this,
                        "Connection failed. Retrying...", Toast.LENGTH_SHORT)
                        .show();
                Log.e(TAG,
                        "Wi-fi Direct connection failed. The error code is: "
                                + reason);
            }
        });
    }

    @Override
    public void disconnect()
    {
        if (manager == null)
        {
            return;
        }

        // TODO: why do we have to remove the whole group upon disconnect?
        // perhaps we only need to do so upon exiting DJ mode
        manager.removeGroup(channel, new ActionListener()
        {
            @Override
            public void onFailure(int reasonCode)
            {
                Log.e(TAG, "Disconnect failed. Reason is: " + reasonCode);

            }

            @Override
            public void onSuccess()
            {
                Toast.makeText(DJActivity.this, "Disconnected a device.",
                        Toast.LENGTH_SHORT).show();
                Log.d(TAG, "Disconnected from a device.");
            }
        });
    }

    /**
     * @param isWifiP2pEnabled
     *            the isWifiP2pEnabled to set
     */
    public void setIsWifiP2pEnabled(boolean isWifiP2pEnabled)
    {
        this.isWifiP2pEnabled = isWifiP2pEnabled;
    }

    public void playRemoteMusic(Uri musicFileURI, long startTime, int startPos)
    {
        ServerDeviceListFragment fragmentList = (ServerDeviceListFragment) getFragmentManager()
                .findFragmentById(R.id.frag_djs_devices);

        // convert URI to actual file path
        Uri filePathFromActivity = Uri.parse(Utilities.getRealPathFromUri(
                (Activity) this, musicFileURI));

        File audioFile = new File(filePathFromActivity.getPath());

        fragmentList.playMusicOnClients(audioFile, startTime, startPos);
    }

    public void playRemoteMusic(String musicFilePath, long startTime,
            int startPos)
    {
        ServerDeviceListFragment fragmentList = (ServerDeviceListFragment) getFragmentManager()
                .findFragmentById(R.id.frag_djs_devices);

        File audioFile = new File(musicFilePath);

        fragmentList.playMusicOnClients(audioFile, startTime, startPos);
    }

    public void stopRemoteMusic()
    {
        ServerDeviceListFragment fragmentList = (ServerDeviceListFragment) getFragmentManager()
                .findFragmentById(R.id.frag_djs_devices);
        fragmentList.stopMusicOnClients();
    }

    public Timer getTimer()
    {
        return timer;
    }
}

songsmanager:

package com.example.musicsaround;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.HashMap;

public class SongsManager {
    // SDCard Path
    final String MEDIA_PATH = new String("/sdcard/Download");
    private ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();

    // Constructor
    public SongsManager(){

    }

    /**
     * Function to read all mp3 files from sdcard
     * and store the details in ArrayList
     * */
    public ArrayList<HashMap<String, String>> getPlayList(){
        File home = new File(MEDIA_PATH);

        if (home.listFiles(new FileExtensionFilter()).length > 0) {
            for (File file : home.listFiles(new FileExtensionFilter())) {
                HashMap<String, String> song = new HashMap<String, String>();
                song.put("songTitle", file.getName().substring(0, (file.getName().length() - 4)));
                song.put("songPath", file.getPath());

                // Adding each song to SongList
                songsList.add(song);
            }
        }
        // return songs list array
        return songsList;
    }

    /**
     * Class to filter files which are having .mp3 extension
     * */
    class FileExtensionFilter implements FilenameFilter {
        public boolean accept(File dir, String name) {
            return (name.endsWith(".mp3") || name.endsWith(".MP3"));
        }
    }
}

and logcat errors:

10-19 02:07:55.147: E/AndroidRuntime(1521): Process: com.example.musicsaround, PID: 1521
10-19 02:07:55.147: E/AndroidRuntime(1521): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.musicsaround/com.example.musicsaround.dj.DJActivity}: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2184)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2233)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread.access$800(ActivityThread.java:135)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.os.Handler.dispatchMessage(Handler.java:102)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.os.Looper.loop(Looper.java:136)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread.main(ActivityThread.java:5001)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at java.lang.reflect.Method.invokeNative(Native Method)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at java.lang.reflect.Method.invoke(Method.java:515)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at dalvik.system.NativeStart.main(Native Method)
10-19 02:07:55.147: E/AndroidRuntime(1521): Caused by: android.view.InflateException: Binary XML file line #13: Error inflating class fragment
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.Activity.setContentView(Activity.java:1929)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.example.musicsaround.dj.DJActivity.onCreate(DJActivity.java:62)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.Activity.performCreate(Activity.java:5231)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2148)
10-19 02:07:55.147: E/AndroidRuntime(1521):     ... 11 more
10-19 02:07:55.147: E/AndroidRuntime(1521): Caused by: java.lang.NullPointerException
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.example.musicsaround.SongsManager.getPlayList(SongsManager.java:25)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at com.example.musicsaround.dj.DJMusicFragment.onCreateView(DJMusicFragment.java:126)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.Fragment.performCreateView(Fragment.java:1700)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:866)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1040)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1142)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.app.Activity.onCreateView(Activity.java:4786)
10-19 02:07:55.147: E/AndroidRuntime(1521):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:689)

Its right in your log:

9 02:07:55.147: E/AndroidRuntime(1521): Caused by: java.lang.NullPointerException 10-19 02:07:55.147: E/AndroidRuntime(1521): at com.example.musicsaround.SongsManager.getPlayList(SongsManager.java:25) 10-19 02:07:55.147: E/AndroidRuntime(1521): at com.example.musicsaround.dj.DJMusicFragment.onCreateView(DJMusicFragment.java:126)

You got NullPointerException at line 25 in your SongsManager class at getPlayList method.

you can using FrameLayout instead of fragment

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".DJActivity" >

    <FrameLayout
        android:id="@+id/frag_dj_music"
        android:name="com.example.musicsaround.dj.DJMusicFragment"
        android:layout_width="match_parent"
        android:layout_height="300dp" />

    <FrameLayout
        android:id="@+id/frag_djs_devices"
        android:name="com.example.musicsaround.dj.ServerDeviceListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/txt_dj_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="DJ Time" />

</LinearLayout>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM