问:
How to debug nsis script? 3.05-2 gives error: Error: unterminated string parsing line at macro:_IncludeStrFunction
How to debug nsis script?

I have upgraded from Ubuntu 19.10 to 20.04 which seems to update nsis from v3.04-1 to v3.05-2. Now I get an error with my script:

```<code># makensis installer.nsi
Processing config: /etc/nsisconf.nsh
Processing script file: "installer.nsi" (UTF8)
Error: unterminated string parsing line at macro:_IncludeStrFunction:7
Error in macro _IncludeStrFunction on macroline 7
!include: error in script: "../src/other/EnvVarUpdate.nsh" on line 49
Error in script "installer.nsi" on line 2 -- aborting creation process
</code>```

My script is this:

```<code>OutFile speedata-publisher-windows-386-3.9.14-installer.exe
!include "../src/other/EnvVarUpdate.nsh"
InstallDir $PROGRAMFILES\speedata-publisher
DirText "This will install speedata Publisher on your computer. Choose a directory"

Section
SetOutPath $INSTDIR
RMDir /r /REBOOTOK $INSTDIR
File /r /tmp/publisher-git/build/speedata-publisher\*.*
${EnvVarUpdate} $0 "PATH" "A" "HKCU" "$INSTDIR\bin"
WriteUninstaller $INSTDIR\Uninstall.exe
MessageBox MB_OK "Run speedata Publisher with 'sp' on the command.com prompt"
SectionEnd

Section "Uninstall"
${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin"
RMDir /r /REBOOTOK $INSTDIR
SectionEnd
</code>```

and the EnvVarUpdate.nsh is from https://nsis.sourceforge.io/Environmental_Variables:_append,_prepend,_and_remove_entries

The line 49 in this script is !insertmacro _IncludeStrFunction StrTok

The output of my command with the previous version 3.04-1 is:

```<code>Processing config: /etc/nsisconf.nsh
Processing script file: "build/installer.nsi" (UTF8)

Processed 1 file, writing output (x86-ansi):

Output: "/tmp/publisher-git/build/speedata-publisher-windows-386-3.9.14-installer.exe"
Install: 2 pages (128 bytes), 1 section (4120 bytes), 1139 instructions (31892 bytes), 647 strings (11565 bytes), 1 language table (230 bytes).
Uninstall: 1 page (128 bytes), 1 section (4120 bytes), 385 instructions (10780 bytes), 100 strings (1387 bytes), 1 language table (194 bytes).
Datablock optimizer saved 650630 bytes (~1.8%).

Using zlib compression.

EXE header size:               75264 / 76288 bytes
Install code:                  10537 / 45255 bytes
Install data:               34526923 / 62531730 bytes
Uninstall code+data:            2665 / 3163 bytes
CRC (0xFE2E922E):                  4 / 4 bytes

Total size:                 34615393 / 62656440 bytes (55.2%)
</code>```

I am not really into nsis scripts, so I would like to know how to find where the problem could be.

答:
There was a change to how StrFunc works internally and the 3rd-party EnvVarUpdate.nsh file from the Wiki is incompatible with it.

As discussed here, you could try fixing EnvVarUpdate.nsh by changing  !define un.${StrFuncName} "${Un${StrFuncName}}" to
!define un.${StrFuncName} '${Un${StrFuncName}}'.

Instead of manually patching that file, I would recommend that you use the EnVar plug-in as a replacement.

Body:
How to debug nsis script?

I have upgraded from Ubuntu 19.10 to 20.04 which seems to update nsis from v3.04-1 to v3.05-2. Now I get an error with my script:

# makensis installer.nsi
Processing config: /etc/nsisconf.nsh
Processing script file: "installer.nsi" (UTF8)
Error: unterminated string parsing line at macro:_IncludeStrFunction:7
Error in macro _IncludeStrFunction on macroline 7
!include: error in script: "../src/other/EnvVarUpdate.nsh" on line 49
Error in script "installer.nsi" on line 2 -- aborting creation process

My script is this:

OutFile speedata-publisher-windows-386-3.9.14-installer.exe
!include "../src/other/EnvVarUpdate.nsh"
InstallDir $PROGRAMFILES\speedata-publisher
DirText "This will install speedata Publisher on your computer. Choose a directory"

Section
SetOutPath $INSTDIR
RMDir /r /REBOOTOK $INSTDIR
File /r /tmp/publisher-git/build/speedata-publisher\*.*
${EnvVarUpdate} $0 "PATH" "A" "HKCU" "$INSTDIR\bin"
WriteUninstaller $INSTDIR\Uninstall.exe
MessageBox MB_OK "Run speedata Publisher with 'sp' on the command.com prompt"
SectionEnd

Section "Uninstall"
${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin"
RMDir /r /REBOOTOK $INSTDIR
SectionEnd

and the EnvVarUpdate.nsh is from https://nsis.sourceforge.io/Environmental_Variables:_append,_prepend,_and_remove_entries

The line 49 in this script is !insertmacro _IncludeStrFunction StrTok

The output of my command with the previous version 3.04-1 is:

Processing config: /etc/nsisconf.nsh
Processing script file: "build/installer.nsi" (UTF8)

Processed 1 file, writing output (x86-ansi):

Output: "/tmp/publisher-git/build/speedata-publisher-windows-386-3.9.14-installer.exe"
Install: 2 pages (128 bytes), 1 section (4120 bytes), 1139 instructions (31892 bytes), 647 strings (11565 bytes), 1 language table (230 bytes).
Uninstall: 1 page (128 bytes), 1 section (4120 bytes), 385 instructions (10780 bytes), 100 strings (1387 bytes), 1 language table (194 bytes).
Datablock optimizer saved 650630 bytes (~1.8%).

Using zlib compression.

EXE header size:               75264 / 76288 bytes
Install code:                  10537 / 45255 bytes
Install data:               34526923 / 62531730 bytes
Uninstall code+data:            2665 / 3163 bytes
CRC (0xFE2E922E):                  4 / 4 bytes

Total size:                 34615393 / 62656440 bytes (55.2%)

I am not really into nsis scripts, so I would like to know how to find where the problem could be.


来源: stackexchange

问:
PHP Multiple File Array
I have the following code which works and uploads but it will not cycle through the array to upload every file, just the first file.

```<code><form method="post" enctype="multipart/form-data" action="http://<?php echo $pageURL;?>">
<input class="new" multiple="multiple" name="documents[]" type="file" />
<input class="new" multiple="multiple" name="documents[]" type="file" />
<input type="submit" class="button" name="addMaterials" value="Add" />

<?php

    foreach($_FILES['documents']['tmp_name'] as $key => $tmp_name)
        {
            $file_name = $key.$_FILES['documents']['name'][$key];
            $file_size =$_FILES['documents']['size'][$key];
            $file_tmp =$_FILES['documents']['tmp_name'][$key];
            $file_type=$_FILES['documents']['type'][$key];
            move_uploaded_file($file_tmp,"files/".time().$file_name);
        }
?>
</code>```

I need it to cycle through my documents[] file array.

Example print_r() of the documents array:

```<code>Array (
    [name] => Array ( [0] => AcroRd32.exe )
    [type] => Array ( [0] => application/x-msdownload )
    [tmp_name] => Array ( [0] => C:\xampp\tmp\phpE8BD.tmp )
    [error] => Array ( [0] => 0 )
    [size] => Array ( [0] => 1343112 )
    )
</code>```

Any help appreciated.

答:
it's easy to upload multiple files, follow these steps.

use array notation means square brackets with the name of the input like this

<input type="file" id="indtbl_logo[]" name="indtbl_logo[]" multiple />

you can loop throught this using $_FILES Global Variable

    foreach ($_FILES['indtbl_logo']['tmp_name'] as $key => $tmp_name) {
        $file_name = $key . $_FILES['indtbl_logo']['name'][$key];
        $file_size = $_FILES['indtbl_logo']['size'][$key];
        $file_tmp = $_FILES['indtbl_logo']['tmp_name'][$key];
        $file_type = $_FILES['indtbl_logo']['type'][$key];

        echo $file_name;
        echo "
";
    }
```

ContentLicense: CC BY-SA 3.0

Title: PHP Multiple File Array

Body:
I have the following code which works and uploads but it will not cycle through the array to upload every file, just the first file.

<form method="post" enctype="multipart/form-data" action="http://<?php echo $pageURL;?>">
<input class="new" multiple="multiple" name="documents[]" type="file" />
<input class="new" multiple="multiple" name="documents[]" type="file" />
<input type="submit" class="button" name="addMaterials" value="Add" />

<?php

    foreach($_FILES['documents']['tmp_name'] as $key => $tmp_name)
        {
            $file_name = $key.$_FILES['documents']['name'][$key];
            $file_size =$_FILES['documents']['size'][$key];
            $file_tmp =$_FILES['documents']['tmp_name'][$key];
            $file_type=$_FILES['documents']['type'][$key];
            move_uploaded_file($file_tmp,"files/".time().$file_name);
        }
?>

I need it to cycle through my documents[] file array.

Example print_r() of the documents array:

Array (
    [name] => Array ( [0] => AcroRd32.exe )
    [type] => Array ( [0] => application/x-msdownload )
    [tmp_name] => Array ( [0] => C:\xampp\tmp\phpE8BD.tmp )
    [error] => Array ( [0] => 0 )
    [size] => Array ( [0] => 1343112 )
    )

Any help appreciated.

Body:
it's easy to upload multiple files, follow these steps.

use array notation means square brackets with the name of the input like this

<input type="file" id="indtbl_logo[]" name="indtbl_logo[]" multiple />

you can loop throught this using $_FILES Global Variable

    foreach ($_FILES['indtbl_logo']['tmp_name'] as $key => $tmp_name) {
        $file_name = $key . $_FILES['indtbl_logo']['name'][$key];
        $file_size = $_FILES['indtbl_logo']['size'][$key];
        $file_tmp = $_FILES['indtbl_logo']['tmp_name'][$key];
        $file_type = $_FILES['indtbl_logo']['type'][$key];

        echo $file_name;
        echo "<br>";
    }

ContentLicense: CC BY-SA 4.0


问:
What does it mean that Conda and Pip cannot be used interchangeably?
Some time ago, I installed Django (with pip) and had some trouble doing some things with it because I didn't create a virtual environment (at least that's what it looked like). That time I was recommended to install it with conda since I use Anaconda's spyder.

Now, with a new Windows installation, I'm trying to start to learn Django again, but I'm confused as to whether I should use conda or pip to install it. I read here What is the difference between pip and conda? that they cannot be used interchangeably, but I'm not sure what that means.

If I install Django and some other packages with conda, does that mean I have to do something extra to then install some package with pip? Say, if there is a package conda can't install, as I read in that same question.

They said that conda "also creates a virtual environment`, does that mean that every time I install something with it, it is not being installed globally and besides the installation I also set up its virtual environment?

Thank you very much.

答:
Installing a conda package without activating an environment installs the package to conda's default virtual environment, called base. I'd recommend you read up on how virtual environments work and prevent package conflicts.

You can install a python package in a conda environment using pip. Just activate that environment and use pip install package_name as you would normally do. You should however avoid this by first making sure the package is unavailable in any of the conda repositories.


问:
Make date_range of hourly frequency over multiple years for a selected month
I understand how to make a date_range in pandas using the freq option.  However, I do not know how to use it to do two frequencies at once (or do I need a loop for this)?

I am trying to make an hourly date range for only july for a span over some years.

I have tried:

```<code>In:  pd.date_range('1951-07-01','1955-07-01',freq='AS')
Out: DatetimeIndex(['1952-01-01', '1953-01-01', '1954-01-01', '1955-01-01'], dtype='datetime64[ns]', freq='AS-JAN')
</code>```

And also the hourly frequency.. But what I want is a date range that spans over multiple years, but only an hourly frequency for the month of july.

I do not want any months other than july in my date_range.

Any hints are appreciated, and if a loop is necessary?

Body:
I understand how to make a date_range in pandas using the freq option.  However, I do not know how to use it to do two frequencies at once (or do I need a loop for this)?

I am trying to make an hourly date range for only july for a span over some years.

I have tried:

In:  pd.date_range('1951-07-01','1955-07-01',freq='AS')
Out: DatetimeIndex(['1952-01-01', '1953-01-01', '1954-01-01', '1955-01-01'], dtype='datetime64[ns]', freq='AS-JAN')

And also the hourly frequency.. But what I want is a date range that spans over multiple years, but only an hourly frequency for the month of july.

I do not want any months other than july in my date_range.

Any hints are appreciated, and if a loop is necessary?

Body:
You can create hours frequency with start and end year and then filter only julys:

d = pd.date_range('1951-07-01','1955-07-01',freq='H')

d = d[d.month == 7]
print (d)
DatetimeIndex(['1951-07-01 00:00:00', '1951-07-01 01:00:00',
               '1951-07-01 02:00:00', '1951-07-01 03:00:00',
               '1951-07-01 04:00:00', '1951-07-01 05:00:00',
               '1951-07-01 06:00:00', '1951-07-01 07:00:00',
               '1951-07-01 08:00:00', '1951-07-01 09:00:00',
               ...
               '1954-07-31 15:00:00', '1954-07-31 16:00:00',
               '1954-07-31 17:00:00', '1954-07-31 18:00:00',
               '1954-07-31 19:00:00', '1954-07-31 20:00:00',
               '1954-07-31 21:00:00', '1954-07-31 22:00:00',
               '1954-07-31 23:00:00', '1955-07-01 00:00:00'],
              dtype='datetime64[ns]', length=2977, freq=None)


问:
NPDA for L= {w ∈ {a,b}*: number of a's is twice the number of b's}
I have been trying to find a NPDA for this language but I can't come up with anything that will accept all of the words in the language. I did try making its accepting condition an empty stack and using the stack alphabet {$ a b} but maybe I should try something else?</p>

答:
Maybe you are looking the equivalent Grammar for the given Regular Expression.

If so maybe this one with the following productions:

```<code>S->AAb | SAAb | ASAb | AASb | AAbS
A->a
</code>```

Some Tests:

```<code>aab : S->AAb->aAb->aab
aaaabb : S-> AASb -> AA(AAb)b -> aaaabb
</code>```

Could check also with other example and see if fit on all cases.

If fine always should have on
 Result = (2*count_of_b) for a, count_b

Looking twice, A->a can be removed and have only:

```<code>S->aab|Saab|aSab|aaSb|aabS
</code>```

Test:

```<code>aaaabb : aaSb(S_4)->aaaabb(S_1), etc.
</code>```

Body:
Maybe you are looking the equivalent Grammar for the given Regular Expression.

If so maybe this one with the following productions:

S->AAb | SAAb | ASAb | AASb | AAbS
A->a

Some Tests:

aab : S->AAb->aAb->aab
aaaabb : S-> AASb -> AA(AAb)b -> aaaabb

Could check also with other example and see if fit on all cases.

If fine always should have on
 Result = (2*count_of_b) for a, count_b

Looking twice, A->a can be removed and have only:

S->aab|Saab|aSab|aaSb|aabS

Test:

aaaabb : aaSb(S_4)->aaaabb(S_1), etc.


问:
How do I solve this 'Launching Box2DBuild' error when creating a new libgdx project?
'Launching Box2DBuild' has encountered a problem.

Launch configuration Box2DBuild references closed project my-gdx-game-core

I don't know why I keep getting this error whenever I try to create a new libgdx project.

I've included a screenshot of the settings I used to create the project. Do I need to install Box2D, or does that come pre-installed?

I'm using Eclipse as my IDE.

答: I think I found a solution. If you go in Run Configurations and change the Main Class to the DesktopLauncher, it should run fine.</p>


问:
Detecting scroll direction
So I am trying to use the JavaScript on scroll to call a function. But I wanted to know if I could detect the direction of the the scroll without using jQuery. If not then are there any workarounds?

I was thinking of just putting a 'to top' button but would like to avoid that if I could.

I have now just tried using this code but it didn't work:

```<code>if document.body.scrollTop <= 0 {
    alert ("scrolling down")
} else {
    alert ("scrolling up")
}
</code>```

答:
This simple code would work: Check the console for results.</p>

```<code>let scroll_position = 0;
let scroll_direction;

window.addEventListener('scroll', function(e){
    scroll_direction = (document.body.getBoundingClientRect()).top > scroll_position ? 'up' : 'down';
    scroll_position = (document.body.getBoundingClientRect()).top;
    console.log(scroll_direction);
});
</code>```

Title: Detecting scroll direction

Body:
So I am trying to use the JavaScript on scroll to call a function. But I wanted to know if I could detect the direction of the the scroll without using jQuery. If not then are there any workarounds?

I was thinking of just putting a 'to top' button but would like to avoid that if I could.

I have now just tried using this code but it didn't work:

if document.body.scrollTop <= 0 {
    alert ("scrolling down")
} else {
    alert ("scrolling up")
}

Body:
This simple code would work: Check the console for results.

let scroll_position = 0;
let scroll_direction;

window.addEventListener('scroll', function(e){
    scroll_direction = (document.body.getBoundingClientRect()).top > scroll_position ? 'up' : 'down';
    scroll_position = (document.body.getBoundingClientRect()).top;
    console.log(scroll_direction);
});


问:
Why json hijacking can be prevented using POST method?
I came across the following ASP.NET MVC error, when returning json in a Get method:

This request has been blocked because sensitive information could be
  disclosed to third party web sites when this is used in a GET request.
  To allow GET requests, set JsonRequestBehavior to AllowGet.

Apparently this vulnerability is called json Hijacking. This article explains that a website could be exploited when returning json using Get. But returning json in a Post method is safe.

Why changing Get to Post prevents this attack?

Body:
If you open the network panel on any webpage that contains scripts, images, stylesheets or fonts you will see that all those requests are done using GET HTTP method. For example this is how a request for a file loaded by a <script> tag looks like:

And this is an example for an file loaded by an <img> tag looks like:

Browser will just blindly trust you that if you are loading such a resource from anywhere you know what you are doing and it will fetch it for you (otherwise things like CDN would not work) as opposed to an XHR request!

XHR requests (including fetch calls) are checked against CORS policy, I believe you are familiar with what that is. JavaScript will not be able to make any XHR request for a resource that lives on a different domain (or port etc.).

So you have two types of request policies:

Anything you fetch using XHR will be checked against CORS but you can pick whatever HTTP request method you want

Anything you load using img, script, link etc will not be checked against CORS policy but you are restricted to GET HTTP requests only. The browser will also send all the cookies along, most importantly the authentication ones in this case.

That means that if you are serving a JSON array using GET you can use a script tag to fetch it for you no matter which domain you are on. Then, using the trick mentioned in the article, you can execute the array (sounds weird but yes) and grab the sensitive information.

If you'd be using POST, the attacker has no way of using a script (or any other) tag to perform this request since they use GET requests to fetch resources.

You could think Ah but I can use form to do that! but you will run into the same CORS issues. If you just submit a form, the JSON data will load into the current page and there is no way for you as an attacker to get it since your script no longer exists on the page.

You could think Ah I just set the form target to an iframe! but JavaScript will not allow you to access anything within that iframe.

Does that make sense?


问:
move_uploaded_file failed to open stream: Permission denied - Mac
While i am trying to move_uploaded_file in php with following code :

```<code>if(is_uploaded_file($_FILES['fileupload2']['tmp_name'])){

        move_uploaded_file($_FILES['fileupload2']['tmp_name'], "images/".$_FILES['fileupload2']['name']);

    }
</code>```

I've got this error saying:

```<code>Warning: move_uploaded_file(images/VIDEO_TS.VOB): failed to open stream: Permission denied in /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php on line 24
</code>```

i tried in the terminal and didn't work:

```<code>sudo CHMOD 775 /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php

sudo chmod -R 0755 /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php

sudo chown nobody /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php
</code>```

I am still getting the error and i am using Yosemite, any other solution ?

答: I am using ubuntu and once I have encounter this problem, I have solved this problem by changing all the access permissions of the folder in which I want to move the files to 'create and delete files'. See below screenshot:

Body:
While i am trying to move_uploaded_file in php with following code :

if(is_uploaded_file($_FILES['fileupload2']['tmp_name'])){

        move_uploaded_file($_FILES['fileupload2']['tmp_name'], "images/".$_FILES['fileupload2']['name']);

    }

I've got this error saying:

Warning: move_uploaded_file(images/VIDEO_TS.VOB): failed to open stream: Permission denied in /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php on line 24

i tried in the terminal and didn't work:

sudo CHMOD 775 /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php

sudo chmod -R 0755 /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php

sudo chown nobody /Applications/XAMPP/xamppfiles/htdocs/Week3/Lesson2/do_upload.php

I am still getting the error and i am using Yosemite, any other solution ?


问:
Running two python code in parallel from two different directory using Multiprocessing
Below is my code for running two python code in parallel using multiprocessing :

defs.py

```<code>import os

def pro(process):
    #print(process)
    os.system('python {}'.format(process))
</code>```

Multiprocessing.py

```<code>import os
from multiprocessing import Pool
import multiprocessing as mp
import defs
import datetime
import pandas as pd

processes = ('python_code1.py','python_code2.py')

if __name__ == '__main__':
    pool = Pool(processes=4)
    start = datetime.datetime.now()
    print('Start:',start)
    pool.map(defs.pro, processes)
    end = datetime.datetime.now()
    print('End :',end)
    total = end-start
    print('Total :', end-start)
</code>```

This code is running perfectly fine. But my requirement is I need to run the python code 'python_code1.py' and 'python_code2.py' from two different directory.

so I made the below changes in Multiprocessing.py:

```<code>path1 = r'C:\Users\code1\python_code1.py'
path2 = r'C:\Users\code2\python_code2.py'

processes = (path1,path2)
</code>```

but this is not working for me.

My Multiprocessing.py and defs.py are kept on path `C:\Users\Multiprocessing\'

答:
Well an elegant solution using asyncio. It is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc. Plus it has both high-level and low-level APIs to accomodate any kind of problem. And you might find syntax easier as I do:

```<code>import os
import asyncio
    def background(f):
        def wrapped(*args, **kwargs):
            return asyncio.get_event_loop().run_in_executor(None, f, *args, **kwargs)

        return wrapped

    @background
    def pro(process):
    #print(process)
    os.system('python {}'.format(process))

processes = (r'C:\Users\code1\python_code1.py',r'C:\Users\code2\python_code2.py')
for process in processes:
    pro(process)
</code>```

Detailed answer on parallelizing for loop. You might find useful.

Body:
Below is my code for running two python code in parallel using multiprocessing :

defs.py

import os

def pro(process):
    #print(process)
    os.system('python {}'.format(process))

Multiprocessing.py

import os
from multiprocessing import Pool
import multiprocessing as mp
import defs
import datetime
import pandas as pd

processes = ('python_code1.py','python_code2.py')

if __name__ == '__main__':
    pool = Pool(processes=4)
    start = datetime.datetime.now()
    print('Start:',start)
    pool.map(defs.pro, processes)
    end = datetime.datetime.now()
    print('End :',end)
    total = end-start
    print('Total :', end-start)

This code is running perfectly fine. But my requirement is I need to run the python code 'python_code1.py' and 'python_code2.py' from two different directory.

so I made the below changes in Multiprocessing.py:

path1 = r'C:\Users\code1\python_code1.py'
path2 = r'C:\Users\code2\python_code2.py'

processes = (path1,path2)

but this is not working for me.

My Multiprocessing.py and defs.py are kept on path `C:\Users\Multiprocessing\'

Body:
Well an elegant solution using asyncio. It is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc. Plus it has both high-level and low-level APIs to accomodate any kind of problem. And you might find syntax easier as I do:

import os
import asyncio
    def background(f):
        def wrapped(*args, **kwargs):
            return asyncio.get_event_loop().run_in_executor(None, f, *args, **kwargs)

        return wrapped

    @background
    def pro(process):
    #print(process)
    os.system('python {}'.format(process))

processes = (r'C:\Users\code1\python_code1.py',r'C:\Users\code2\python_code2.py')
for process in processes:
    pro(process)

Detailed answer on parallelizing for loop. You might find useful.


问:
Exit android app on back pressed
I am building an Android App. How to exit an Android App when back is pressed. Android version is 2.3.3 and above. The Android App goes to previous activity which i don't want.</p>

答:
```<code>// Finish current activity
// Go back to previous activity or closes app if last activity
finish()

// Finish all activities in stack and app closes
finishAffinity()

// Takes you to home screen but app isnt closed
// Opening app takes you back to this current activity (if it hasnt been destroyed)
Intent(Intent.ACTION_MAIN).apply {
    addCategory(Intent.CATEGORY_HOME)
    flags = Intent.FLAG_ACTIVITY_NEW_TASK
    startActivity(this)
}
</code>```

Title: Exit android app on back pressed


问:
Why I couldn't access object's property?
I'm trying to manipulate Vec2 object's properties (x and y) in onDocumentKeyDown() function which is in event.js. Why I couldn't access vec2's property in onDocumentKeyDown() function?

file: event.js

function onDocumentKeyDown(event, vec2){
    var x_p = vec2.x;    // Uncaught TypeError: Cannot read property 'x' of undefined
    var y_p = vec2.y;
    ...
```

<p>file: app.js</p>

<pre class="lang-js prettyprint-override"><code>function init(){
    ...
    var vec2 = new Vec2(0,0);

    function animate (time) {
        ...

        document.addEventListener("keydown", onDocumentKeyDown, false);
        vec2 = onDocumentKeyDown(event, vec2);
        obj.move(vec2);
        ...
        startTime = time;

        window.requestAnimationFrame(animate);
    }
    animate(0);
}

</code>```

Vec2 class (Vec2.js):

class Vec2{
    x;
    y;
    constructor(x, y){
        this.x = x;
        this.y = y;
    }
    ...
}
```

<p>index.html:</p>

<pre class="lang-html prettyprint-override"><code>    .....
    <script src="vec2.js"></script>
    <script src="lib.js"></script>
    <script src="event.js"></script>
    <script src="app.js"></script>
</body>
</code>```

答:
When you addEventListener as onDocumentKeyDown it is just passed an event value and not the vec2 as argument.

You can use .bind method to pass on the custom arguments. However you would need to change the order in which you receive arguments  like

```<code>   function onDocumentKeyDown(vec2, event){
    var x_p = vec2.x;
    var y_p = vec2.y;
    ...
    }
    function init(){
        ...
        var vec2 = new Vec2(0,0);

        function animate (time) {
            ...
            const fn = onDocumentKeyDown.bind(this, vec2);
            document.addEventListener("keydown", fn , false);
            vec2 = onDocumentKeyDown(vec2, event);
            obj.move(vec2);
            ...
            startTime = time;

            window.requestAnimationFrame(animate);
        }
        animate(0);
    }
</code>```

Since you wouldn't want to change the argument order to onDocumentKeyDown, you can make use of arrow function

```<code>function onDocumentKeyDown(event, vec2){
    var x_p = vec2.x;
    var y_p = vec2.y;
    ...

}

function init(){
    ...
    var vec2 = new Vec2(0,0);

    function animate (time) {
        ...
        const fn = (event) => onDocumentKeyDown(event, vec2);
        document.addEventListener("keydown", fn , false);
        vec2 = onDocumentKeyDown(vec2, event);
        obj.move(vec2);
        ...
        startTime = time;

        window.requestAnimationFrame(animate);
    }
    animate(0);
}
</code>```

P.S. Since you need to pass the same instance of function to removeEventListener that you passed to addEventListener, we can store the binded function to a seperate variable

Body:
I'm trying to manipulate Vec2 object's properties (x and y) in onDocumentKeyDown() function which is in event.js. Why I couldn't access vec2's property in onDocumentKeyDown() function?

file: event.js

function onDocumentKeyDown(event, vec2){
    var x_p = vec2.x;    // Uncaught TypeError: Cannot read property 'x' of undefined
    var y_p = vec2.y;
    ...

file: app.js

function init(){
    ...
    var vec2 = new Vec2(0,0);

    function animate (time) {
        ...

        document.addEventListener("keydown", onDocumentKeyDown, false);
        vec2 = onDocumentKeyDown(event, vec2);
        obj.move(vec2);
        ...
        startTime = time;

        window.requestAnimationFrame(animate);
    }
    animate(0);
}

Vec2 class (Vec2.js):

class Vec2{
    x;
    y;
    constructor(x, y){
        this.x = x;
        this.y = y;
    }
    ...
}

index.html:

    .....

Body:
When you addEventListener as onDocumentKeyDown it is just passed an event value and not the vec2 as argument.

You can use .bind method to pass on the custom arguments. However you would need to change the order in which you receive arguments  like

   function onDocumentKeyDown(vec2, event){
    var x_p = vec2.x;
    var y_p = vec2.y;
    ...
    }
    function init(){
        ...
        var vec2 = new Vec2(0,0);

        function animate (time) {
            ...
            const fn = onDocumentKeyDown.bind(this, vec2);
            document.addEventListener("keydown", fn , false);
            vec2 = onDocumentKeyDown(vec2, event);
            obj.move(vec2);
            ...
            startTime = time;

            window.requestAnimationFrame(animate);
        }
        animate(0);
    }

Since you wouldn't want to change the argument order to onDocumentKeyDown, you can make use of arrow function

function onDocumentKeyDown(event, vec2){
    var x_p = vec2.x;
    var y_p = vec2.y;
    ...

}

function init(){
    ...
    var vec2 = new Vec2(0,0);

    function animate (time) {
        ...
        const fn = (event) => onDocumentKeyDown(event, vec2);
        document.addEventListener("keydown", fn , false);
        vec2 = onDocumentKeyDown(vec2, event);
        obj.move(vec2);
        ...
        startTime = time;

        window.requestAnimationFrame(animate);
    }
    animate(0);
}

P.S. Since you need to pass the same instance of function to removeEventListener that you passed to addEventListener, we can store the binded function to a seperate variable


问:
switch while won't loop
This is part of a program I'm writting. My main porblem is that once it goes trough one of the cases, tit won't loop so it's useless as it is. Any help? (Sorry for the variables in Spanish, also a couple of functions i created appear in the cose which are in the program and work just fine so I don't thin they have anything to do with the problem).</p>

```<code>static void Main(string[] args)
    {
        int minutos_restantes = 480;
        int opcion;
        int valorComercial = 0;
        Tarea[] listado_tareas = new Tarea[10];

        CrearTareas(ref listado_tareas);

        Console.WriteLine("1. Mostrar tareas. \n2. Asignar tarea \n3. Salir, \n Elige opción: ");
        opcion = Convert.ToInt32(Console.ReadLine());

        switch (opcion)
        {
            case 1:
                Imprimirtareas(listado_tareas);
                break;

            case 2:
                Console.WriteLine("Seleccionar número de tarea: ");
                int n = Convert.ToInt32(Console.ReadLine())-1;

                if (n < 0 || n > 10)
                {
                    Console.WriteLine("TAREA INEXISTENTE");
                }

                else if (listado_tareas[n].realizada == true)
                {
                    Console.WriteLine("TAREA YA REALIZADA");
                }

                else if((minutos_restantes - listado_tareas[n].tiempo) <= 0)
                {
                    Console.WriteLine("TIEMPO INSUFICIENTE");
                }

                else
                {
                    listado_tareas[n].realizada = true;
                    minutos_restantes -= listado_tareas[n].tiempo;
                }

                break;
        } while (opcion != 3) ;

    }
</code>```

答:
There's no such construct:

```<code>switch
{

} while (...);
</code>```

In C#. What you've actually written is:

```<code>switch
{

}
while (...);
</code>```

Which is another way of writing

```<code>switch
{

}

while (...)
{

}
</code>```

I suspect you want to put your switch statement inside a while or a do...while loop.

Title: switch while won't loop

Body:
This is part of a program I'm writting. My main porblem is that once it goes trough one of the cases, tit won't loop so it's useless as it is. Any help? (Sorry for the variables in Spanish, also a couple of functions i created appear in the cose which are in the program and work just fine so I don't thin they have anything to do with the problem).

static void Main(string[] args)
    {
        int minutos_restantes = 480;
        int opcion;
        int valorComercial = 0;
        Tarea[] listado_tareas = new Tarea[10];

        CrearTareas(ref listado_tareas);

        Console.WriteLine("1. Mostrar tareas. \n2. Asignar tarea \n3. Salir, \n Elige opción: ");
        opcion = Convert.ToInt32(Console.ReadLine());

        switch (opcion)
        {
            case 1:
                Imprimirtareas(listado_tareas);
                break;

            case 2:
                Console.WriteLine("Seleccionar número de tarea: ");
                int n = Convert.ToInt32(Console.ReadLine())-1;

                if (n < 0 || n > 10)
                {
                    Console.WriteLine("TAREA INEXISTENTE");
                }

                else if (listado_tareas[n].realizada == true)
                {
                    Console.WriteLine("TAREA YA REALIZADA");
                }

                else if((minutos_restantes - listado_tareas[n].tiempo) <= 0)
                {
                    Console.WriteLine("TIEMPO INSUFICIENTE");
                }

                else
                {
                    listado_tareas[n].realizada = true;
                    minutos_restantes -= listado_tareas[n].tiempo;
                }

                break;
        } while (opcion != 3) ;

    }

Body:
There's no such construct:

switch
{

} while (...);

In C#. What you've actually written is:

switch
{

}
while (...);

Which is another way of writing

switch
{

}

while (...)
{

}

I suspect you want to put your switch statement inside a while or a do...while loop.


问:
usort is returning array in reverse order
This usort function is returning the array reverse from what I want. It's returning an array like ("1", "2", "3"). How can I make it return ("3", "2", "1")?</p>

```<code>usort($myArray, function($a, $b) {
    return $a["comments"] - $b["comments"];
});
</code>```

答:
usort($myArray, function($a, $b) {
    if($a['comments'] === $b['comments']) {
        return 0;
    }

    return ($a['comments'] > $b['comments']) ? -1 : 1;
});
```

Body:
This usort function is returning the array reverse from what I want. It's returning an array like ("1", "2", "3"). How can I make it return ("3", "2", "1")?

usort($myArray, function($a, $b) {
    return $a["comments"] - $b["comments"];
});


问:
How can I nest an Angular 2+ form inside an AngularJS form?
I am working on upgrading a big AngularJS application to Angular 5+. This means using new Angular 5 components within a hybrid AngularJS application. In many cases there are forms nested inside other forms. The old AngularJS code has the parent form like this:

```<code>export default function PersonDirective() {
    return {
        restrict: "E",
        template: `
              <div ng-form="personForm">
                <input type="text" name="surname" ng-model="person.surname" ng-required="true">
                <address-form address="person.homeAddress"></address-form>
              </div>`,
        replace: true,
        scope: {
            person: "="
        }
    };
}
</code>```

and the child form similar:

```<code>export default function AddressDirective() {
    return {
        restrict: "E",
        template: `
           <div ng-form="addressForm">
             <input type="text" name="firstLine" ng-model="address.firstLine" ng-required="true">
             <input type="text" name="city" ng-model="address.city" ng-required="true">
           </div>`,
        replace: true,
        scope: {
            address: "="
        }
    };
}
</code>```

This results in a FormController for the PersonDirective which has the address form as a nested FormController field called addressForm. Validation errors in the subform affect the validity of the parent form.

I have converted the address form to an Angular 5 component, replacing the AngularJS ng-form and ng-required directives with standard HTML:

```<code>@Component({
    selector: 'address-form',
    template: `
          <div>
            <form #addressForm="ngForm">
              <input type="text" name="firstLine" [(ngModel)]="address.firstLine" required>
              <input type="text" name="city" [(ngModel)]="address.city" required>
           </div>`
})
export class AddressFormComponent {
    @Input() address: any;
}

</code>```

The new component is downgraded in index.ts for use in AngularJS:

```<code>angular.module('common')
 .directive("ng2AddressForm", downgradeComponent({component: AddressFormComponent}));
</code>```

and the PersonDirective template modified to use the new component:

```<code><div ng-form="personForm">
  <input type="text" name="surname" ng-model="person.surname" ng-required="true">
  <ng2-address-form address="person.homeAddress"></ng2-address-form>
</div>
</code>```

The new component displays and validates as expected. The problem is that it no longer appears as a field in the parent form, and its validity and state are no longer propagated to the parent. It's impossible to convert all the forms at once.  Can anyone suggest a solution?

答:
The best solution I have found is to create a child component that implements ControlValueAccessor and Validator. ControlValueAccessor allows the component to be bound to an arbitrary object (the address in my example above) using [(ngModel)] in new Angular 2+ templates and ng-model in old AngularJS templates.

In new templates, the validity status of the child component will automatically affect the validity of the parent form.  In AngularJS I've had to use an event handler to report child status to the parent.  So the relationship looks like this:

In the AngularJS parent form template:

```<code><ng2-address-form
    ng-model="myCtrl.person.homeAddress"
    (status)="myCtrl.onAddressStatus($event)">
</ng2-address-form>
</code>```

In the Angular 2+ component:

```<code>export class AddressFormComponent implements ControlValueAccessor, Validator   {
    @Output("status") statusEvent = new EventEmitter<ValidationErrors | null>();
    addressForm: FormGroup;
...
        this.addressForm.statusChanges.subscribe(s => this.statusEvent.emit(this.validate(null)));
...
    validate(c: AbstractControl): ValidationErrors | null {
         // validate the form
    }
</code>```

I've found this easier using a reactive form as it gives the component logic direct access to the form controls.

Body:
I am working on upgrading a big AngularJS application to Angular 5+. This means using new Angular 5 components within a hybrid AngularJS application. In many cases there are forms nested inside other forms. The old AngularJS code has the parent form like this:

export default function PersonDirective() {
    return {
        restrict: "E",
        template: `

                <input type="text" name="surname" ng-model="person.surname" ng-required="true">
                <address-form address="person.homeAddress"></address-form>

`,
        replace: true,
        scope: {
            person: "="
        }
    };
}

and the child form similar:

export default function AddressDirective() {
    return {
        restrict: "E",
        template: `

             <input type="text" name="firstLine" ng-model="address.firstLine" ng-required="true">
             <input type="text" name="city" ng-model="address.city" ng-required="true">

`,
        replace: true,
        scope: {
            address: "="
        }
    };
}

This results in a FormController for the PersonDirective which has the address form as a nested FormController field called addressForm. Validation errors in the subform affect the validity of the parent form.

I have converted the address form to an Angular 5 component, replacing the AngularJS ng-form and ng-required directives with standard HTML:

@Component({
    selector: 'address-form',
    template: `

            <form #addressForm="ngForm">
              <input type="text" name="firstLine" [(ngModel)]="address.firstLine" required>
              <input type="text" name="city" [(ngModel)]="address.city" required>

`
})
export class AddressFormComponent {
    @Input() address: any;
}

The new component is downgraded in index.ts for use in AngularJS:

angular.module('common')
 .directive("ng2AddressForm", downgradeComponent({component: AddressFormComponent}));

and the PersonDirective template modified to use the new component:

  <input type="text" name="surname" ng-model="person.surname" ng-required="true">
  <ng2-address-form address="person.homeAddress"></ng2-address-form>

The new component displays and validates as expected. The problem is that it no longer appears as a field in the parent form, and its validity and state are no longer propagated to the parent. It's impossible to convert all the forms at once.  Can anyone suggest a solution?

Body:
The best solution I have found is to create a child component that implements ControlValueAccessor and Validator. ControlValueAccessor allows the component to be bound to an arbitrary object (the address in my example above) using [(ngModel)] in new Angular 2+ templates and ng-model in old AngularJS templates.

In new templates, the validity status of the child component will automatically affect the validity of the parent form.  In AngularJS I've had to use an event handler to report child status to the parent.  So the relationship looks like this:

In the AngularJS parent form template:

<ng2-address-form
    ng-model="myCtrl.person.homeAddress"
    (status)="myCtrl.onAddressStatus($event)">
</ng2-address-form>

In the Angular 2+ component:

export class AddressFormComponent implements ControlValueAccessor, Validator   {
    @Output("status") statusEvent = new EventEmitter<ValidationErrors | null>();
    addressForm: FormGroup;
...
        this.addressForm.statusChanges.subscribe(s => this.statusEvent.emit(this.validate(null)));
...
    validate(c: AbstractControl): ValidationErrors | null {
         // validate the form
    }

I've found this easier using a reactive form as it gives the component logic direct access to the form controls.


问:
Use the wordpress premium theme but not looks like demo theme
I use this theme , when I install this theme not looks like the demo, I refer the documentation and uploaded the .dat and .xml file for dummy data.

https://themeforest.net/item/pixiebolt-esports-gaming-theme-for-clans-organizations/19336338

答: After installing and activating your theme you need to look for import data function in wordpress left side panel after clicking on import in that function then it will start copying the dumpy content of the website from the developer server to your site.</p>


问:
forground service destroy on minimize app
I am developing an audio player app that works well but I am facing one problem if I minimize the app it kill my foreground service. I don't know why it's happening can anyone suggest me any solution

MainActivity

```<code>import android.Manifest
import android.app.PendingIntent
import android.content.*
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.text.Html
import android.util.Log
import android.view.WindowManager
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.fragment.*
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.service.MusicPlayerService
import com.brahmakumaris.service.MyService
import com.brahmakumaris.util.*
import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
import kotlin.collections.ArrayList

class MainActivity : AppCompatActivity(), OnFragmentInteractionListener {

    override fun onFragmentInteraction(screen: String, model: RecentSong, songList: ArrayList<RecentSong>, position: Int) {
        MyLog.e(TAG, screen)
        when (screen) {
            getString(R.string.speakers) -> {
                bottom_navigation.selectedItemId = R.id.nav_speaker
                supportFragmentManager.switch(
                    newFrag = SpeakerPageFragment.newInstance(),
                    tag = getString(R.string.speakers)
                )
            }
            getString(R.string.classes) -> {
                bottom_navigation.selectedItemId = R.id.nav_class
                supportFragmentManager.switch(
                    newFrag = ClassesPageFragment.newInstance(),
                    tag = getString(R.string.classes)
                )
            }
            getString(R.string.songs) -> {
                bottom_navigation.selectedItemId = R.id.nav_song
                supportFragmentManager.switch(
                    newFrag = SongsPageFragment.newInstance(),
                    tag = getString(R.string.songs)
                )
            }
            getString(R.string.play_song) -> {
                if(!model.name.isNullOrBlank()) {
                    songPosition = position
                    mSongList = songList
                    MyLog.e(TAG, "======= ${getString(R.string.play_song)} ${model.name}")
                    isPlaying = false       // to start new song
                    // play song
                    if (!lnPlayer.isVisible) {
                        lnPlayer.isVisible = true
                    }

                    titleTxt.setHtmlText(model.name)

                    if(mBound) {
                        startService()
                        mMusicPlayerService.playSong(mSongList,songPosition)
                        media_button.setImageResource(R.drawable.ic_pause_black_24dp)
                    }
                    setPlayPause(!mMusicPlayerService.isPlaying())
                    initSeekBar()
                }
            }
            else -> {
            }
        }
    }
    private val TAG = javaClass.simpleName
    private var isPlaying = false
    private var mediaSource: ProgressiveMediaSource? = null
    // notification
    private lateinit var mediaSessionConnector: MediaSessionConnector
    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var playerNotificationManager: PlayerNotificationManager

    private var handler: Handler? = null
    private val dashUrl = "http://www.panacherock.com/downloads/mp3/01_All_Tangled_Up.mp3"
    var mSongList: ArrayList<RecentSong> = ArrayList()
    var songPosition = 0

    val MESSAGE_KEY = "message_key"
    private lateinit var mMusicPlayerService:MusicPlayerService
    private lateinit var mPlayer: SimpleExoPlayer
    private var mBound = false

    private val mServiceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
            val binder = iBinder as MusicPlayerService.MyServiceBinder
            mMusicPlayerService = binder.getService()
            mPlayer = mMusicPlayerService.getPlayerInstance()!!
            mPlayer.addListener(playerListener)

            mBound = true
            MyLog.e(TAG,"onServiceConnected: ")
        }

        override fun onServiceDisconnected(componentName: ComponentName) {
            mBound = false
            MyLog.e(TAG,"onServiceDisconnected: ")  // calles only in rare case if service destroy unexpectedly
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        if (savedInstanceState == null) {

            supportFragmentManager.switch(
                newFrag = DashboardPageFragment.newInstance(),
                tag = getString(R.string.home)
            )
        }
        getIntentData()
        bottom_navigation.setOnNavigationItemSelectedListener { item ->
            hideKeybord()
            when(item.itemId) {
                R.id.nav_home -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = DashboardPageFragment.newInstance(),
                        tag = getString(R.string.home)
                    )
                    true
                }
                R.id.nav_song -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SongsPageFragment.newInstance(),
                        tag = getString(R.string.songs)
                    )
                    true
                }
                R.id.nav_speaker -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SpeakerPageFragment.newInstance(),
                        tag = getString(R.string.speakers)
                    )
                    true
                }
                R.id.nav_class -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = ClassesPageFragment.newInstance(),
                        tag = getString(R.string.classes)
                    )
                    true
                }
                R.id.nav_search -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SearchPageFragment.newInstance(),
                        tag = getString(R.string.search)
                    )
                    true
                }
                else -> false
            }

        }

        bottom_navigation.setOnNavigationItemReselectedListener {  }    //disable reselection tab

        media_button.setOnClickListener {
           // startService()
            setPlayPause(!isPlaying)
        }

        imgClose.setOnClickListener {
            isPlaying = true       // to stop song
            playerNotificationManager.setPlayer(null)
            setPlayPause(!isPlaying)
            if (lnPlayer.isVisible) {
                lnPlayer.isVisible = false
            }
        }
    }

    private fun getIntentData() {
        if (intent!=null && intent.hasExtra("internet") && !intent.getBooleanExtra("internet", false)) {
            this.changeFragment(
                DownloadPageFragment.newInstance(), Constants.DOWNLOAD_TAG
            )
        }
    }

    private fun checkFragment() {
        val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
        if (fragment != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment).commit()
        }
        val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
        if (fragment2 != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
        }
    }

    private val playerListener by lazy {
        object : Player.EventListener {
            override fun onPlayerError(error: ExoPlaybackException) {
                super.onPlayerError(error)
                //onError(error)
            }

            override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
                super.onPlayerStateChanged(playWhenReady, playbackState)
                when (playbackState) {
                    Player.STATE_BUFFERING -> Log.e(TAG,"STATE_BUFFERING")
                    Player.STATE_ENDED -> Log.e(TAG,"STATE_ENDED")
                    Player.STATE_IDLE -> Log.e(TAG,"STATE_IDLE")
                    Player.STATE_READY -> {
//                        setPlayPause(playWhenReady)
                        isPlaying = playWhenReady
                        mPlayer.setPlayWhenReady(playWhenReady)
                        if (!isPlaying) {
                            media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
                        } else {
                            setProgress()
                            media_button.setImageResource(R.drawable.ic_pause_black_24dp)
                        }
                        if (playWhenReady) {
                            Log.e(TAG, "PlaybackStatus.PLAYING")
                        } else {
                            Log.e(TAG, "PlaybackStatus.PAUSED")
                        }
                        titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
                        MyLog.e(TAG, "====== " + mSongList[mPlayer.currentWindowIndex].name)
                        MyLog.e(TAG, "======111 " + mSongList[mPlayer.currentWindowIndex].descripation)
                    }
                    else -> Log.e(TAG, "PlaybackStatus.IDLE")
                }

            }
        }
    }

    private fun startService() {
        val myService = Intent(this, MusicPlayerService ::class.java)
        Util.startForegroundService(this,myService)
    }

    private fun stopService() {
        val myService = Intent(this, MusicPlayerService ::class.java)
        stopService(myService)
    }

    private fun setPlayPause(play: Boolean) {
        if(mBound) {
            if(mMusicPlayerService.isPlaying()) {
                mMusicPlayerService.pause()
                media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
            } else {
                startService()
                playerNotificationManager = mMusicPlayerService.getNotificationInstance()!!
                /* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                     startForegroundService(intent)
                 } else {
                     startService(intent)
                 }*/
                mMusicPlayerService.play()
                setProgress()
                media_button.setImageResource(R.drawable.ic_pause_black_24dp)
            }
        }

        /*isPlaying = play
        exoPlayer.setPlayWhenReady(play)
        if (!isPlaying) {
            media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
        } else {
            setProgress()
            media_button.setImageResource(R.drawable.ic_pause_black_24dp)
        }*/
    }

    private fun stringForTime(timeMs: Int): String {
        val mFormatBuilder: StringBuilder
        val mFormatter: Formatter
        mFormatBuilder = StringBuilder()
        mFormatter = Formatter(mFormatBuilder, Locale.getDefault())
        val totalSeconds = timeMs / 1000

        val seconds = totalSeconds % 60
        val minutes = totalSeconds / 60 % 60
        val hours = totalSeconds / 3600

        mFormatBuilder.setLength(0)
        return if (hours > 0) {
            mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
        } else {
            mFormatter.format("%02d:%02d", minutes, seconds).toString()
        }
    }

    private fun setProgress() {
        seekPlayerProgress.progress = 0
        seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
        position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
        duration.setText(stringForTime(mPlayer.getDuration().toInt()))

        if (handler == null) handler = Handler()
        //Make sure you update Seekbar on UI thread
        handler!!.post(object : Runnable {
            override fun run() {
                if (mPlayer != null && ::mPlayer.isInitialized && isPlaying) {
                    seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
                    val mCurrentPosition = mPlayer.getCurrentPosition().toInt() / 1000
                    seekPlayerProgress.progress = mCurrentPosition
                    position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
                    duration.setText(stringForTime(mPlayer.getDuration().toInt()))

                    handler!!.postDelayed(this, 1000)
                }
            }
        })
    }

    private fun initSeekBar() {
        seekPlayerProgress.requestFocus()

        seekPlayerProgress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                if (!fromUser) {
                    // We're not interested in programmatically generated changes to
                    // the progress bar's position.
                    return
                }

                mPlayer.seekTo((progress * 1000).toLong())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar) {

            }

            override fun onStopTrackingTouch(seekBar: SeekBar) {

            }
        })

        seekPlayerProgress.setMax(0)
        seekPlayerProgress.setMax(mPlayer.getDuration().toInt() / 1000)

    }

    private var doubleBackToExitPressedOnce = false

    override fun onBackPressed() {
        val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
        if (fragment != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment).commit()
            return
        }
        val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
        if (fragment2 != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
            return
        }
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed()
            return
        }

        this.doubleBackToExitPressedOnce = true
        this.showSnackBarToast("Please click BACK again to exit")

        Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
    }

    override fun onDestroy() {
        if(::playerNotificationManager.isInitialized) {
            playerNotificationManager.setPlayer(null)
        }
        killPlayer()
//        stopService()
        MyLog.e(TAG," #### onDestroy #### ")
        super.onDestroy()
    }

    override fun onStop() {
        super.onStop()
        if(mBound) {
            unbindService(mServiceConnection)
            mBound = false
        }
        LocalBroadcastManager.getInstance(this)
            .unregisterReceiver(broadCastReceiver)
        MyLog.e(TAG," #### onStop #### ")
    }

     private fun killPlayer() {
        if (mPlayer != null) {
            mPlayer.release()
            mediaSource = null
        }
         MyLog.e(TAG,"#### killPlayer ####")
    }

    private fun getHtmlText(str:String):String {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return (Html.fromHtml(str, Html.FROM_HTML_MODE_COMPACT)).toString()
        } else {
            return (Html.fromHtml(str)).toString()
        }
    }

    private fun setMediaSession() {
        mediaSession = MediaSessionCompat(this@MainActivity,"MEDIA_SESSION_TAG")
        mediaSession.isActive = true
        playerNotificationManager.setMediaSessionToken(mediaSession.sessionToken)   //enhance media stye notification and provide artwork in lock screen
        mediaSessionConnector = MediaSessionConnector(mediaSession)
        //timeline is the internal representation of the pllaylist after the player has been prepared
        mediaSessionConnector.setQueueNavigator(object : TimelineQueueNavigator(mediaSession){
            override fun getMediaDescription(player: Player?, windowIndex: Int): MediaDescriptionCompat {
                return getMediaDescriptionData(this@MainActivity, mSongList[windowIndex])
            }

        })
        mediaSessionConnector.setPlayer(exoPlayer/*, null*/)   //sync player wth media session

    }

    fun getMediaDescriptionData(context: Context, sample: RecentSong): MediaDescriptionCompat {
        val extras = Bundle()
        val options = BitmapFactory.Options()
        options.inSampleSize = 8

//        val bitmap = BitmapFactory.decodeFile(getBitmap(context, sample.bitmapResource), options)
        val bitmap = context.getBitmap(R.drawable.bg)

        extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
        extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap)
        return MediaDescriptionCompat.Builder()
            .setMediaId(sample.song)
            .setIconBitmap(bitmap)
            .setTitle(sample.name)
            .setDescription(sample.descripation)
            .setExtras(extras)
            .build()
    }

    override fun onStart() {
        super.onStart()
        bindService(Intent(this,MusicPlayerService::class.java),mServiceConnection,Context.BIND_AUTO_CREATE)
        LocalBroadcastManager.getInstance(this)
            .registerReceiver(broadCastReceiver, IntentFilter(MusicPlayerService().MUSIC_COMPLETED))
    }

    val broadCastReceiver = object : BroadcastReceiver() {
        override fun onReceive(contxt: Context?, intent: Intent?) {
            MyLog.e(TAG,"onReceive: ${intent?.getBooleanExtra(MESSAGE_KEY,false)}")
            if(intent!!.getBooleanExtra(MESSAGE_KEY,false)) {
                setPlayPause(intent.getBooleanExtra(MESSAGE_KEY,false))
                if (intent.getBooleanExtra(MESSAGE_KEY,false)) {
                    Log.e(TAG, "PlaybackStatus.PLAYING")
                } else {
                    Log.e(TAG, "PlaybackStatus.PAUSED")
                }
                titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
                MyLog.e(TAG,"====== "+mSongList[mPlayer.currentWindowIndex].name)
                MyLog.e(TAG,"======111 "+mSongList[mPlayer.currentWindowIndex].descripation)
            }

        }
    }
}
</code>```

MusicPlayerService

```<code>import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Binder
import android.os.IBinder
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.MainActivity
import com.brahmakumaris.R
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.util.MyLog
import com.brahmakumaris.util.getBitmap
import com.brahmakumaris.util.getPlaintextfromHtmlHtmlText
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util

class MusicPlayerService : Service() {
    private val TAG = javaClass.simpleName
    private val mContext: Context = this
    private val mBinder = MyServiceBinder()
    val MUSIC_COMPLETED = "music completed"
    val mPlayer: SimpleExoPlayer by lazy { SimpleExoPlayer.Builder(this).build() }
    private lateinit var playerNotificationManager: PlayerNotificationManager
    var mSongList: ArrayList<RecentSong> = ArrayList()

    override fun onCreate() {
        super.onCreate()
        MyLog.d(TAG,"onCreate: ")

    }

    fun playSong(mSongList: ArrayList<RecentSong> = ArrayList(), position: Int = 0)/* mContext: Context = this*/ {
        this.mSongList = mSongList
        val dataSourceFactory = DefaultDataSourceFactory(mContext, Util.getUserAgent(mContext,getString(R.string.app_name)))

        val concateMediaSource = ConcatenatingMediaSource()
        for (i in mSongList) {
            val mediaSource = ProgressiveMediaSource
                .Factory(
                    DefaultDataSourceFactory(mContext, dataSourceFactory),
                    DefaultExtractorsFactory()
                )
                .createMediaSource(/*i.uri*/Uri.parse(i.musicFile))
            concateMediaSource.addMediaSource(mediaSource)
        }

        mPlayer.prepare(concateMediaSource)
        mPlayer.seekToDefaultPosition(position)
        mPlayer.playWhenReady =true

        setNotification()
    }

    private fun setNotification() {
        playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
            this,"channel_id",R.string.channelName,R.string.channelDescription,11,
            object : PlayerNotificationManager.MediaDescriptionAdapter{
                override fun createCurrentContentIntent(player: Player): PendingIntent? {
                    val intent = Intent(mContext, MainActivity::class.java)
                    return PendingIntent.getActivity(mContext,0,intent, PendingIntent.FLAG_UPDATE_CURRENT)
                }

                override fun getCurrentContentText(player: Player): String? {
//                    return mSongList[player.currentWindowIndex].descripation // descrption
                    return mSongList[player.currentWindowIndex].descripation.getPlaintextfromHtmlHtmlText() // descrption
                }

                override fun getCurrentContentTitle(player: Player): String {
//                    return mSongList[player.currentWindowIndex].name // title
                    return mSongList[player.currentWindowIndex].name.getPlaintextfromHtmlHtmlText()
                }

                override fun getCurrentLargeIcon(
                    player: Player,
                    callback: PlayerNotificationManager.BitmapCallback
                ): Bitmap? {
                    return mContext.getBitmap(R.drawable.bg)
                }

            } ,object : PlayerNotificationManager.NotificationListener {
             override fun onNotificationStarted(notificationId: Int, notification: Notification) {
                 startForeground(notificationId,notification)
             }
             override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
                 startForeground(notificationId,notification)
             }

             override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
                 stopSelf()
             }

             override fun onNotificationCancelled(notificationId: Int) {
                 stopSelf()
             }
         }

        )

        //show hide button
        playerNotificationManager.setUseStopAction(false)  //stop song
        playerNotificationManager.setRewindIncrementMs(0)   //hide rewind button
        playerNotificationManager.setFastForwardIncrementMs(0)  //hide fast forward button
        playerNotificationManager.setPlayer(mPlayer)
    }

    inner class MyServiceBinder : Binder() {
        fun getService(): MusicPlayerService = this@MusicPlayerService
    }

    fun getPlayerInstance(): SimpleExoPlayer? {
        return mPlayer
    }

    fun getNotificationInstance(): PlayerNotificationManager? {
        return playerNotificationManager
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        MyLog.d(TAG,"onStartCommand: ")
        return START_NOT_STICKY
    }
    override fun onBind(intent: Intent?): IBinder? {
        MyLog.d(TAG,"onBind: ")
        return mBinder

    }

    override fun onUnbind(intent: Intent?): Boolean {
        MyLog.d(TAG,"onUnbind: ")
        return true
    }

    override fun onRebind(intent: Intent?) {
        MyLog.d(TAG,"onRebind: ")
        super.onRebind(intent)
    }
    override fun onDestroy() {
        MyLog.e(TAG,"onDestroy: ")
        super.onDestroy()
        mPlayer.release()
        if(::playerNotificationManager.isInitialized) {
            playerNotificationManager.setPlayer(null)
        }
    }

    // public client method
    fun isPlaying():Boolean {
        return mPlayer.isPlaying
    }

    fun play() {
        mPlayer.setPlayWhenReady(true)
    }

    fun pause() {
        mPlayer.setPlayWhenReady(false)
    }
}
</code>```

if I minimize the app then it's printing unbind and then it directly going to onDestroy why it's happening can anyone help me,

Any Help Would Be Highly Appreciated.

答:
You should be using startForeground() with a notification, to Android service that never stops running.

```<code>startForeground(1, notification)
</code>```

Please have a look at this.
https://robertohuertas.com/2019/06/29/android_foreground_services/

I hope this will help you.

Body:
I am developing an audio player app that works well but I am facing one problem if I minimize the app it kill my foreground service. I don't know why it's happening can anyone suggest me any solution

MainActivity

import android.Manifest
import android.app.PendingIntent
import android.content.*
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaSessionCompat
import android.text.Html
import android.util.Log
import android.view.WindowManager
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.fragment.*
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.service.MusicPlayerService
import com.brahmakumaris.service.MyService
import com.brahmakumaris.util.*
import com.google.android.exoplayer2.DefaultLoadControl
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueNavigator
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
import kotlin.collections.ArrayList

class MainActivity : AppCompatActivity(), OnFragmentInteractionListener {

    override fun onFragmentInteraction(screen: String, model: RecentSong, songList: ArrayList<RecentSong>, position: Int) {
        MyLog.e(TAG, screen)
        when (screen) {
            getString(R.string.speakers) -> {
                bottom_navigation.selectedItemId = R.id.nav_speaker
                supportFragmentManager.switch(
                    newFrag = SpeakerPageFragment.newInstance(),
                    tag = getString(R.string.speakers)
                )
            }
            getString(R.string.classes) -> {
                bottom_navigation.selectedItemId = R.id.nav_class
                supportFragmentManager.switch(
                    newFrag = ClassesPageFragment.newInstance(),
                    tag = getString(R.string.classes)
                )
            }
            getString(R.string.songs) -> {
                bottom_navigation.selectedItemId = R.id.nav_song
                supportFragmentManager.switch(
                    newFrag = SongsPageFragment.newInstance(),
                    tag = getString(R.string.songs)
                )
            }
            getString(R.string.play_song) -> {
                if(!model.name.isNullOrBlank()) {
                    songPosition = position
                    mSongList = songList
                    MyLog.e(TAG, "======= ${getString(R.string.play_song)} ${model.name}")
                    isPlaying = false       // to start new song
                    // play song
                    if (!lnPlayer.isVisible) {
                        lnPlayer.isVisible = true
                    }

                    titleTxt.setHtmlText(model.name)

                    if(mBound) {
                        startService()
                        mMusicPlayerService.playSong(mSongList,songPosition)
                        media_button.setImageResource(R.drawable.ic_pause_black_24dp)
                    }
                    setPlayPause(!mMusicPlayerService.isPlaying())
                    initSeekBar()
                }
            }
            else -> {
            }
        }
    }
    private val TAG = javaClass.simpleName
    private var isPlaying = false
    private var mediaSource: ProgressiveMediaSource? = null
    // notification
    private lateinit var mediaSessionConnector: MediaSessionConnector
    private lateinit var mediaSession: MediaSessionCompat
    private lateinit var playerNotificationManager: PlayerNotificationManager

    private var handler: Handler? = null
    private val dashUrl = "http://www.panacherock.com/downloads/mp3/01_All_Tangled_Up.mp3"
    var mSongList: ArrayList<RecentSong> = ArrayList()
    var songPosition = 0

    val MESSAGE_KEY = "message_key"
    private lateinit var mMusicPlayerService:MusicPlayerService
    private lateinit var mPlayer: SimpleExoPlayer
    private var mBound = false

    private val mServiceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
            val binder = iBinder as MusicPlayerService.MyServiceBinder
            mMusicPlayerService = binder.getService()
            mPlayer = mMusicPlayerService.getPlayerInstance()!!
            mPlayer.addListener(playerListener)

            mBound = true
            MyLog.e(TAG,"onServiceConnected: ")
        }

        override fun onServiceDisconnected(componentName: ComponentName) {
            mBound = false
            MyLog.e(TAG,"onServiceDisconnected: ")  // calles only in rare case if service destroy unexpectedly
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
        if (savedInstanceState == null) {

            supportFragmentManager.switch(
                newFrag = DashboardPageFragment.newInstance(),
                tag = getString(R.string.home)
            )
        }
        getIntentData()
        bottom_navigation.setOnNavigationItemSelectedListener { item ->
            hideKeybord()
            when(item.itemId) {
                R.id.nav_home -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = DashboardPageFragment.newInstance(),
                        tag = getString(R.string.home)
                    )
                    true
                }
                R.id.nav_song -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SongsPageFragment.newInstance(),
                        tag = getString(R.string.songs)
                    )
                    true
                }
                R.id.nav_speaker -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SpeakerPageFragment.newInstance(),
                        tag = getString(R.string.speakers)
                    )
                    true
                }
                R.id.nav_class -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = ClassesPageFragment.newInstance(),
                        tag = getString(R.string.classes)
                    )
                    true
                }
                R.id.nav_search -> {
                    checkFragment()
                    supportFragmentManager.switch(
                        newFrag = SearchPageFragment.newInstance(),
                        tag = getString(R.string.search)
                    )
                    true
                }
                else -> false
            }

        }

        bottom_navigation.setOnNavigationItemReselectedListener {  }    //disable reselection tab

        media_button.setOnClickListener {
           // startService()
            setPlayPause(!isPlaying)
        }

        imgClose.setOnClickListener {
            isPlaying = true       // to stop song
            playerNotificationManager.setPlayer(null)
            setPlayPause(!isPlaying)
            if (lnPlayer.isVisible) {
                lnPlayer.isVisible = false
            }
        }
    }

    private fun getIntentData() {
        if (intent!=null && intent.hasExtra("internet") && !intent.getBooleanExtra("internet", false)) {
            this.changeFragment(
                DownloadPageFragment.newInstance(), Constants.DOWNLOAD_TAG
            )
        }
    }

    private fun checkFragment() {
        val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
        if (fragment != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment).commit()
        }
        val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
        if (fragment2 != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
        }
    }

    private val playerListener by lazy {
        object : Player.EventListener {
            override fun onPlayerError(error: ExoPlaybackException) {
                super.onPlayerError(error)
                //onError(error)
            }

            override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
                super.onPlayerStateChanged(playWhenReady, playbackState)
                when (playbackState) {
                    Player.STATE_BUFFERING -> Log.e(TAG,"STATE_BUFFERING")
                    Player.STATE_ENDED -> Log.e(TAG,"STATE_ENDED")
                    Player.STATE_IDLE -> Log.e(TAG,"STATE_IDLE")
                    Player.STATE_READY -> {
//                        setPlayPause(playWhenReady)
                        isPlaying = playWhenReady
                        mPlayer.setPlayWhenReady(playWhenReady)
                        if (!isPlaying) {
                            media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
                        } else {
                            setProgress()
                            media_button.setImageResource(R.drawable.ic_pause_black_24dp)
                        }
                        if (playWhenReady) {
                            Log.e(TAG, "PlaybackStatus.PLAYING")
                        } else {
                            Log.e(TAG, "PlaybackStatus.PAUSED")
                        }
                        titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
                        MyLog.e(TAG, "====== " + mSongList[mPlayer.currentWindowIndex].name)
                        MyLog.e(TAG, "======111 " + mSongList[mPlayer.currentWindowIndex].descripation)
                    }
                    else -> Log.e(TAG, "PlaybackStatus.IDLE")
                }

            }
        }
    }

    private fun startService() {
        val myService = Intent(this, MusicPlayerService ::class.java)
        Util.startForegroundService(this,myService)
    }

    private fun stopService() {
        val myService = Intent(this, MusicPlayerService ::class.java)
        stopService(myService)
    }

    private fun setPlayPause(play: Boolean) {
        if(mBound) {
            if(mMusicPlayerService.isPlaying()) {
                mMusicPlayerService.pause()
                media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
            } else {
                startService()
                playerNotificationManager = mMusicPlayerService.getNotificationInstance()!!
                /* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                     startForegroundService(intent)
                 } else {
                     startService(intent)
                 }*/
                mMusicPlayerService.play()
                setProgress()
                media_button.setImageResource(R.drawable.ic_pause_black_24dp)
            }
        }

        /*isPlaying = play
        exoPlayer.setPlayWhenReady(play)
        if (!isPlaying) {
            media_button.setImageResource(R.drawable.ic_play_arrow_black_24dp)
        } else {
            setProgress()
            media_button.setImageResource(R.drawable.ic_pause_black_24dp)
        }*/
    }

    private fun stringForTime(timeMs: Int): String {
        val mFormatBuilder: StringBuilder
        val mFormatter: Formatter
        mFormatBuilder = StringBuilder()
        mFormatter = Formatter(mFormatBuilder, Locale.getDefault())
        val totalSeconds = timeMs / 1000

        val seconds = totalSeconds % 60
        val minutes = totalSeconds / 60 % 60
        val hours = totalSeconds / 3600

        mFormatBuilder.setLength(0)
        return if (hours > 0) {
            mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
        } else {
            mFormatter.format("%02d:%02d", minutes, seconds).toString()
        }
    }

    private fun setProgress() {
        seekPlayerProgress.progress = 0
        seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
        position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
        duration.setText(stringForTime(mPlayer.getDuration().toInt()))

        if (handler == null) handler = Handler()
        //Make sure you update Seekbar on UI thread
        handler!!.post(object : Runnable {
            override fun run() {
                if (mPlayer != null && ::mPlayer.isInitialized && isPlaying) {
                    seekPlayerProgress.max = mPlayer.getDuration().toInt() / 1000
                    val mCurrentPosition = mPlayer.getCurrentPosition().toInt() / 1000
                    seekPlayerProgress.progress = mCurrentPosition
                    position.setText(stringForTime(mPlayer.getCurrentPosition().toInt()))
                    duration.setText(stringForTime(mPlayer.getDuration().toInt()))

                    handler!!.postDelayed(this, 1000)
                }
            }
        })
    }

    private fun initSeekBar() {
        seekPlayerProgress.requestFocus()

        seekPlayerProgress.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
                if (!fromUser) {
                    // We're not interested in programmatically generated changes to
                    // the progress bar's position.
                    return
                }

                mPlayer.seekTo((progress * 1000).toLong())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar) {

            }

            override fun onStopTrackingTouch(seekBar: SeekBar) {

            }
        })

        seekPlayerProgress.setMax(0)
        seekPlayerProgress.setMax(mPlayer.getDuration().toInt() / 1000)

    }

    private var doubleBackToExitPressedOnce = false

    override fun onBackPressed() {
        val fragment = getSupportFragmentManager().findFragmentByTag(Constants.SUB_CATEGORY_TAG)
        if (fragment != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment).commit()
            return
        }
        val fragment2 = getSupportFragmentManager().findFragmentByTag(Constants.DOWNLOAD_TAG)
        if (fragment2 != null) {
            getSupportFragmentManager().beginTransaction().remove(fragment2).commit()
            return
        }
        if (doubleBackToExitPressedOnce) {
            super.onBackPressed()
            return
        }

        this.doubleBackToExitPressedOnce = true
        this.showSnackBarToast("Please click BACK again to exit")

        Handler().postDelayed(Runnable { doubleBackToExitPressedOnce = false }, 2000)
    }

    override fun onDestroy() {
        if(::playerNotificationManager.isInitialized) {
            playerNotificationManager.setPlayer(null)
        }
        killPlayer()
//        stopService()
        MyLog.e(TAG," #### onDestroy #### ")
        super.onDestroy()
    }

    override fun onStop() {
        super.onStop()
        if(mBound) {
            unbindService(mServiceConnection)
            mBound = false
        }
        LocalBroadcastManager.getInstance(this)
            .unregisterReceiver(broadCastReceiver)
        MyLog.e(TAG," #### onStop #### ")
    }

     private fun killPlayer() {
        if (mPlayer != null) {
            mPlayer.release()
            mediaSource = null
        }
         MyLog.e(TAG,"#### killPlayer ####")
    }

    private fun getHtmlText(str:String):String {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return (Html.fromHtml(str, Html.FROM_HTML_MODE_COMPACT)).toString()
        } else {
            return (Html.fromHtml(str)).toString()
        }
    }

    private fun setMediaSession() {
        mediaSession = MediaSessionCompat(this@MainActivity,"MEDIA_SESSION_TAG")
        mediaSession.isActive = true
        playerNotificationManager.setMediaSessionToken(mediaSession.sessionToken)   //enhance media stye notification and provide artwork in lock screen
        mediaSessionConnector = MediaSessionConnector(mediaSession)
        //timeline is the internal representation of the pllaylist after the player has been prepared
        mediaSessionConnector.setQueueNavigator(object : TimelineQueueNavigator(mediaSession){
            override fun getMediaDescription(player: Player?, windowIndex: Int): MediaDescriptionCompat {
                return getMediaDescriptionData(this@MainActivity, mSongList[windowIndex])
            }

        })
        mediaSessionConnector.setPlayer(exoPlayer/*, null*/)   //sync player wth media session

    }

    fun getMediaDescriptionData(context: Context, sample: RecentSong): MediaDescriptionCompat {
        val extras = Bundle()
        val options = BitmapFactory.Options()
        options.inSampleSize = 8

//        val bitmap = BitmapFactory.decodeFile(getBitmap(context, sample.bitmapResource), options)
        val bitmap = context.getBitmap(R.drawable.bg)

        extras.putParcelable(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
        extras.putParcelable(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap)
        return MediaDescriptionCompat.Builder()
            .setMediaId(sample.song)
            .setIconBitmap(bitmap)
            .setTitle(sample.name)
            .setDescription(sample.descripation)
            .setExtras(extras)
            .build()
    }

    override fun onStart() {
        super.onStart()
        bindService(Intent(this,MusicPlayerService::class.java),mServiceConnection,Context.BIND_AUTO_CREATE)
        LocalBroadcastManager.getInstance(this)
            .registerReceiver(broadCastReceiver, IntentFilter(MusicPlayerService().MUSIC_COMPLETED))
    }

    val broadCastReceiver = object : BroadcastReceiver() {
        override fun onReceive(contxt: Context?, intent: Intent?) {
            MyLog.e(TAG,"onReceive: ${intent?.getBooleanExtra(MESSAGE_KEY,false)}")
            if(intent!!.getBooleanExtra(MESSAGE_KEY,false)) {
                setPlayPause(intent.getBooleanExtra(MESSAGE_KEY,false))
                if (intent.getBooleanExtra(MESSAGE_KEY,false)) {
                    Log.e(TAG, "PlaybackStatus.PLAYING")
                } else {
                    Log.e(TAG, "PlaybackStatus.PAUSED")
                }
                titleTxt.setHtmlText(mSongList[mPlayer.currentWindowIndex].name)
                MyLog.e(TAG,"====== "+mSongList[mPlayer.currentWindowIndex].name)
                MyLog.e(TAG,"======111 "+mSongList[mPlayer.currentWindowIndex].descripation)
            }

        }
    }
}

MusicPlayerService

import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Binder
import android.os.IBinder
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.brahmakumaris.MainActivity
import com.brahmakumaris.R
import com.brahmakumaris.model.getDashboard.RecentSong
import com.brahmakumaris.util.MyLog
import com.brahmakumaris.util.getBitmap
import com.brahmakumaris.util.getPlaintextfromHtmlHtmlText
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util

class MusicPlayerService : Service() {
    private val TAG = javaClass.simpleName
    private val mContext: Context = this
    private val mBinder = MyServiceBinder()
    val MUSIC_COMPLETED = "music completed"
    val mPlayer: SimpleExoPlayer by lazy { SimpleExoPlayer.Builder(this).build() }
    private lateinit var playerNotificationManager: PlayerNotificationManager
    var mSongList: ArrayList<RecentSong> = ArrayList()

    override fun onCreate() {
        super.onCreate()
        MyLog.d(TAG,"onCreate: ")

    }

    fun playSong(mSongList: ArrayList<RecentSong> = ArrayList(), position: Int = 0)/* mContext: Context = this*/ {
        this.mSongList = mSongList
        val dataSourceFactory = DefaultDataSourceFactory(mContext, Util.getUserAgent(mContext,getString(R.string.app_name)))

        val concateMediaSource = ConcatenatingMediaSource()
        for (i in mSongList) {
            val mediaSource = ProgressiveMediaSource
                .Factory(
                    DefaultDataSourceFactory(mContext, dataSourceFactory),
                    DefaultExtractorsFactory()
                )
                .createMediaSource(/*i.uri*/Uri.parse(i.musicFile))
            concateMediaSource.addMediaSource(mediaSource)
        }

        mPlayer.prepare(concateMediaSource)
        mPlayer.seekToDefaultPosition(position)
        mPlayer.playWhenReady =true

        setNotification()
    }

    private fun setNotification() {
        playerNotificationManager = PlayerNotificationManager.createWithNotificationChannel(
            this,"channel_id",R.string.channelName,R.string.channelDescription,11,
            object : PlayerNotificationManager.MediaDescriptionAdapter{
                override fun createCurrentContentIntent(player: Player): PendingIntent? {
                    val intent = Intent(mContext, MainActivity::class.java)
                    return PendingIntent.getActivity(mContext,0,intent, PendingIntent.FLAG_UPDATE_CURRENT)
                }

                override fun getCurrentContentText(player: Player): String? {
//                    return mSongList[player.currentWindowIndex].descripation // descrption
                    return mSongList[player.currentWindowIndex].descripation.getPlaintextfromHtmlHtmlText() // descrption
                }

                override fun getCurrentContentTitle(player: Player): String {
//                    return mSongList[player.currentWindowIndex].name // title
                    return mSongList[player.currentWindowIndex].name.getPlaintextfromHtmlHtmlText()
                }

                override fun getCurrentLargeIcon(
                    player: Player,
                    callback: PlayerNotificationManager.BitmapCallback
                ): Bitmap? {
                    return mContext.getBitmap(R.drawable.bg)
                }

            } ,object : PlayerNotificationManager.NotificationListener {
             override fun onNotificationStarted(notificationId: Int, notification: Notification) {
                 startForeground(notificationId,notification)
             }
             override fun onNotificationPosted(notificationId: Int, notification: Notification, ongoing: Boolean) {
                 startForeground(notificationId,notification)
             }

             override fun onNotificationCancelled(notificationId: Int, dismissedByUser: Boolean) {
                 stopSelf()
             }

             override fun onNotificationCancelled(notificationId: Int) {
                 stopSelf()
             }
         }

        )

        //show hide button
        playerNotificationManager.setUseStopAction(false)  //stop song
        playerNotificationManager.setRewindIncrementMs(0)   //hide rewind button
        playerNotificationManager.setFastForwardIncrementMs(0)  //hide fast forward button
        playerNotificationManager.setPlayer(mPlayer)
    }

    inner class MyServiceBinder : Binder() {
        fun getService(): MusicPlayerService = this@MusicPlayerService
    }

    fun getPlayerInstance(): SimpleExoPlayer? {
        return mPlayer
    }

    fun getNotificationInstance(): PlayerNotificationManager? {
        return playerNotificationManager
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        MyLog.d(TAG,"onStartCommand: ")
        return START_NOT_STICKY
    }
    override fun onBind(intent: Intent?): IBinder? {
        MyLog.d(TAG,"onBind: ")
        return mBinder

    }

    override fun onUnbind(intent: Intent?): Boolean {
        MyLog.d(TAG,"onUnbind: ")
        return true
    }

    override fun onRebind(intent: Intent?) {
        MyLog.d(TAG,"onRebind: ")
        super.onRebind(intent)
    }
    override fun onDestroy() {
        MyLog.e(TAG,"onDestroy: ")
        super.onDestroy()
        mPlayer.release()
        if(::playerNotificationManager.isInitialized) {
            playerNotificationManager.setPlayer(null)
        }
    }

    // public client method
    fun isPlaying():Boolean {
        return mPlayer.isPlaying
    }

    fun play() {
        mPlayer.setPlayWhenReady(true)
    }

    fun pause() {
        mPlayer.setPlayWhenReady(false)
    }
}

if I minimize the app then it's printing unbind and then it directly going to onDestroy why it's happening can anyone help me,

Any Help Would Be Highly Appreciated.

Body:
You should be using startForeground() with a notification, to Android service that never stops running.

startForeground(1, notification)

Please have a look at this.
https://robertohuertas.com/2019/06/29/android_foreground_services/

I hope this will help you.